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() { 46753f127fSDimitry Andric SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); 47fe6060f1SDimitry Andric 48753f127fSDimitry Andric bool MadeChange = false; 49753f127fSDimitry Andric while (Position != CurDAG->allnodes_begin()) { 50753f127fSDimitry Andric SDNode *N = &*--Position; 51753f127fSDimitry Andric if (N->use_empty()) 52753f127fSDimitry Andric continue; 53753f127fSDimitry Andric 54753f127fSDimitry Andric SDValue Result; 55753f127fSDimitry Andric switch (N->getOpcode()) { 56753f127fSDimitry 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()); 64753f127fSDimitry Andric Result = CurDAG->getNode(Opc, DL, VT, CurDAG->getUNDEF(VT), 6581ad6265SDimitry Andric N->getOperand(0), VL); 66753f127fSDimitry Andric break; 6781ad6265SDimitry Andric } 68753f127fSDimitry 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(); 82753f127fSDimitry Andric RISCVMachineFunctionInfo *FuncInfo = 83753f127fSDimitry 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 114753f127fSDimitry Andric Result = CurDAG->getMemIntrinsicNode(ISD::INTRINSIC_W_CHAIN, DL, VTs, Ops, 115753f127fSDimitry Andric MVT::i64, MPI, Align(8), 116fe6060f1SDimitry Andric MachineMemOperand::MOLoad); 117753f127fSDimitry Andric break; 118fe6060f1SDimitry Andric } 119fe6060f1SDimitry Andric } 120fe6060f1SDimitry Andric 121753f127fSDimitry Andric if (Result) { 122753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "RISCV DAG preprocessing replacing:\nOld: "); 123753f127fSDimitry Andric LLVM_DEBUG(N->dump(CurDAG)); 124753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "\nNew: "); 125753f127fSDimitry Andric LLVM_DEBUG(Result->dump(CurDAG)); 126753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "\n"); 127753f127fSDimitry Andric 128753f127fSDimitry Andric CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0), Result); 129753f127fSDimitry Andric MadeChange = true; 130753f127fSDimitry Andric } 131753f127fSDimitry Andric } 132753f127fSDimitry Andric 133753f127fSDimitry Andric if (MadeChange) 134753f127fSDimitry Andric CurDAG->RemoveDeadNodes(); 135753f127fSDimitry Andric } 136753f127fSDimitry 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 256753f127fSDimitry 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; 693*fcaf7f86SDimitry Andric // If C2 is (1 << ShAmt) use bexti if possible. 694*fcaf7f86SDimitry Andric if (Subtarget->hasStdExtZbs() && ShAmt + 1 == TrailingOnes) { 695*fcaf7f86SDimitry Andric SDNode *BEXTI = 696*fcaf7f86SDimitry Andric CurDAG->getMachineNode(RISCV::BEXTI, DL, VT, N0->getOperand(0), 697*fcaf7f86SDimitry Andric CurDAG->getTargetConstant(ShAmt, DL, VT)); 698*fcaf7f86SDimitry Andric ReplaceNode(Node, BEXTI); 699*fcaf7f86SDimitry Andric return; 700*fcaf7f86SDimitry Andric } 70104eeddc0SDimitry Andric unsigned LShAmt = Subtarget->getXLen() - TrailingOnes; 702fe6060f1SDimitry Andric SDNode *SLLI = 703fe6060f1SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0->getOperand(0), 704fe6060f1SDimitry Andric CurDAG->getTargetConstant(LShAmt, DL, VT)); 705fe6060f1SDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 706fe6060f1SDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 707fe6060f1SDimitry Andric CurDAG->getTargetConstant(LShAmt + ShAmt, DL, VT)); 708fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 709fe6060f1SDimitry Andric return; 710fe6060f1SDimitry Andric } 71104eeddc0SDimitry Andric case ISD::SRA: { 71204eeddc0SDimitry Andric // Optimize (sra (sext_inreg X, i16), C) -> 71304eeddc0SDimitry Andric // (srai (slli X, (XLen-16), (XLen-16) + C) 71404eeddc0SDimitry Andric // And (sra (sext_inreg X, i8), C) -> 71504eeddc0SDimitry Andric // (srai (slli X, (XLen-8), (XLen-8) + C) 71604eeddc0SDimitry Andric // This can occur when Zbb is enabled, which makes sext_inreg i16/i8 legal. 71704eeddc0SDimitry Andric // This transform matches the code we get without Zbb. The shifts are more 71804eeddc0SDimitry Andric // compressible, and this can help expose CSE opportunities in the sdiv by 71904eeddc0SDimitry Andric // constant optimization. 72004eeddc0SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 72104eeddc0SDimitry Andric if (!N1C) 722fe6060f1SDimitry Andric break; 72304eeddc0SDimitry Andric SDValue N0 = Node->getOperand(0); 72404eeddc0SDimitry Andric if (N0.getOpcode() != ISD::SIGN_EXTEND_INREG || !N0.hasOneUse()) 72504eeddc0SDimitry Andric break; 72604eeddc0SDimitry Andric unsigned ShAmt = N1C->getZExtValue(); 72704eeddc0SDimitry Andric unsigned ExtSize = 72804eeddc0SDimitry Andric cast<VTSDNode>(N0.getOperand(1))->getVT().getSizeInBits(); 72904eeddc0SDimitry Andric // ExtSize of 32 should use sraiw via tablegen pattern. 73004eeddc0SDimitry Andric if (ExtSize >= 32 || ShAmt >= ExtSize) 73104eeddc0SDimitry Andric break; 73204eeddc0SDimitry Andric unsigned LShAmt = Subtarget->getXLen() - ExtSize; 73304eeddc0SDimitry Andric SDNode *SLLI = 73404eeddc0SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0->getOperand(0), 73504eeddc0SDimitry Andric CurDAG->getTargetConstant(LShAmt, DL, VT)); 73604eeddc0SDimitry Andric SDNode *SRAI = CurDAG->getMachineNode( 73704eeddc0SDimitry Andric RISCV::SRAI, DL, VT, SDValue(SLLI, 0), 73804eeddc0SDimitry Andric CurDAG->getTargetConstant(LShAmt + ShAmt, DL, VT)); 73904eeddc0SDimitry Andric ReplaceNode(Node, SRAI); 74004eeddc0SDimitry Andric return; 741fe6060f1SDimitry Andric } 742fe6060f1SDimitry Andric case ISD::AND: { 743fe6060f1SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 744fe6060f1SDimitry Andric if (!N1C) 745fe6060f1SDimitry Andric break; 746fe6060f1SDimitry Andric 747fe6060f1SDimitry Andric SDValue N0 = Node->getOperand(0); 748fe6060f1SDimitry Andric 749fe6060f1SDimitry Andric bool LeftShift = N0.getOpcode() == ISD::SHL; 750fe6060f1SDimitry Andric if (!LeftShift && N0.getOpcode() != ISD::SRL) 751fe6060f1SDimitry Andric break; 752fe6060f1SDimitry Andric 753fe6060f1SDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N0.getOperand(1)); 754fe6060f1SDimitry Andric if (!C) 755fe6060f1SDimitry Andric break; 756753f127fSDimitry Andric unsigned C2 = C->getZExtValue(); 757fe6060f1SDimitry Andric unsigned XLen = Subtarget->getXLen(); 758753f127fSDimitry Andric assert((C2 > 0 && C2 < XLen) && "Unexpected shift amount!"); 759fe6060f1SDimitry Andric 760fe6060f1SDimitry Andric uint64_t C1 = N1C->getZExtValue(); 761fe6060f1SDimitry Andric 76281ad6265SDimitry Andric // Keep track of whether this is a c.andi. If we can't use c.andi, the 76381ad6265SDimitry Andric // shift pair might offer more compression opportunities. 76481ad6265SDimitry Andric // TODO: We could check for C extension here, but we don't have many lit 76581ad6265SDimitry Andric // tests with the C extension enabled so not checking gets better coverage. 76681ad6265SDimitry Andric // TODO: What if ANDI faster than shift? 76781ad6265SDimitry Andric bool IsCANDI = isInt<6>(N1C->getSExtValue()); 768fe6060f1SDimitry Andric 769fe6060f1SDimitry Andric // Clear irrelevant bits in the mask. 770fe6060f1SDimitry Andric if (LeftShift) 771fe6060f1SDimitry Andric C1 &= maskTrailingZeros<uint64_t>(C2); 772fe6060f1SDimitry Andric else 773fe6060f1SDimitry Andric C1 &= maskTrailingOnes<uint64_t>(XLen - C2); 774fe6060f1SDimitry Andric 775fe6060f1SDimitry Andric // Some transforms should only be done if the shift has a single use or 776fe6060f1SDimitry Andric // the AND would become (srli (slli X, 32), 32) 777fe6060f1SDimitry Andric bool OneUseOrZExtW = N0.hasOneUse() || C1 == UINT64_C(0xFFFFFFFF); 778fe6060f1SDimitry Andric 779fe6060f1SDimitry Andric SDValue X = N0.getOperand(0); 780fe6060f1SDimitry Andric 781fe6060f1SDimitry Andric // Turn (and (srl x, c2) c1) -> (srli (slli x, c3-c2), c3) if c1 is a mask 782fe6060f1SDimitry Andric // with c3 leading zeros. 783fe6060f1SDimitry Andric if (!LeftShift && isMask_64(C1)) { 784753f127fSDimitry Andric unsigned Leading = XLen - (64 - countLeadingZeros(C1)); 785753f127fSDimitry Andric if (C2 < Leading) { 786fe6060f1SDimitry Andric // If the number of leading zeros is C2+32 this can be SRLIW. 787753f127fSDimitry Andric if (C2 + 32 == Leading) { 78881ad6265SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 78981ad6265SDimitry Andric RISCV::SRLIW, DL, VT, X, CurDAG->getTargetConstant(C2, DL, VT)); 790fe6060f1SDimitry Andric ReplaceNode(Node, SRLIW); 791fe6060f1SDimitry Andric return; 792fe6060f1SDimitry Andric } 793fe6060f1SDimitry Andric 794fe6060f1SDimitry Andric // (and (srl (sexti32 Y), c2), c1) -> (srliw (sraiw Y, 31), c3 - 32) if 795fe6060f1SDimitry Andric // c1 is a mask with c3 leading zeros and c2 >= 32 and c3-c2==1. 796fe6060f1SDimitry Andric // 797fe6060f1SDimitry Andric // This pattern occurs when (i32 (srl (sra 31), c3 - 32)) is type 798fe6060f1SDimitry Andric // legalized and goes through DAG combine. 799753f127fSDimitry Andric if (C2 >= 32 && (Leading - C2) == 1 && N0.hasOneUse() && 80081ad6265SDimitry Andric X.getOpcode() == ISD::SIGN_EXTEND_INREG && 80181ad6265SDimitry Andric cast<VTSDNode>(X.getOperand(1))->getVT() == MVT::i32) { 802fe6060f1SDimitry Andric SDNode *SRAIW = 80381ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::SRAIW, DL, VT, X.getOperand(0), 80481ad6265SDimitry Andric CurDAG->getTargetConstant(31, DL, VT)); 805fe6060f1SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 80681ad6265SDimitry Andric RISCV::SRLIW, DL, VT, SDValue(SRAIW, 0), 807753f127fSDimitry Andric CurDAG->getTargetConstant(Leading - 32, DL, VT)); 808fe6060f1SDimitry Andric ReplaceNode(Node, SRLIW); 809fe6060f1SDimitry Andric return; 810fe6060f1SDimitry Andric } 811fe6060f1SDimitry Andric 812fe6060f1SDimitry Andric // (srli (slli x, c3-c2), c3). 81381ad6265SDimitry Andric // Skip if we could use (zext.w (sraiw X, C2)). 814753f127fSDimitry Andric bool Skip = Subtarget->hasStdExtZba() && Leading == 32 && 81581ad6265SDimitry Andric X.getOpcode() == ISD::SIGN_EXTEND_INREG && 81681ad6265SDimitry Andric cast<VTSDNode>(X.getOperand(1))->getVT() == MVT::i32; 81781ad6265SDimitry Andric // Also Skip if we can use bexti. 818753f127fSDimitry Andric Skip |= Subtarget->hasStdExtZbs() && Leading == XLen - 1; 81981ad6265SDimitry Andric if (OneUseOrZExtW && !Skip) { 820fe6060f1SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 82181ad6265SDimitry Andric RISCV::SLLI, DL, VT, X, 822753f127fSDimitry Andric CurDAG->getTargetConstant(Leading - C2, DL, VT)); 823753f127fSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 824753f127fSDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 825753f127fSDimitry Andric CurDAG->getTargetConstant(Leading, DL, VT)); 826fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 827fe6060f1SDimitry Andric return; 828fe6060f1SDimitry Andric } 829fe6060f1SDimitry Andric } 830fe6060f1SDimitry Andric } 831fe6060f1SDimitry Andric 832349cc55cSDimitry Andric // Turn (and (shl x, c2), c1) -> (srli (slli c2+c3), c3) if c1 is a mask 833fe6060f1SDimitry Andric // shifted by c2 bits with c3 leading zeros. 834fe6060f1SDimitry Andric if (LeftShift && isShiftedMask_64(C1)) { 835753f127fSDimitry Andric unsigned Leading = XLen - (64 - countLeadingZeros(C1)); 836fe6060f1SDimitry Andric 837753f127fSDimitry Andric if (C2 + Leading < XLen && 838753f127fSDimitry Andric C1 == (maskTrailingOnes<uint64_t>(XLen - (C2 + Leading)) << C2)) { 839fe6060f1SDimitry Andric // Use slli.uw when possible. 840753f127fSDimitry Andric if ((XLen - (C2 + Leading)) == 32 && Subtarget->hasStdExtZba()) { 84181ad6265SDimitry Andric SDNode *SLLI_UW = CurDAG->getMachineNode( 84281ad6265SDimitry Andric RISCV::SLLI_UW, DL, VT, X, CurDAG->getTargetConstant(C2, DL, VT)); 8431fd87a68SDimitry Andric ReplaceNode(Node, SLLI_UW); 844fe6060f1SDimitry Andric return; 845fe6060f1SDimitry Andric } 846fe6060f1SDimitry Andric 847fe6060f1SDimitry Andric // (srli (slli c2+c3), c3) 84881ad6265SDimitry Andric if (OneUseOrZExtW && !IsCANDI) { 849fe6060f1SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 85081ad6265SDimitry Andric RISCV::SLLI, DL, VT, X, 851753f127fSDimitry Andric CurDAG->getTargetConstant(C2 + Leading, DL, VT)); 852753f127fSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 853753f127fSDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 854753f127fSDimitry Andric CurDAG->getTargetConstant(Leading, DL, VT)); 855fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 856fe6060f1SDimitry Andric return; 857fe6060f1SDimitry Andric } 858fe6060f1SDimitry Andric } 859fe6060f1SDimitry Andric } 860fe6060f1SDimitry Andric 861349cc55cSDimitry Andric // Turn (and (shr x, c2), c1) -> (slli (srli x, c2+c3), c3) if c1 is a 862349cc55cSDimitry Andric // shifted mask with c2 leading zeros and c3 trailing zeros. 863349cc55cSDimitry Andric if (!LeftShift && isShiftedMask_64(C1)) { 864753f127fSDimitry Andric unsigned Leading = XLen - (64 - countLeadingZeros(C1)); 865753f127fSDimitry Andric unsigned Trailing = countTrailingZeros(C1); 866753f127fSDimitry Andric if (Leading == C2 && C2 + Trailing < XLen && OneUseOrZExtW && !IsCANDI) { 86781ad6265SDimitry Andric unsigned SrliOpc = RISCV::SRLI; 86881ad6265SDimitry Andric // If the input is zexti32 we should use SRLIW. 86981ad6265SDimitry Andric if (X.getOpcode() == ISD::AND && isa<ConstantSDNode>(X.getOperand(1)) && 87081ad6265SDimitry Andric X.getConstantOperandVal(1) == UINT64_C(0xFFFFFFFF)) { 87181ad6265SDimitry Andric SrliOpc = RISCV::SRLIW; 87281ad6265SDimitry Andric X = X.getOperand(0); 87381ad6265SDimitry Andric } 874349cc55cSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 875753f127fSDimitry Andric SrliOpc, DL, VT, X, 876753f127fSDimitry Andric CurDAG->getTargetConstant(C2 + Trailing, DL, VT)); 877349cc55cSDimitry Andric SDNode *SLLI = 87881ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, SDValue(SRLI, 0), 879753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 880349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 881349cc55cSDimitry Andric return; 882349cc55cSDimitry Andric } 883349cc55cSDimitry Andric // If the leading zero count is C2+32, we can use SRLIW instead of SRLI. 884753f127fSDimitry Andric if (Leading > 32 && (Leading - 32) == C2 && C2 + Trailing < 32 && 88581ad6265SDimitry Andric OneUseOrZExtW && !IsCANDI) { 886753f127fSDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 887753f127fSDimitry Andric RISCV::SRLIW, DL, VT, X, 888753f127fSDimitry Andric CurDAG->getTargetConstant(C2 + Trailing, DL, VT)); 889349cc55cSDimitry Andric SDNode *SLLI = 89081ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 891753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 892349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 893349cc55cSDimitry Andric return; 894349cc55cSDimitry Andric } 895349cc55cSDimitry Andric } 896349cc55cSDimitry Andric 897349cc55cSDimitry Andric // Turn (and (shl x, c2), c1) -> (slli (srli x, c3-c2), c3) if c1 is a 898349cc55cSDimitry Andric // shifted mask with no leading zeros and c3 trailing zeros. 899349cc55cSDimitry Andric if (LeftShift && isShiftedMask_64(C1)) { 900753f127fSDimitry Andric unsigned Leading = XLen - (64 - countLeadingZeros(C1)); 901753f127fSDimitry Andric unsigned Trailing = countTrailingZeros(C1); 902753f127fSDimitry Andric if (Leading == 0 && C2 < Trailing && OneUseOrZExtW && !IsCANDI) { 903349cc55cSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 904753f127fSDimitry Andric RISCV::SRLI, DL, VT, X, 905753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)); 906349cc55cSDimitry Andric SDNode *SLLI = 90781ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, SDValue(SRLI, 0), 908753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 909349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 910349cc55cSDimitry Andric return; 911349cc55cSDimitry Andric } 912349cc55cSDimitry Andric // If we have (32-C2) leading zeros, we can use SRLIW instead of SRLI. 913753f127fSDimitry Andric if (C2 < Trailing && Leading + C2 == 32 && OneUseOrZExtW && !IsCANDI) { 914753f127fSDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 915753f127fSDimitry Andric RISCV::SRLIW, DL, VT, X, 916753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)); 917349cc55cSDimitry Andric SDNode *SLLI = 91881ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 919753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 920349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 921349cc55cSDimitry Andric return; 922349cc55cSDimitry Andric } 923349cc55cSDimitry Andric } 924349cc55cSDimitry Andric 925fe6060f1SDimitry Andric break; 926fe6060f1SDimitry Andric } 9270eae32dcSDimitry Andric case ISD::MUL: { 9280eae32dcSDimitry Andric // Special case for calculating (mul (and X, C2), C1) where the full product 9290eae32dcSDimitry Andric // fits in XLen bits. We can shift X left by the number of leading zeros in 9300eae32dcSDimitry Andric // C2 and shift C1 left by XLen-lzcnt(C2). This will ensure the final 9310eae32dcSDimitry Andric // product has XLen trailing zeros, putting it in the output of MULHU. This 9320eae32dcSDimitry Andric // can avoid materializing a constant in a register for C2. 9330eae32dcSDimitry Andric 9340eae32dcSDimitry Andric // RHS should be a constant. 9350eae32dcSDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 9360eae32dcSDimitry Andric if (!N1C || !N1C->hasOneUse()) 9370eae32dcSDimitry Andric break; 9380eae32dcSDimitry Andric 9390eae32dcSDimitry Andric // LHS should be an AND with constant. 9400eae32dcSDimitry Andric SDValue N0 = Node->getOperand(0); 9410eae32dcSDimitry Andric if (N0.getOpcode() != ISD::AND || !isa<ConstantSDNode>(N0.getOperand(1))) 9420eae32dcSDimitry Andric break; 9430eae32dcSDimitry Andric 9440eae32dcSDimitry Andric uint64_t C2 = cast<ConstantSDNode>(N0.getOperand(1))->getZExtValue(); 9450eae32dcSDimitry Andric 9460eae32dcSDimitry Andric // Constant should be a mask. 9470eae32dcSDimitry Andric if (!isMask_64(C2)) 9480eae32dcSDimitry Andric break; 9490eae32dcSDimitry Andric 950*fcaf7f86SDimitry Andric // If this can be an ANDI, ZEXT.H or ZEXT.W, don't do this if the ANDI/ZEXT 951*fcaf7f86SDimitry Andric // has multiple users or the constant is a simm12. This prevents inserting 952*fcaf7f86SDimitry Andric // a shift and still have uses of the AND/ZEXT. Shifting a simm12 will 953*fcaf7f86SDimitry Andric // likely make it more costly to materialize. Otherwise, using a SLLI 954*fcaf7f86SDimitry Andric // might allow it to be compressed. 955*fcaf7f86SDimitry Andric bool IsANDIOrZExt = 956*fcaf7f86SDimitry Andric isInt<12>(C2) || 9570eae32dcSDimitry Andric (C2 == UINT64_C(0xFFFF) && 9580eae32dcSDimitry Andric (Subtarget->hasStdExtZbb() || Subtarget->hasStdExtZbp())) || 959*fcaf7f86SDimitry Andric (C2 == UINT64_C(0xFFFFFFFF) && Subtarget->hasStdExtZba()); 960*fcaf7f86SDimitry Andric if (IsANDIOrZExt && (isInt<12>(N1C->getSExtValue()) || !N0.hasOneUse())) 9610eae32dcSDimitry Andric break; 9620eae32dcSDimitry Andric 9630eae32dcSDimitry Andric // We need to shift left the AND input and C1 by a total of XLen bits. 9640eae32dcSDimitry Andric 9650eae32dcSDimitry Andric // How far left do we need to shift the AND input? 9660eae32dcSDimitry Andric unsigned XLen = Subtarget->getXLen(); 9670eae32dcSDimitry Andric unsigned LeadingZeros = XLen - (64 - countLeadingZeros(C2)); 9680eae32dcSDimitry Andric 9690eae32dcSDimitry Andric // The constant gets shifted by the remaining amount unless that would 9700eae32dcSDimitry Andric // shift bits out. 9710eae32dcSDimitry Andric uint64_t C1 = N1C->getZExtValue(); 9720eae32dcSDimitry Andric unsigned ConstantShift = XLen - LeadingZeros; 9730eae32dcSDimitry Andric if (ConstantShift > (XLen - (64 - countLeadingZeros(C1)))) 9740eae32dcSDimitry Andric break; 9750eae32dcSDimitry Andric 9760eae32dcSDimitry Andric uint64_t ShiftedC1 = C1 << ConstantShift; 9770eae32dcSDimitry Andric // If this RV32, we need to sign extend the constant. 9780eae32dcSDimitry Andric if (XLen == 32) 97981ad6265SDimitry Andric ShiftedC1 = SignExtend64<32>(ShiftedC1); 9800eae32dcSDimitry Andric 9810eae32dcSDimitry Andric // Create (mulhu (slli X, lzcnt(C2)), C1 << (XLen - lzcnt(C2))). 98204eeddc0SDimitry Andric SDNode *Imm = selectImm(CurDAG, DL, VT, ShiftedC1, *Subtarget); 9830eae32dcSDimitry Andric SDNode *SLLI = 9840eae32dcSDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0.getOperand(0), 9850eae32dcSDimitry Andric CurDAG->getTargetConstant(LeadingZeros, DL, VT)); 9860eae32dcSDimitry Andric SDNode *MULHU = CurDAG->getMachineNode(RISCV::MULHU, DL, VT, 9870eae32dcSDimitry Andric SDValue(SLLI, 0), SDValue(Imm, 0)); 9880eae32dcSDimitry Andric ReplaceNode(Node, MULHU); 9890eae32dcSDimitry Andric return; 9900eae32dcSDimitry Andric } 991fe6060f1SDimitry Andric case ISD::INTRINSIC_WO_CHAIN: { 992fe6060f1SDimitry Andric unsigned IntNo = Node->getConstantOperandVal(0); 993fe6060f1SDimitry Andric switch (IntNo) { 994fe6060f1SDimitry Andric // By default we do not custom select any intrinsic. 995fe6060f1SDimitry Andric default: 996fe6060f1SDimitry Andric break; 997fe6060f1SDimitry Andric case Intrinsic::riscv_vmsgeu: 998fe6060f1SDimitry Andric case Intrinsic::riscv_vmsge: { 999fe6060f1SDimitry Andric SDValue Src1 = Node->getOperand(1); 1000fe6060f1SDimitry Andric SDValue Src2 = Node->getOperand(2); 100104eeddc0SDimitry Andric bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu; 100204eeddc0SDimitry Andric bool IsCmpUnsignedZero = false; 1003fe6060f1SDimitry Andric // Only custom select scalar second operand. 1004fe6060f1SDimitry Andric if (Src2.getValueType() != XLenVT) 1005fe6060f1SDimitry Andric break; 1006fe6060f1SDimitry Andric // Small constants are handled with patterns. 1007fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Src2)) { 1008fe6060f1SDimitry Andric int64_t CVal = C->getSExtValue(); 100904eeddc0SDimitry Andric if (CVal >= -15 && CVal <= 16) { 101004eeddc0SDimitry Andric if (!IsUnsigned || CVal != 0) 1011fe6060f1SDimitry Andric break; 101204eeddc0SDimitry Andric IsCmpUnsignedZero = true; 1013fe6060f1SDimitry Andric } 101404eeddc0SDimitry Andric } 1015fe6060f1SDimitry Andric MVT Src1VT = Src1.getSimpleValueType(); 101604eeddc0SDimitry Andric unsigned VMSLTOpcode, VMNANDOpcode, VMSetOpcode; 1017fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(Src1VT)) { 1018fe6060f1SDimitry Andric default: 1019fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 102004eeddc0SDimitry Andric #define CASE_VMSLT_VMNAND_VMSET_OPCODES(lmulenum, suffix, suffix_b) \ 102104eeddc0SDimitry Andric case RISCVII::VLMUL::lmulenum: \ 102204eeddc0SDimitry Andric VMSLTOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix \ 102304eeddc0SDimitry Andric : RISCV::PseudoVMSLT_VX_##suffix; \ 102404eeddc0SDimitry Andric VMNANDOpcode = RISCV::PseudoVMNAND_MM_##suffix; \ 102504eeddc0SDimitry Andric VMSetOpcode = RISCV::PseudoVMSET_M_##suffix_b; \ 1026fe6060f1SDimitry Andric break; 102704eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F8, MF8, B1) 102804eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F4, MF4, B2) 102904eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F2, MF2, B4) 103004eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_1, M1, B8) 103104eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_2, M2, B16) 103204eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_4, M4, B32) 103304eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_8, M8, B64) 103404eeddc0SDimitry Andric #undef CASE_VMSLT_VMNAND_VMSET_OPCODES 1035fe6060f1SDimitry Andric } 1036fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant( 1037fe6060f1SDimitry Andric Log2_32(Src1VT.getScalarSizeInBits()), DL, XLenVT); 1038fe6060f1SDimitry Andric SDValue VL; 1039fe6060f1SDimitry Andric selectVLOp(Node->getOperand(3), VL); 1040fe6060f1SDimitry Andric 104104eeddc0SDimitry Andric // If vmsgeu with 0 immediate, expand it to vmset. 104204eeddc0SDimitry Andric if (IsCmpUnsignedZero) { 104304eeddc0SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMSetOpcode, DL, VT, VL, SEW)); 104404eeddc0SDimitry Andric return; 104504eeddc0SDimitry Andric } 104604eeddc0SDimitry Andric 1047fe6060f1SDimitry Andric // Expand to 1048fe6060f1SDimitry Andric // vmslt{u}.vx vd, va, x; vmnand.mm vd, vd, vd 1049fe6060f1SDimitry Andric SDValue Cmp = SDValue( 1050fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTOpcode, DL, VT, {Src1, Src2, VL, SEW}), 1051fe6060f1SDimitry Andric 0); 1052fe6060f1SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMNANDOpcode, DL, VT, 1053fe6060f1SDimitry Andric {Cmp, Cmp, VL, SEW})); 1054fe6060f1SDimitry Andric return; 1055fe6060f1SDimitry Andric } 1056fe6060f1SDimitry Andric case Intrinsic::riscv_vmsgeu_mask: 1057fe6060f1SDimitry Andric case Intrinsic::riscv_vmsge_mask: { 1058fe6060f1SDimitry Andric SDValue Src1 = Node->getOperand(2); 1059fe6060f1SDimitry Andric SDValue Src2 = Node->getOperand(3); 106004eeddc0SDimitry Andric bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu_mask; 106104eeddc0SDimitry Andric bool IsCmpUnsignedZero = false; 1062fe6060f1SDimitry Andric // Only custom select scalar second operand. 1063fe6060f1SDimitry Andric if (Src2.getValueType() != XLenVT) 1064fe6060f1SDimitry Andric break; 1065fe6060f1SDimitry Andric // Small constants are handled with patterns. 1066fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Src2)) { 1067fe6060f1SDimitry Andric int64_t CVal = C->getSExtValue(); 106804eeddc0SDimitry Andric if (CVal >= -15 && CVal <= 16) { 106904eeddc0SDimitry Andric if (!IsUnsigned || CVal != 0) 1070fe6060f1SDimitry Andric break; 107104eeddc0SDimitry Andric IsCmpUnsignedZero = true; 1072fe6060f1SDimitry Andric } 107304eeddc0SDimitry Andric } 1074fe6060f1SDimitry Andric MVT Src1VT = Src1.getSimpleValueType(); 107504eeddc0SDimitry Andric unsigned VMSLTOpcode, VMSLTMaskOpcode, VMXOROpcode, VMANDNOpcode, 107681ad6265SDimitry Andric VMOROpcode; 1077fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(Src1VT)) { 1078fe6060f1SDimitry Andric default: 1079fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 108081ad6265SDimitry Andric #define CASE_VMSLT_OPCODES(lmulenum, suffix, suffix_b) \ 108104eeddc0SDimitry Andric case RISCVII::VLMUL::lmulenum: \ 108204eeddc0SDimitry Andric VMSLTOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix \ 108304eeddc0SDimitry Andric : RISCV::PseudoVMSLT_VX_##suffix; \ 108404eeddc0SDimitry Andric VMSLTMaskOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix##_MASK \ 108504eeddc0SDimitry Andric : RISCV::PseudoVMSLT_VX_##suffix##_MASK; \ 1086fe6060f1SDimitry Andric break; 108781ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_F8, MF8, B1) 108881ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_F4, MF4, B2) 108981ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_F2, MF2, B4) 109081ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_1, M1, B8) 109181ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_2, M2, B16) 109281ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_4, M4, B32) 109381ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_8, M8, B64) 109481ad6265SDimitry Andric #undef CASE_VMSLT_OPCODES 1095fe6060f1SDimitry Andric } 1096fe6060f1SDimitry Andric // Mask operations use the LMUL from the mask type. 1097fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(VT)) { 1098fe6060f1SDimitry Andric default: 1099fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 110081ad6265SDimitry Andric #define CASE_VMXOR_VMANDN_VMOR_OPCODES(lmulenum, suffix) \ 110104eeddc0SDimitry Andric case RISCVII::VLMUL::lmulenum: \ 110204eeddc0SDimitry Andric VMXOROpcode = RISCV::PseudoVMXOR_MM_##suffix; \ 110304eeddc0SDimitry Andric VMANDNOpcode = RISCV::PseudoVMANDN_MM_##suffix; \ 110481ad6265SDimitry Andric VMOROpcode = RISCV::PseudoVMOR_MM_##suffix; \ 1105fe6060f1SDimitry Andric break; 110681ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_F8, MF8) 110781ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_F4, MF4) 110881ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_F2, MF2) 110981ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_1, M1) 111081ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_2, M2) 111181ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_4, M4) 111281ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_8, M8) 111381ad6265SDimitry Andric #undef CASE_VMXOR_VMANDN_VMOR_OPCODES 1114fe6060f1SDimitry Andric } 1115fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant( 1116fe6060f1SDimitry Andric Log2_32(Src1VT.getScalarSizeInBits()), DL, XLenVT); 1117fe6060f1SDimitry Andric SDValue MaskSEW = CurDAG->getTargetConstant(0, DL, XLenVT); 1118fe6060f1SDimitry Andric SDValue VL; 1119fe6060f1SDimitry Andric selectVLOp(Node->getOperand(5), VL); 1120fe6060f1SDimitry Andric SDValue MaskedOff = Node->getOperand(1); 1121fe6060f1SDimitry Andric SDValue Mask = Node->getOperand(4); 112204eeddc0SDimitry Andric 112381ad6265SDimitry Andric // If vmsgeu_mask with 0 immediate, expand it to vmor mask, maskedoff. 112404eeddc0SDimitry Andric if (IsCmpUnsignedZero) { 112581ad6265SDimitry Andric // We don't need vmor if the MaskedOff and the Mask are the same 112681ad6265SDimitry Andric // value. 112781ad6265SDimitry Andric if (Mask == MaskedOff) { 112881ad6265SDimitry Andric ReplaceUses(Node, Mask.getNode()); 112981ad6265SDimitry Andric return; 113081ad6265SDimitry Andric } 113181ad6265SDimitry Andric ReplaceNode(Node, 113281ad6265SDimitry Andric CurDAG->getMachineNode(VMOROpcode, DL, VT, 113381ad6265SDimitry Andric {Mask, MaskedOff, VL, MaskSEW})); 113404eeddc0SDimitry Andric return; 113504eeddc0SDimitry Andric } 113604eeddc0SDimitry Andric 1137fe6060f1SDimitry Andric // If the MaskedOff value and the Mask are the same value use 1138349cc55cSDimitry Andric // vmslt{u}.vx vt, va, x; vmandn.mm vd, vd, vt 1139fe6060f1SDimitry Andric // This avoids needing to copy v0 to vd before starting the next sequence. 1140fe6060f1SDimitry Andric if (Mask == MaskedOff) { 1141fe6060f1SDimitry Andric SDValue Cmp = SDValue( 1142fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTOpcode, DL, VT, {Src1, Src2, VL, SEW}), 1143fe6060f1SDimitry Andric 0); 1144349cc55cSDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMANDNOpcode, DL, VT, 1145fe6060f1SDimitry Andric {Mask, Cmp, VL, MaskSEW})); 1146fe6060f1SDimitry Andric return; 1147fe6060f1SDimitry Andric } 1148fe6060f1SDimitry Andric 1149fe6060f1SDimitry Andric // Mask needs to be copied to V0. 1150fe6060f1SDimitry Andric SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, 1151fe6060f1SDimitry Andric RISCV::V0, Mask, SDValue()); 1152fe6060f1SDimitry Andric SDValue Glue = Chain.getValue(1); 1153fe6060f1SDimitry Andric SDValue V0 = CurDAG->getRegister(RISCV::V0, VT); 1154fe6060f1SDimitry Andric 1155fe6060f1SDimitry Andric // Otherwise use 1156fe6060f1SDimitry Andric // vmslt{u}.vx vd, va, x, v0.t; vmxor.mm vd, vd, v0 115781ad6265SDimitry Andric // The result is mask undisturbed. 115881ad6265SDimitry Andric // We use the same instructions to emulate mask agnostic behavior, because 115981ad6265SDimitry Andric // the agnostic result can be either undisturbed or all 1. 1160fe6060f1SDimitry Andric SDValue Cmp = SDValue( 1161fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTMaskOpcode, DL, VT, 1162fe6060f1SDimitry Andric {MaskedOff, Src1, Src2, V0, VL, SEW, Glue}), 1163fe6060f1SDimitry Andric 0); 116481ad6265SDimitry Andric // vmxor.mm vd, vd, v0 is used to update active value. 1165fe6060f1SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMXOROpcode, DL, VT, 1166fe6060f1SDimitry Andric {Cmp, Mask, VL, MaskSEW})); 1167fe6060f1SDimitry Andric return; 1168fe6060f1SDimitry Andric } 116904eeddc0SDimitry Andric case Intrinsic::riscv_vsetvli_opt: 117004eeddc0SDimitry Andric case Intrinsic::riscv_vsetvlimax_opt: 117104eeddc0SDimitry Andric return selectVSETVLI(Node); 1172fe6060f1SDimitry Andric } 1173fe6060f1SDimitry Andric break; 1174fe6060f1SDimitry Andric } 1175e8d8bef9SDimitry Andric case ISD::INTRINSIC_W_CHAIN: { 1176e8d8bef9SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 1177e8d8bef9SDimitry Andric switch (IntNo) { 1178e8d8bef9SDimitry Andric // By default we do not custom select any intrinsic. 1179e8d8bef9SDimitry Andric default: 11800b57cec5SDimitry Andric break; 1181fe6060f1SDimitry Andric case Intrinsic::riscv_vsetvli: 118204eeddc0SDimitry Andric case Intrinsic::riscv_vsetvlimax: 118304eeddc0SDimitry Andric return selectVSETVLI(Node); 1184e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg2: 1185e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg3: 1186e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg4: 1187e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg5: 1188e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg6: 1189e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg7: 1190e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg8: { 1191fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ false, /*IsStrided*/ false); 1192e8d8bef9SDimitry Andric return; 1193e8d8bef9SDimitry Andric } 1194e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg2_mask: 1195e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg3_mask: 1196e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg4_mask: 1197e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg5_mask: 1198e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg6_mask: 1199e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg7_mask: 1200e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg8_mask: { 1201fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ true, /*IsStrided*/ false); 1202e8d8bef9SDimitry Andric return; 1203e8d8bef9SDimitry Andric } 1204e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg2: 1205e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg3: 1206e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg4: 1207e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg5: 1208e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg6: 1209e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg7: 1210e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg8: { 1211fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ false, /*IsStrided*/ true); 1212e8d8bef9SDimitry Andric return; 1213e8d8bef9SDimitry Andric } 1214e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg2_mask: 1215e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg3_mask: 1216e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg4_mask: 1217e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg5_mask: 1218e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg6_mask: 1219e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg7_mask: 1220e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg8_mask: { 1221fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ true, /*IsStrided*/ true); 1222e8d8bef9SDimitry Andric return; 1223e8d8bef9SDimitry Andric } 1224e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg2: 1225e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg3: 1226e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg4: 1227e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg5: 1228e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg6: 1229e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg7: 1230e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg8: 1231fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ true); 1232fe6060f1SDimitry Andric return; 1233e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg2: 1234e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg3: 1235e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg4: 1236e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg5: 1237e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg6: 1238e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg7: 1239fe6060f1SDimitry Andric case Intrinsic::riscv_vluxseg8: 1240fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ false); 1241e8d8bef9SDimitry Andric return; 1242e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg2_mask: 1243e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg3_mask: 1244e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg4_mask: 1245e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg5_mask: 1246e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg6_mask: 1247e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg7_mask: 1248e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg8_mask: 1249fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ true); 1250fe6060f1SDimitry Andric return; 1251e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg2_mask: 1252e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg3_mask: 1253e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg4_mask: 1254e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg5_mask: 1255e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg6_mask: 1256e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg7_mask: 1257fe6060f1SDimitry Andric case Intrinsic::riscv_vluxseg8_mask: 1258fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ false); 1259fe6060f1SDimitry Andric return; 1260fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg8ff: 1261fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg7ff: 1262fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg6ff: 1263fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg5ff: 1264fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg4ff: 1265fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg3ff: 1266fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg2ff: { 1267fe6060f1SDimitry Andric selectVLSEGFF(Node, /*IsMasked*/ false); 1268fe6060f1SDimitry Andric return; 1269fe6060f1SDimitry Andric } 1270fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg8ff_mask: 1271fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg7ff_mask: 1272fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg6ff_mask: 1273fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg5ff_mask: 1274fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg4ff_mask: 1275fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg3ff_mask: 1276fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg2ff_mask: { 1277fe6060f1SDimitry Andric selectVLSEGFF(Node, /*IsMasked*/ true); 1278fe6060f1SDimitry Andric return; 1279fe6060f1SDimitry Andric } 1280fe6060f1SDimitry Andric case Intrinsic::riscv_vloxei: 1281fe6060f1SDimitry Andric case Intrinsic::riscv_vloxei_mask: 1282fe6060f1SDimitry Andric case Intrinsic::riscv_vluxei: 1283fe6060f1SDimitry Andric case Intrinsic::riscv_vluxei_mask: { 1284fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vloxei_mask || 1285fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vluxei_mask; 1286fe6060f1SDimitry Andric bool IsOrdered = IntNo == Intrinsic::riscv_vloxei || 1287fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vloxei_mask; 1288fe6060f1SDimitry Andric 1289fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1290fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1291fe6060f1SDimitry Andric 1292fe6060f1SDimitry Andric unsigned CurOp = 2; 129304eeddc0SDimitry Andric // Masked intrinsic only have TU version pseduo instructions. 129481ad6265SDimitry Andric bool IsTU = IsMasked || !Node->getOperand(CurOp).isUndef(); 1295fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 129604eeddc0SDimitry Andric if (IsTU) 1297fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 129804eeddc0SDimitry Andric else 129904eeddc0SDimitry Andric // Skip the undef passthru operand for nomask TA version pseudo 130004eeddc0SDimitry Andric CurOp++; 1301fe6060f1SDimitry Andric 1302fe6060f1SDimitry Andric MVT IndexVT; 1303fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1304fe6060f1SDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 1305349cc55cSDimitry Andric /*IsLoad=*/true, &IndexVT); 1306fe6060f1SDimitry Andric 1307fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 1308fe6060f1SDimitry Andric "Element count mismatch"); 1309fe6060f1SDimitry Andric 1310fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1311fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 1312fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 131304eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 131404eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 131504eeddc0SDimitry Andric "values when XLEN=32"); 131604eeddc0SDimitry Andric } 1317fe6060f1SDimitry Andric const RISCV::VLX_VSXPseudo *P = RISCV::getVLXPseudo( 131804eeddc0SDimitry Andric IsMasked, IsTU, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 1319fe6060f1SDimitry Andric static_cast<unsigned>(IndexLMUL)); 1320fe6060f1SDimitry Andric MachineSDNode *Load = 1321fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1322fe6060f1SDimitry Andric 1323fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1324fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1325fe6060f1SDimitry Andric 1326fe6060f1SDimitry Andric ReplaceNode(Node, Load); 1327fe6060f1SDimitry Andric return; 1328fe6060f1SDimitry Andric } 1329349cc55cSDimitry Andric case Intrinsic::riscv_vlm: 1330fe6060f1SDimitry Andric case Intrinsic::riscv_vle: 1331fe6060f1SDimitry Andric case Intrinsic::riscv_vle_mask: 1332fe6060f1SDimitry Andric case Intrinsic::riscv_vlse: 1333fe6060f1SDimitry Andric case Intrinsic::riscv_vlse_mask: { 1334fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vle_mask || 1335fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vlse_mask; 1336fe6060f1SDimitry Andric bool IsStrided = 1337fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vlse || IntNo == Intrinsic::riscv_vlse_mask; 1338fe6060f1SDimitry Andric 1339fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1340fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1341fe6060f1SDimitry Andric 1342fe6060f1SDimitry Andric unsigned CurOp = 2; 134304eeddc0SDimitry Andric // The riscv_vlm intrinsic are always tail agnostic and no passthru operand. 134404eeddc0SDimitry Andric bool HasPassthruOperand = IntNo != Intrinsic::riscv_vlm; 134504eeddc0SDimitry Andric // Masked intrinsic only have TU version pseduo instructions. 134681ad6265SDimitry Andric bool IsTU = HasPassthruOperand && 134781ad6265SDimitry Andric (IsMasked || !Node->getOperand(CurOp).isUndef()); 1348fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 134904eeddc0SDimitry Andric if (IsTU) 1350fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 135104eeddc0SDimitry Andric else if (HasPassthruOperand) 135204eeddc0SDimitry Andric // Skip the undef passthru operand for nomask TA version pseudo 135304eeddc0SDimitry Andric CurOp++; 1354fe6060f1SDimitry Andric 1355fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 1356349cc55cSDimitry Andric Operands, /*IsLoad=*/true); 1357fe6060f1SDimitry Andric 1358fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1359fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = 136004eeddc0SDimitry Andric RISCV::getVLEPseudo(IsMasked, IsTU, IsStrided, /*FF*/ false, Log2SEW, 1361fe6060f1SDimitry Andric static_cast<unsigned>(LMUL)); 1362fe6060f1SDimitry Andric MachineSDNode *Load = 1363fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1364fe6060f1SDimitry Andric 1365fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1366fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1367fe6060f1SDimitry Andric 1368fe6060f1SDimitry Andric ReplaceNode(Node, Load); 1369fe6060f1SDimitry Andric return; 1370fe6060f1SDimitry Andric } 1371fe6060f1SDimitry Andric case Intrinsic::riscv_vleff: 1372fe6060f1SDimitry Andric case Intrinsic::riscv_vleff_mask: { 1373fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vleff_mask; 1374fe6060f1SDimitry Andric 1375fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1376fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1377fe6060f1SDimitry Andric 1378fe6060f1SDimitry Andric unsigned CurOp = 2; 137904eeddc0SDimitry Andric // Masked intrinsic only have TU version pseduo instructions. 138081ad6265SDimitry Andric bool IsTU = IsMasked || !Node->getOperand(CurOp).isUndef(); 1381fe6060f1SDimitry Andric SmallVector<SDValue, 7> Operands; 138204eeddc0SDimitry Andric if (IsTU) 1383fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 138404eeddc0SDimitry Andric else 138504eeddc0SDimitry Andric // Skip the undef passthru operand for nomask TA version pseudo 138604eeddc0SDimitry Andric CurOp++; 1387fe6060f1SDimitry Andric 1388fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1389349cc55cSDimitry Andric /*IsStridedOrIndexed*/ false, Operands, 1390349cc55cSDimitry Andric /*IsLoad=*/true); 1391fe6060f1SDimitry Andric 1392fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1393fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = 139404eeddc0SDimitry Andric RISCV::getVLEPseudo(IsMasked, IsTU, /*Strided*/ false, /*FF*/ true, 139504eeddc0SDimitry Andric Log2SEW, static_cast<unsigned>(LMUL)); 139681ad6265SDimitry Andric MachineSDNode *Load = CurDAG->getMachineNode( 139781ad6265SDimitry Andric P->Pseudo, DL, Node->getVTList(), Operands); 1398fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1399fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1400fe6060f1SDimitry Andric 140181ad6265SDimitry Andric ReplaceNode(Node, Load); 14020b57cec5SDimitry Andric return; 14030b57cec5SDimitry Andric } 14040b57cec5SDimitry Andric } 14050b57cec5SDimitry Andric break; 14060b57cec5SDimitry Andric } 1407e8d8bef9SDimitry Andric case ISD::INTRINSIC_VOID: { 1408e8d8bef9SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 1409e8d8bef9SDimitry Andric switch (IntNo) { 1410e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg2: 1411e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg3: 1412e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg4: 1413e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg5: 1414e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg6: 1415e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg7: 1416e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg8: { 1417fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ false, /*IsStrided*/ false); 14180b57cec5SDimitry Andric return; 14190b57cec5SDimitry Andric } 1420e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg2_mask: 1421e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg3_mask: 1422e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg4_mask: 1423e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg5_mask: 1424e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg6_mask: 1425e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg7_mask: 1426e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg8_mask: { 1427fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ true, /*IsStrided*/ false); 1428e8d8bef9SDimitry Andric return; 1429e8d8bef9SDimitry Andric } 1430e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg2: 1431e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg3: 1432e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg4: 1433e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg5: 1434e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg6: 1435e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg7: 1436e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg8: { 1437fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ false, /*IsStrided*/ true); 1438e8d8bef9SDimitry Andric return; 1439e8d8bef9SDimitry Andric } 1440e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg2_mask: 1441e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg3_mask: 1442e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg4_mask: 1443e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg5_mask: 1444e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg6_mask: 1445e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg7_mask: 1446e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg8_mask: { 1447fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ true, /*IsStrided*/ true); 1448e8d8bef9SDimitry Andric return; 1449e8d8bef9SDimitry Andric } 1450e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg2: 1451e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg3: 1452e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg4: 1453e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg5: 1454e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg6: 1455e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg7: 1456e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg8: 1457fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ true); 1458fe6060f1SDimitry Andric return; 1459e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg2: 1460e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg3: 1461e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg4: 1462e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg5: 1463e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg6: 1464e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg7: 1465fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxseg8: 1466fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ false); 1467e8d8bef9SDimitry Andric return; 1468e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg2_mask: 1469e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg3_mask: 1470e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg4_mask: 1471e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg5_mask: 1472e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg6_mask: 1473e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg7_mask: 1474e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg8_mask: 1475fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ true); 1476fe6060f1SDimitry Andric return; 1477e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg2_mask: 1478e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg3_mask: 1479e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg4_mask: 1480e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg5_mask: 1481e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg6_mask: 1482e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg7_mask: 1483fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxseg8_mask: 1484fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ false); 1485fe6060f1SDimitry Andric return; 1486fe6060f1SDimitry Andric case Intrinsic::riscv_vsoxei: 1487fe6060f1SDimitry Andric case Intrinsic::riscv_vsoxei_mask: 1488fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxei: 1489fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxei_mask: { 1490fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vsoxei_mask || 1491fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsuxei_mask; 1492fe6060f1SDimitry Andric bool IsOrdered = IntNo == Intrinsic::riscv_vsoxei || 1493fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsoxei_mask; 1494fe6060f1SDimitry Andric 1495fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 1496fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1497fe6060f1SDimitry Andric 1498fe6060f1SDimitry Andric unsigned CurOp = 2; 1499fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 1500fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Store value. 1501fe6060f1SDimitry Andric 1502fe6060f1SDimitry Andric MVT IndexVT; 1503fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1504fe6060f1SDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 1505349cc55cSDimitry Andric /*IsLoad=*/false, &IndexVT); 1506fe6060f1SDimitry Andric 1507fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 1508fe6060f1SDimitry Andric "Element count mismatch"); 1509fe6060f1SDimitry Andric 1510fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1511fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 1512fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 151304eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 151404eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 151504eeddc0SDimitry Andric "values when XLEN=32"); 151604eeddc0SDimitry Andric } 1517fe6060f1SDimitry Andric const RISCV::VLX_VSXPseudo *P = RISCV::getVSXPseudo( 151804eeddc0SDimitry Andric IsMasked, /*TU*/ false, IsOrdered, IndexLog2EEW, 151904eeddc0SDimitry Andric static_cast<unsigned>(LMUL), static_cast<unsigned>(IndexLMUL)); 1520fe6060f1SDimitry Andric MachineSDNode *Store = 1521fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1522fe6060f1SDimitry Andric 1523fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1524fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 1525fe6060f1SDimitry Andric 1526fe6060f1SDimitry Andric ReplaceNode(Node, Store); 1527fe6060f1SDimitry Andric return; 1528fe6060f1SDimitry Andric } 1529349cc55cSDimitry Andric case Intrinsic::riscv_vsm: 1530fe6060f1SDimitry Andric case Intrinsic::riscv_vse: 1531fe6060f1SDimitry Andric case Intrinsic::riscv_vse_mask: 1532fe6060f1SDimitry Andric case Intrinsic::riscv_vsse: 1533fe6060f1SDimitry Andric case Intrinsic::riscv_vsse_mask: { 1534fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vse_mask || 1535fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsse_mask; 1536fe6060f1SDimitry Andric bool IsStrided = 1537fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsse || IntNo == Intrinsic::riscv_vsse_mask; 1538fe6060f1SDimitry Andric 1539fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 1540fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1541fe6060f1SDimitry Andric 1542fe6060f1SDimitry Andric unsigned CurOp = 2; 1543fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 1544fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Store value. 1545fe6060f1SDimitry Andric 1546fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 1547fe6060f1SDimitry Andric Operands); 1548fe6060f1SDimitry Andric 1549fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1550fe6060f1SDimitry Andric const RISCV::VSEPseudo *P = RISCV::getVSEPseudo( 1551fe6060f1SDimitry Andric IsMasked, IsStrided, Log2SEW, static_cast<unsigned>(LMUL)); 1552fe6060f1SDimitry Andric MachineSDNode *Store = 1553fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1554fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1555fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 1556fe6060f1SDimitry Andric 1557fe6060f1SDimitry Andric ReplaceNode(Node, Store); 1558e8d8bef9SDimitry Andric return; 1559e8d8bef9SDimitry Andric } 1560e8d8bef9SDimitry Andric } 1561e8d8bef9SDimitry Andric break; 1562e8d8bef9SDimitry Andric } 1563fe6060f1SDimitry Andric case ISD::BITCAST: { 1564fe6060f1SDimitry Andric MVT SrcVT = Node->getOperand(0).getSimpleValueType(); 1565fe6060f1SDimitry Andric // Just drop bitcasts between vectors if both are fixed or both are 1566fe6060f1SDimitry Andric // scalable. 1567fe6060f1SDimitry Andric if ((VT.isScalableVector() && SrcVT.isScalableVector()) || 1568fe6060f1SDimitry Andric (VT.isFixedLengthVector() && SrcVT.isFixedLengthVector())) { 1569fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, 0), Node->getOperand(0)); 1570fe6060f1SDimitry Andric CurDAG->RemoveDeadNode(Node); 1571e8d8bef9SDimitry Andric return; 1572e8d8bef9SDimitry Andric } 1573fe6060f1SDimitry Andric break; 1574fe6060f1SDimitry Andric } 1575fe6060f1SDimitry Andric case ISD::INSERT_SUBVECTOR: { 1576fe6060f1SDimitry Andric SDValue V = Node->getOperand(0); 1577fe6060f1SDimitry Andric SDValue SubV = Node->getOperand(1); 1578fe6060f1SDimitry Andric SDLoc DL(SubV); 1579fe6060f1SDimitry Andric auto Idx = Node->getConstantOperandVal(2); 1580fe6060f1SDimitry Andric MVT SubVecVT = SubV.getSimpleValueType(); 1581fe6060f1SDimitry Andric 1582fe6060f1SDimitry Andric const RISCVTargetLowering &TLI = *Subtarget->getTargetLowering(); 1583fe6060f1SDimitry Andric MVT SubVecContainerVT = SubVecVT; 1584fe6060f1SDimitry Andric // Establish the correct scalable-vector types for any fixed-length type. 1585fe6060f1SDimitry Andric if (SubVecVT.isFixedLengthVector()) 1586fe6060f1SDimitry Andric SubVecContainerVT = TLI.getContainerForFixedLengthVector(SubVecVT); 1587fe6060f1SDimitry Andric if (VT.isFixedLengthVector()) 1588fe6060f1SDimitry Andric VT = TLI.getContainerForFixedLengthVector(VT); 1589fe6060f1SDimitry Andric 1590fe6060f1SDimitry Andric const auto *TRI = Subtarget->getRegisterInfo(); 1591fe6060f1SDimitry Andric unsigned SubRegIdx; 1592fe6060f1SDimitry Andric std::tie(SubRegIdx, Idx) = 1593fe6060f1SDimitry Andric RISCVTargetLowering::decomposeSubvectorInsertExtractToSubRegs( 1594fe6060f1SDimitry Andric VT, SubVecContainerVT, Idx, TRI); 1595fe6060f1SDimitry Andric 1596fe6060f1SDimitry Andric // If the Idx hasn't been completely eliminated then this is a subvector 1597fe6060f1SDimitry Andric // insert which doesn't naturally align to a vector register. These must 1598fe6060f1SDimitry Andric // be handled using instructions to manipulate the vector registers. 1599fe6060f1SDimitry Andric if (Idx != 0) 1600fe6060f1SDimitry Andric break; 1601fe6060f1SDimitry Andric 1602fe6060f1SDimitry Andric RISCVII::VLMUL SubVecLMUL = RISCVTargetLowering::getLMUL(SubVecContainerVT); 1603fe6060f1SDimitry Andric bool IsSubVecPartReg = SubVecLMUL == RISCVII::VLMUL::LMUL_F2 || 1604fe6060f1SDimitry Andric SubVecLMUL == RISCVII::VLMUL::LMUL_F4 || 1605fe6060f1SDimitry Andric SubVecLMUL == RISCVII::VLMUL::LMUL_F8; 1606fe6060f1SDimitry Andric (void)IsSubVecPartReg; // Silence unused variable warning without asserts. 1607fe6060f1SDimitry Andric assert((!IsSubVecPartReg || V.isUndef()) && 1608fe6060f1SDimitry Andric "Expecting lowering to have created legal INSERT_SUBVECTORs when " 1609fe6060f1SDimitry Andric "the subvector is smaller than a full-sized register"); 1610fe6060f1SDimitry Andric 1611fe6060f1SDimitry Andric // If we haven't set a SubRegIdx, then we must be going between 1612fe6060f1SDimitry Andric // equally-sized LMUL groups (e.g. VR -> VR). This can be done as a copy. 1613fe6060f1SDimitry Andric if (SubRegIdx == RISCV::NoSubRegister) { 1614fe6060f1SDimitry Andric unsigned InRegClassID = RISCVTargetLowering::getRegClassIDForVecVT(VT); 1615fe6060f1SDimitry Andric assert(RISCVTargetLowering::getRegClassIDForVecVT(SubVecContainerVT) == 1616fe6060f1SDimitry Andric InRegClassID && 1617fe6060f1SDimitry Andric "Unexpected subvector extraction"); 1618fe6060f1SDimitry Andric SDValue RC = CurDAG->getTargetConstant(InRegClassID, DL, XLenVT); 1619fe6060f1SDimitry Andric SDNode *NewNode = CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, 1620fe6060f1SDimitry Andric DL, VT, SubV, RC); 1621fe6060f1SDimitry Andric ReplaceNode(Node, NewNode); 1622fe6060f1SDimitry Andric return; 1623fe6060f1SDimitry Andric } 1624fe6060f1SDimitry Andric 1625fe6060f1SDimitry Andric SDValue Insert = CurDAG->getTargetInsertSubreg(SubRegIdx, DL, VT, V, SubV); 1626fe6060f1SDimitry Andric ReplaceNode(Node, Insert.getNode()); 1627fe6060f1SDimitry Andric return; 1628fe6060f1SDimitry Andric } 1629fe6060f1SDimitry Andric case ISD::EXTRACT_SUBVECTOR: { 1630fe6060f1SDimitry Andric SDValue V = Node->getOperand(0); 1631fe6060f1SDimitry Andric auto Idx = Node->getConstantOperandVal(1); 1632fe6060f1SDimitry Andric MVT InVT = V.getSimpleValueType(); 1633fe6060f1SDimitry Andric SDLoc DL(V); 1634fe6060f1SDimitry Andric 1635fe6060f1SDimitry Andric const RISCVTargetLowering &TLI = *Subtarget->getTargetLowering(); 1636fe6060f1SDimitry Andric MVT SubVecContainerVT = VT; 1637fe6060f1SDimitry Andric // Establish the correct scalable-vector types for any fixed-length type. 1638fe6060f1SDimitry Andric if (VT.isFixedLengthVector()) 1639fe6060f1SDimitry Andric SubVecContainerVT = TLI.getContainerForFixedLengthVector(VT); 1640fe6060f1SDimitry Andric if (InVT.isFixedLengthVector()) 1641fe6060f1SDimitry Andric InVT = TLI.getContainerForFixedLengthVector(InVT); 1642fe6060f1SDimitry Andric 1643fe6060f1SDimitry Andric const auto *TRI = Subtarget->getRegisterInfo(); 1644fe6060f1SDimitry Andric unsigned SubRegIdx; 1645fe6060f1SDimitry Andric std::tie(SubRegIdx, Idx) = 1646fe6060f1SDimitry Andric RISCVTargetLowering::decomposeSubvectorInsertExtractToSubRegs( 1647fe6060f1SDimitry Andric InVT, SubVecContainerVT, Idx, TRI); 1648fe6060f1SDimitry Andric 1649fe6060f1SDimitry Andric // If the Idx hasn't been completely eliminated then this is a subvector 1650fe6060f1SDimitry Andric // extract which doesn't naturally align to a vector register. These must 1651fe6060f1SDimitry Andric // be handled using instructions to manipulate the vector registers. 1652fe6060f1SDimitry Andric if (Idx != 0) 1653fe6060f1SDimitry Andric break; 1654fe6060f1SDimitry Andric 1655fe6060f1SDimitry Andric // If we haven't set a SubRegIdx, then we must be going between 1656fe6060f1SDimitry Andric // equally-sized LMUL types (e.g. VR -> VR). This can be done as a copy. 1657fe6060f1SDimitry Andric if (SubRegIdx == RISCV::NoSubRegister) { 1658fe6060f1SDimitry Andric unsigned InRegClassID = RISCVTargetLowering::getRegClassIDForVecVT(InVT); 1659fe6060f1SDimitry Andric assert(RISCVTargetLowering::getRegClassIDForVecVT(SubVecContainerVT) == 1660fe6060f1SDimitry Andric InRegClassID && 1661fe6060f1SDimitry Andric "Unexpected subvector extraction"); 1662fe6060f1SDimitry Andric SDValue RC = CurDAG->getTargetConstant(InRegClassID, DL, XLenVT); 1663fe6060f1SDimitry Andric SDNode *NewNode = 1664fe6060f1SDimitry Andric CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, VT, V, RC); 1665fe6060f1SDimitry Andric ReplaceNode(Node, NewNode); 1666fe6060f1SDimitry Andric return; 1667fe6060f1SDimitry Andric } 1668fe6060f1SDimitry Andric 1669fe6060f1SDimitry Andric SDValue Extract = CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, V); 1670fe6060f1SDimitry Andric ReplaceNode(Node, Extract.getNode()); 1671fe6060f1SDimitry Andric return; 1672fe6060f1SDimitry Andric } 16730eae32dcSDimitry Andric case ISD::SPLAT_VECTOR: 167404eeddc0SDimitry Andric case RISCVISD::VMV_S_X_VL: 167504eeddc0SDimitry Andric case RISCVISD::VFMV_S_F_VL: 1676fe6060f1SDimitry Andric case RISCVISD::VMV_V_X_VL: 1677fe6060f1SDimitry Andric case RISCVISD::VFMV_V_F_VL: { 1678fe6060f1SDimitry Andric // Try to match splat of a scalar load to a strided load with stride of x0. 167904eeddc0SDimitry Andric bool IsScalarMove = Node->getOpcode() == RISCVISD::VMV_S_X_VL || 168004eeddc0SDimitry Andric Node->getOpcode() == RISCVISD::VFMV_S_F_VL; 168181ad6265SDimitry Andric bool HasPassthruOperand = Node->getOpcode() != ISD::SPLAT_VECTOR; 168281ad6265SDimitry Andric if (HasPassthruOperand && !Node->getOperand(0).isUndef()) 168304eeddc0SDimitry Andric break; 168481ad6265SDimitry Andric SDValue Src = HasPassthruOperand ? Node->getOperand(1) : Node->getOperand(0); 1685fe6060f1SDimitry Andric auto *Ld = dyn_cast<LoadSDNode>(Src); 1686fe6060f1SDimitry Andric if (!Ld) 1687fe6060f1SDimitry Andric break; 1688fe6060f1SDimitry Andric EVT MemVT = Ld->getMemoryVT(); 1689fe6060f1SDimitry Andric // The memory VT should be the same size as the element type. 1690fe6060f1SDimitry Andric if (MemVT.getStoreSize() != VT.getVectorElementType().getStoreSize()) 1691fe6060f1SDimitry Andric break; 1692fe6060f1SDimitry Andric if (!IsProfitableToFold(Src, Node, Node) || 1693fe6060f1SDimitry Andric !IsLegalToFold(Src, Node, Node, TM.getOptLevel())) 1694fe6060f1SDimitry Andric break; 1695fe6060f1SDimitry Andric 1696fe6060f1SDimitry Andric SDValue VL; 16970eae32dcSDimitry Andric if (Node->getOpcode() == ISD::SPLAT_VECTOR) 16980eae32dcSDimitry Andric VL = CurDAG->getTargetConstant(RISCV::VLMaxSentinel, DL, XLenVT); 169904eeddc0SDimitry Andric else if (IsScalarMove) { 170004eeddc0SDimitry Andric // We could deal with more VL if we update the VSETVLI insert pass to 170104eeddc0SDimitry Andric // avoid introducing more VSETVLI. 170204eeddc0SDimitry Andric if (!isOneConstant(Node->getOperand(2))) 170304eeddc0SDimitry Andric break; 170404eeddc0SDimitry Andric selectVLOp(Node->getOperand(2), VL); 170504eeddc0SDimitry Andric } else 170681ad6265SDimitry Andric selectVLOp(Node->getOperand(2), VL); 1707fe6060f1SDimitry Andric 1708fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1709fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(Log2SEW, DL, XLenVT); 1710fe6060f1SDimitry Andric 1711fe6060f1SDimitry Andric SDValue Operands[] = {Ld->getBasePtr(), 1712fe6060f1SDimitry Andric CurDAG->getRegister(RISCV::X0, XLenVT), VL, SEW, 1713fe6060f1SDimitry Andric Ld->getChain()}; 1714fe6060f1SDimitry Andric 1715fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1716fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = RISCV::getVLEPseudo( 171704eeddc0SDimitry Andric /*IsMasked*/ false, /*IsTU*/ false, /*IsStrided*/ true, /*FF*/ false, 171804eeddc0SDimitry Andric Log2SEW, static_cast<unsigned>(LMUL)); 1719fe6060f1SDimitry Andric MachineSDNode *Load = 1720fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1721fe6060f1SDimitry Andric 172281ad6265SDimitry Andric CurDAG->setNodeMemRefs(Load, {Ld->getMemOperand()}); 1723fe6060f1SDimitry Andric 1724fe6060f1SDimitry Andric ReplaceNode(Node, Load); 1725e8d8bef9SDimitry Andric return; 1726e8d8bef9SDimitry Andric } 1727e8d8bef9SDimitry Andric } 17280b57cec5SDimitry Andric 17290b57cec5SDimitry Andric // Select the default instruction. 17300b57cec5SDimitry Andric SelectCode(Node); 17310b57cec5SDimitry Andric } 17320b57cec5SDimitry Andric 17330b57cec5SDimitry Andric bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand( 17340b57cec5SDimitry Andric const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { 17350b57cec5SDimitry Andric switch (ConstraintID) { 17360b57cec5SDimitry Andric case InlineAsm::Constraint_m: 17370b57cec5SDimitry Andric // We just support simple memory operands that have a single address 17380b57cec5SDimitry Andric // operand and need no special handling. 17390b57cec5SDimitry Andric OutOps.push_back(Op); 17400b57cec5SDimitry Andric return false; 17410b57cec5SDimitry Andric case InlineAsm::Constraint_A: 17420b57cec5SDimitry Andric OutOps.push_back(Op); 17430b57cec5SDimitry Andric return false; 17440b57cec5SDimitry Andric default: 17450b57cec5SDimitry Andric break; 17460b57cec5SDimitry Andric } 17470b57cec5SDimitry Andric 17480b57cec5SDimitry Andric return true; 17490b57cec5SDimitry Andric } 17500b57cec5SDimitry Andric 175181ad6265SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrFrameIndex(SDValue Addr, SDValue &Base, 175281ad6265SDimitry Andric SDValue &Offset) { 1753fe6060f1SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 17540b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT()); 175581ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), Subtarget->getXLenVT()); 17560b57cec5SDimitry Andric return true; 17570b57cec5SDimitry Andric } 175881ad6265SDimitry Andric 175981ad6265SDimitry Andric return false; 176081ad6265SDimitry Andric } 176181ad6265SDimitry Andric 176281ad6265SDimitry Andric // Select a frame index and an optional immediate offset from an ADD or OR. 176381ad6265SDimitry Andric bool RISCVDAGToDAGISel::SelectFrameAddrRegImm(SDValue Addr, SDValue &Base, 176481ad6265SDimitry Andric SDValue &Offset) { 176581ad6265SDimitry Andric if (SelectAddrFrameIndex(Addr, Base, Offset)) 176681ad6265SDimitry Andric return true; 176781ad6265SDimitry Andric 176881ad6265SDimitry Andric if (!CurDAG->isBaseWithConstantOffset(Addr)) 176981ad6265SDimitry Andric return false; 177081ad6265SDimitry Andric 177181ad6265SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) { 177281ad6265SDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 177381ad6265SDimitry Andric if (isInt<12>(CVal)) { 177481ad6265SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), 177581ad6265SDimitry Andric Subtarget->getXLenVT()); 177681ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(CVal, SDLoc(Addr), 177781ad6265SDimitry Andric Subtarget->getXLenVT()); 177881ad6265SDimitry Andric return true; 177981ad6265SDimitry Andric } 178081ad6265SDimitry Andric } 178181ad6265SDimitry Andric 17820b57cec5SDimitry Andric return false; 17830b57cec5SDimitry Andric } 17840b57cec5SDimitry Andric 1785753f127fSDimitry Andric // Fold constant addresses. 1786753f127fSDimitry Andric static bool selectConstantAddr(SelectionDAG *CurDAG, const SDLoc &DL, 1787753f127fSDimitry Andric const MVT VT, const RISCVSubtarget *Subtarget, 1788753f127fSDimitry Andric SDValue Addr, SDValue &Base, SDValue &Offset) { 1789753f127fSDimitry Andric if (!isa<ConstantSDNode>(Addr)) 1790753f127fSDimitry Andric return false; 1791753f127fSDimitry Andric 1792753f127fSDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr)->getSExtValue(); 1793753f127fSDimitry Andric 1794753f127fSDimitry Andric // If the constant is a simm12, we can fold the whole constant and use X0 as 1795753f127fSDimitry Andric // the base. If the constant can be materialized with LUI+simm12, use LUI as 1796753f127fSDimitry Andric // the base. We can't use generateInstSeq because it favors LUI+ADDIW. 1797753f127fSDimitry Andric int64_t Lo12 = SignExtend64<12>(CVal); 1798753f127fSDimitry Andric int64_t Hi = (uint64_t)CVal - (uint64_t)Lo12; 1799753f127fSDimitry Andric if (!Subtarget->is64Bit() || isInt<32>(Hi)) { 1800753f127fSDimitry Andric if (Hi) { 1801753f127fSDimitry Andric int64_t Hi20 = (Hi >> 12) & 0xfffff; 1802753f127fSDimitry Andric Base = SDValue( 1803753f127fSDimitry Andric CurDAG->getMachineNode(RISCV::LUI, DL, VT, 1804753f127fSDimitry Andric CurDAG->getTargetConstant(Hi20, DL, VT)), 1805753f127fSDimitry Andric 0); 1806753f127fSDimitry Andric } else { 1807753f127fSDimitry Andric Base = CurDAG->getRegister(RISCV::X0, VT); 1808753f127fSDimitry Andric } 1809753f127fSDimitry Andric Offset = CurDAG->getTargetConstant(Lo12, DL, VT); 1810753f127fSDimitry Andric return true; 1811753f127fSDimitry Andric } 1812753f127fSDimitry Andric 1813753f127fSDimitry Andric // Ask how constant materialization would handle this constant. 1814753f127fSDimitry Andric RISCVMatInt::InstSeq Seq = 1815753f127fSDimitry Andric RISCVMatInt::generateInstSeq(CVal, Subtarget->getFeatureBits()); 1816753f127fSDimitry Andric 1817753f127fSDimitry Andric // If the last instruction would be an ADDI, we can fold its immediate and 1818753f127fSDimitry Andric // emit the rest of the sequence as the base. 1819753f127fSDimitry Andric if (Seq.back().Opc != RISCV::ADDI) 1820753f127fSDimitry Andric return false; 1821753f127fSDimitry Andric Lo12 = Seq.back().Imm; 1822753f127fSDimitry Andric 1823753f127fSDimitry Andric // Drop the last instruction. 1824753f127fSDimitry Andric Seq.pop_back(); 1825753f127fSDimitry Andric assert(!Seq.empty() && "Expected more instructions in sequence"); 1826753f127fSDimitry Andric 1827753f127fSDimitry Andric Base = SDValue(selectImmSeq(CurDAG, DL, VT, Seq), 0); 1828753f127fSDimitry Andric Offset = CurDAG->getTargetConstant(Lo12, DL, VT); 1829753f127fSDimitry Andric return true; 1830753f127fSDimitry Andric } 1831753f127fSDimitry Andric 1832753f127fSDimitry Andric // Is this ADD instruction only used as the base pointer of scalar loads and 1833753f127fSDimitry Andric // stores? 1834753f127fSDimitry Andric static bool isWorthFoldingAdd(SDValue Add) { 1835753f127fSDimitry Andric for (auto Use : Add->uses()) { 1836753f127fSDimitry Andric if (Use->getOpcode() != ISD::LOAD && Use->getOpcode() != ISD::STORE && 1837753f127fSDimitry Andric Use->getOpcode() != ISD::ATOMIC_LOAD && 1838753f127fSDimitry Andric Use->getOpcode() != ISD::ATOMIC_STORE) 1839753f127fSDimitry Andric return false; 1840753f127fSDimitry Andric EVT VT = cast<MemSDNode>(Use)->getMemoryVT(); 1841753f127fSDimitry Andric if (!VT.isScalarInteger() && VT != MVT::f16 && VT != MVT::f32 && 1842753f127fSDimitry Andric VT != MVT::f64) 1843753f127fSDimitry Andric return false; 1844753f127fSDimitry Andric // Don't allow stores of the value. It must be used as the address. 1845753f127fSDimitry Andric if (Use->getOpcode() == ISD::STORE && 1846753f127fSDimitry Andric cast<StoreSDNode>(Use)->getValue() == Add) 1847753f127fSDimitry Andric return false; 1848753f127fSDimitry Andric if (Use->getOpcode() == ISD::ATOMIC_STORE && 1849753f127fSDimitry Andric cast<AtomicSDNode>(Use)->getVal() == Add) 1850753f127fSDimitry Andric return false; 1851753f127fSDimitry Andric } 1852753f127fSDimitry Andric 1853fe6060f1SDimitry Andric return true; 1854e8d8bef9SDimitry Andric } 1855e8d8bef9SDimitry Andric 185681ad6265SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrRegImm(SDValue Addr, SDValue &Base, 185781ad6265SDimitry Andric SDValue &Offset) { 185881ad6265SDimitry Andric if (SelectAddrFrameIndex(Addr, Base, Offset)) 185981ad6265SDimitry Andric return true; 186081ad6265SDimitry Andric 186181ad6265SDimitry Andric SDLoc DL(Addr); 186281ad6265SDimitry Andric MVT VT = Addr.getSimpleValueType(); 186381ad6265SDimitry Andric 186481ad6265SDimitry Andric if (Addr.getOpcode() == RISCVISD::ADD_LO) { 186581ad6265SDimitry Andric Base = Addr.getOperand(0); 186681ad6265SDimitry Andric Offset = Addr.getOperand(1); 186781ad6265SDimitry Andric return true; 186881ad6265SDimitry Andric } 186981ad6265SDimitry Andric 187081ad6265SDimitry Andric if (CurDAG->isBaseWithConstantOffset(Addr)) { 187181ad6265SDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 187281ad6265SDimitry Andric if (isInt<12>(CVal)) { 187381ad6265SDimitry Andric Base = Addr.getOperand(0); 187481ad6265SDimitry Andric if (Base.getOpcode() == RISCVISD::ADD_LO) { 187581ad6265SDimitry Andric SDValue LoOperand = Base.getOperand(1); 187681ad6265SDimitry Andric if (auto *GA = dyn_cast<GlobalAddressSDNode>(LoOperand)) { 187781ad6265SDimitry Andric // If the Lo in (ADD_LO hi, lo) is a global variable's address 187881ad6265SDimitry Andric // (its low part, really), then we can rely on the alignment of that 187981ad6265SDimitry Andric // variable to provide a margin of safety before low part can overflow 188081ad6265SDimitry Andric // the 12 bits of the load/store offset. Check if CVal falls within 188181ad6265SDimitry Andric // that margin; if so (low part + CVal) can't overflow. 188281ad6265SDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 188381ad6265SDimitry Andric Align Alignment = commonAlignment( 188481ad6265SDimitry Andric GA->getGlobal()->getPointerAlignment(DL), GA->getOffset()); 188581ad6265SDimitry Andric if (CVal == 0 || Alignment > CVal) { 188681ad6265SDimitry Andric int64_t CombinedOffset = CVal + GA->getOffset(); 188781ad6265SDimitry Andric Base = Base.getOperand(0); 188881ad6265SDimitry Andric Offset = CurDAG->getTargetGlobalAddress( 188981ad6265SDimitry Andric GA->getGlobal(), SDLoc(LoOperand), LoOperand.getValueType(), 189081ad6265SDimitry Andric CombinedOffset, GA->getTargetFlags()); 189181ad6265SDimitry Andric return true; 189281ad6265SDimitry Andric } 189381ad6265SDimitry Andric } 189481ad6265SDimitry Andric } 189581ad6265SDimitry Andric 189681ad6265SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Base)) 189781ad6265SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), VT); 189881ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(CVal, DL, VT); 189981ad6265SDimitry Andric return true; 190081ad6265SDimitry Andric } 190181ad6265SDimitry Andric } 190281ad6265SDimitry Andric 190381ad6265SDimitry Andric // Handle ADD with large immediates. 190481ad6265SDimitry Andric if (Addr.getOpcode() == ISD::ADD && isa<ConstantSDNode>(Addr.getOperand(1))) { 190581ad6265SDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 190681ad6265SDimitry Andric assert(!isInt<12>(CVal) && "simm12 not already handled?"); 190781ad6265SDimitry Andric 1908753f127fSDimitry Andric // Handle immediates in the range [-4096,-2049] or [2048, 4094]. We can use 1909753f127fSDimitry Andric // an ADDI for part of the offset and fold the rest into the load/store. 1910753f127fSDimitry Andric // This mirrors the AddiPair PatFrag in RISCVInstrInfo.td. 191181ad6265SDimitry Andric if (isInt<12>(CVal / 2) && isInt<12>(CVal - CVal / 2)) { 191281ad6265SDimitry Andric int64_t Adj = CVal < 0 ? -2048 : 2047; 191381ad6265SDimitry Andric Base = SDValue( 191481ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::ADDI, DL, VT, Addr.getOperand(0), 191581ad6265SDimitry Andric CurDAG->getTargetConstant(Adj, DL, VT)), 191681ad6265SDimitry Andric 0); 191781ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(CVal - Adj, DL, VT); 191881ad6265SDimitry Andric return true; 191981ad6265SDimitry Andric } 1920753f127fSDimitry Andric 1921753f127fSDimitry Andric // For larger immediates, we might be able to save one instruction from 1922753f127fSDimitry Andric // constant materialization by folding the Lo12 bits of the immediate into 1923753f127fSDimitry Andric // the address. We should only do this if the ADD is only used by loads and 1924753f127fSDimitry Andric // stores that can fold the lo12 bits. Otherwise, the ADD will get iseled 1925753f127fSDimitry Andric // separately with the full materialized immediate creating extra 1926753f127fSDimitry Andric // instructions. 1927753f127fSDimitry Andric if (isWorthFoldingAdd(Addr) && 1928753f127fSDimitry Andric selectConstantAddr(CurDAG, DL, VT, Subtarget, Addr.getOperand(1), Base, 1929753f127fSDimitry Andric Offset)) { 1930753f127fSDimitry Andric // Insert an ADD instruction with the materialized Hi52 bits. 1931753f127fSDimitry Andric Base = SDValue( 1932753f127fSDimitry Andric CurDAG->getMachineNode(RISCV::ADD, DL, VT, Addr.getOperand(0), Base), 1933753f127fSDimitry Andric 0); 1934753f127fSDimitry Andric return true; 193581ad6265SDimitry Andric } 1936753f127fSDimitry Andric } 1937753f127fSDimitry Andric 1938753f127fSDimitry Andric if (selectConstantAddr(CurDAG, DL, VT, Subtarget, Addr, Base, Offset)) 1939753f127fSDimitry Andric return true; 194081ad6265SDimitry Andric 194181ad6265SDimitry Andric Base = Addr; 194281ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(0, DL, VT); 194381ad6265SDimitry Andric return true; 194481ad6265SDimitry Andric } 194581ad6265SDimitry Andric 1946fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth, 1947fe6060f1SDimitry Andric SDValue &ShAmt) { 1948fe6060f1SDimitry Andric // Shift instructions on RISCV only read the lower 5 or 6 bits of the shift 1949fe6060f1SDimitry Andric // amount. If there is an AND on the shift amount, we can bypass it if it 1950fe6060f1SDimitry Andric // doesn't affect any of those bits. 1951fe6060f1SDimitry Andric if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) { 1952fe6060f1SDimitry Andric const APInt &AndMask = N->getConstantOperandAPInt(1); 1953979e22ffSDimitry Andric 1954fe6060f1SDimitry Andric // Since the max shift amount is a power of 2 we can subtract 1 to make a 1955fe6060f1SDimitry Andric // mask that covers the bits needed to represent all shift amounts. 1956fe6060f1SDimitry Andric assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!"); 1957fe6060f1SDimitry Andric APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1); 1958e8d8bef9SDimitry Andric 1959fe6060f1SDimitry Andric if (ShMask.isSubsetOf(AndMask)) { 1960fe6060f1SDimitry Andric ShAmt = N.getOperand(0); 1961fe6060f1SDimitry Andric return true; 1962e8d8bef9SDimitry Andric } 1963e8d8bef9SDimitry Andric 1964fe6060f1SDimitry Andric // SimplifyDemandedBits may have optimized the mask so try restoring any 1965fe6060f1SDimitry Andric // bits that are known zero. 1966fe6060f1SDimitry Andric KnownBits Known = CurDAG->computeKnownBits(N->getOperand(0)); 1967fe6060f1SDimitry Andric if (ShMask.isSubsetOf(AndMask | Known.Zero)) { 1968fe6060f1SDimitry Andric ShAmt = N.getOperand(0); 1969fe6060f1SDimitry Andric return true; 1970fe6060f1SDimitry Andric } 197181ad6265SDimitry Andric } else if (N.getOpcode() == ISD::SUB && 197281ad6265SDimitry Andric isa<ConstantSDNode>(N.getOperand(0))) { 197381ad6265SDimitry Andric uint64_t Imm = N.getConstantOperandVal(0); 197481ad6265SDimitry Andric // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to 197581ad6265SDimitry Andric // generate a NEG instead of a SUB of a constant. 197681ad6265SDimitry Andric if (Imm != 0 && Imm % ShiftWidth == 0) { 197781ad6265SDimitry Andric SDLoc DL(N); 197881ad6265SDimitry Andric EVT VT = N.getValueType(); 197981ad6265SDimitry Andric SDValue Zero = CurDAG->getRegister(RISCV::X0, VT); 198081ad6265SDimitry Andric unsigned NegOpc = VT == MVT::i64 ? RISCV::SUBW : RISCV::SUB; 198181ad6265SDimitry Andric MachineSDNode *Neg = CurDAG->getMachineNode(NegOpc, DL, VT, Zero, 198281ad6265SDimitry Andric N.getOperand(1)); 198381ad6265SDimitry Andric ShAmt = SDValue(Neg, 0); 198481ad6265SDimitry Andric return true; 198581ad6265SDimitry Andric } 1986fe6060f1SDimitry Andric } 1987fe6060f1SDimitry Andric 1988fe6060f1SDimitry Andric ShAmt = N; 1989fe6060f1SDimitry Andric return true; 1990fe6060f1SDimitry Andric } 1991fe6060f1SDimitry Andric 1992fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) { 1993fe6060f1SDimitry Andric if (N.getOpcode() == ISD::SIGN_EXTEND_INREG && 1994fe6060f1SDimitry Andric cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) { 1995fe6060f1SDimitry Andric Val = N.getOperand(0); 1996fe6060f1SDimitry Andric return true; 1997fe6060f1SDimitry Andric } 1998fe6060f1SDimitry Andric MVT VT = N.getSimpleValueType(); 1999fe6060f1SDimitry Andric if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) { 2000fe6060f1SDimitry Andric Val = N; 2001fe6060f1SDimitry Andric return true; 2002fe6060f1SDimitry Andric } 2003fe6060f1SDimitry Andric 2004fe6060f1SDimitry Andric return false; 2005fe6060f1SDimitry Andric } 2006fe6060f1SDimitry Andric 2007fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectZExti32(SDValue N, SDValue &Val) { 2008fe6060f1SDimitry Andric if (N.getOpcode() == ISD::AND) { 2009fe6060f1SDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1)); 2010fe6060f1SDimitry Andric if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) { 2011fe6060f1SDimitry Andric Val = N.getOperand(0); 2012fe6060f1SDimitry Andric return true; 2013fe6060f1SDimitry Andric } 2014fe6060f1SDimitry Andric } 2015fe6060f1SDimitry Andric MVT VT = N.getSimpleValueType(); 2016fe6060f1SDimitry Andric APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), 32); 2017fe6060f1SDimitry Andric if (CurDAG->MaskedValueIsZero(N, Mask)) { 2018fe6060f1SDimitry Andric Val = N; 2019fe6060f1SDimitry Andric return true; 2020fe6060f1SDimitry Andric } 2021fe6060f1SDimitry Andric 2022fe6060f1SDimitry Andric return false; 2023fe6060f1SDimitry Andric } 2024fe6060f1SDimitry Andric 2025753f127fSDimitry Andric /// Look for various patterns that can be done with a SHL that can be folded 2026753f127fSDimitry Andric /// into a SHXADD. \p ShAmt contains 1, 2, or 3 and is set based on which 2027753f127fSDimitry Andric /// SHXADD we are trying to match. 2028753f127fSDimitry Andric bool RISCVDAGToDAGISel::selectSHXADDOp(SDValue N, unsigned ShAmt, 2029753f127fSDimitry Andric SDValue &Val) { 2030753f127fSDimitry Andric if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) { 2031753f127fSDimitry Andric SDValue N0 = N.getOperand(0); 2032753f127fSDimitry Andric 2033753f127fSDimitry Andric bool LeftShift = N0.getOpcode() == ISD::SHL; 2034753f127fSDimitry Andric if ((LeftShift || N0.getOpcode() == ISD::SRL) && 2035753f127fSDimitry Andric isa<ConstantSDNode>(N0.getOperand(1))) { 2036753f127fSDimitry Andric uint64_t Mask = N.getConstantOperandVal(1); 2037753f127fSDimitry Andric unsigned C2 = N0.getConstantOperandVal(1); 2038753f127fSDimitry Andric 2039753f127fSDimitry Andric unsigned XLen = Subtarget->getXLen(); 2040753f127fSDimitry Andric if (LeftShift) 2041753f127fSDimitry Andric Mask &= maskTrailingZeros<uint64_t>(C2); 2042753f127fSDimitry Andric else 2043753f127fSDimitry Andric Mask &= maskTrailingOnes<uint64_t>(XLen - C2); 2044753f127fSDimitry Andric 2045753f127fSDimitry Andric // Look for (and (shl y, c2), c1) where c1 is a shifted mask with no 2046753f127fSDimitry Andric // leading zeros and c3 trailing zeros. We can use an SRLI by c2+c3 2047753f127fSDimitry Andric // followed by a SHXADD with c3 for the X amount. 2048753f127fSDimitry Andric if (isShiftedMask_64(Mask)) { 2049753f127fSDimitry Andric unsigned Leading = XLen - (64 - countLeadingZeros(Mask)); 2050753f127fSDimitry Andric unsigned Trailing = countTrailingZeros(Mask); 2051753f127fSDimitry Andric if (LeftShift && Leading == 0 && C2 < Trailing && Trailing == ShAmt) { 2052753f127fSDimitry Andric SDLoc DL(N); 2053753f127fSDimitry Andric EVT VT = N.getValueType(); 2054753f127fSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 2055753f127fSDimitry Andric RISCV::SRLI, DL, VT, N0.getOperand(0), 2056753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)), 2057753f127fSDimitry Andric 0); 2058753f127fSDimitry Andric return true; 2059753f127fSDimitry Andric } 2060753f127fSDimitry Andric // Look for (and (shr y, c2), c1) where c1 is a shifted mask with c2 2061753f127fSDimitry Andric // leading zeros and c3 trailing zeros. We can use an SRLI by C3 2062753f127fSDimitry Andric // followed by a SHXADD using c3 for the X amount. 2063753f127fSDimitry Andric if (!LeftShift && Leading == C2 && Trailing == ShAmt) { 2064753f127fSDimitry Andric SDLoc DL(N); 2065753f127fSDimitry Andric EVT VT = N.getValueType(); 2066753f127fSDimitry Andric Val = SDValue( 2067753f127fSDimitry Andric CurDAG->getMachineNode( 2068753f127fSDimitry Andric RISCV::SRLI, DL, VT, N0.getOperand(0), 2069753f127fSDimitry Andric CurDAG->getTargetConstant(Leading + Trailing, DL, VT)), 2070753f127fSDimitry Andric 0); 2071753f127fSDimitry Andric return true; 2072753f127fSDimitry Andric } 2073753f127fSDimitry Andric } 2074753f127fSDimitry Andric } 2075753f127fSDimitry Andric } 2076753f127fSDimitry Andric 2077753f127fSDimitry Andric bool LeftShift = N.getOpcode() == ISD::SHL; 2078753f127fSDimitry Andric if ((LeftShift || N.getOpcode() == ISD::SRL) && 2079753f127fSDimitry Andric isa<ConstantSDNode>(N.getOperand(1))) { 2080753f127fSDimitry Andric SDValue N0 = N.getOperand(0); 2081753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && N0.hasOneUse() && 2082753f127fSDimitry Andric isa<ConstantSDNode>(N0.getOperand(1))) { 2083753f127fSDimitry Andric uint64_t Mask = N0.getConstantOperandVal(1); 2084753f127fSDimitry Andric if (isShiftedMask_64(Mask)) { 2085753f127fSDimitry Andric unsigned C1 = N.getConstantOperandVal(1); 2086753f127fSDimitry Andric unsigned XLen = Subtarget->getXLen(); 2087753f127fSDimitry Andric unsigned Leading = XLen - (64 - countLeadingZeros(Mask)); 2088753f127fSDimitry Andric unsigned Trailing = countTrailingZeros(Mask); 2089753f127fSDimitry Andric // Look for (shl (and X, Mask), C1) where Mask has 32 leading zeros and 2090753f127fSDimitry Andric // C3 trailing zeros. If C1+C3==ShAmt we can use SRLIW+SHXADD. 2091753f127fSDimitry Andric if (LeftShift && Leading == 32 && Trailing > 0 && 2092753f127fSDimitry Andric (Trailing + C1) == ShAmt) { 2093753f127fSDimitry Andric SDLoc DL(N); 2094753f127fSDimitry Andric EVT VT = N.getValueType(); 2095753f127fSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 2096753f127fSDimitry Andric RISCV::SRLIW, DL, VT, N0.getOperand(0), 2097753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)), 2098753f127fSDimitry Andric 0); 2099753f127fSDimitry Andric return true; 2100753f127fSDimitry Andric } 2101753f127fSDimitry Andric // Look for (srl (and X, Mask), C1) where Mask has 32 leading zeros and 2102753f127fSDimitry Andric // C3 trailing zeros. If C3-C1==ShAmt we can use SRLIW+SHXADD. 2103753f127fSDimitry Andric if (!LeftShift && Leading == 32 && Trailing > C1 && 2104753f127fSDimitry Andric (Trailing - C1) == ShAmt) { 2105753f127fSDimitry Andric SDLoc DL(N); 2106753f127fSDimitry Andric EVT VT = N.getValueType(); 2107753f127fSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 2108753f127fSDimitry Andric RISCV::SRLIW, DL, VT, N0.getOperand(0), 2109753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)), 2110753f127fSDimitry Andric 0); 2111753f127fSDimitry Andric return true; 2112753f127fSDimitry Andric } 2113753f127fSDimitry Andric } 2114753f127fSDimitry Andric } 2115753f127fSDimitry Andric } 2116753f127fSDimitry Andric 2117753f127fSDimitry Andric return false; 2118753f127fSDimitry Andric } 2119753f127fSDimitry Andric 2120349cc55cSDimitry Andric // Return true if all users of this SDNode* only consume the lower \p Bits. 2121349cc55cSDimitry Andric // This can be used to form W instructions for add/sub/mul/shl even when the 2122349cc55cSDimitry Andric // root isn't a sext_inreg. This can allow the ADDW/SUBW/MULW/SLLIW to CSE if 2123349cc55cSDimitry Andric // SimplifyDemandedBits has made it so some users see a sext_inreg and some 2124349cc55cSDimitry Andric // don't. The sext_inreg+add/sub/mul/shl will get selected, but still leave 2125349cc55cSDimitry Andric // the add/sub/mul/shl to become non-W instructions. By checking the users we 2126349cc55cSDimitry Andric // may be able to use a W instruction and CSE with the other instruction if 2127349cc55cSDimitry Andric // this has happened. We could try to detect that the CSE opportunity exists 2128349cc55cSDimitry Andric // before doing this, but that would be more complicated. 2129349cc55cSDimitry Andric // TODO: Does this need to look through AND/OR/XOR to their users to find more 2130349cc55cSDimitry Andric // opportunities. 2131349cc55cSDimitry Andric bool RISCVDAGToDAGISel::hasAllNBitUsers(SDNode *Node, unsigned Bits) const { 2132349cc55cSDimitry Andric assert((Node->getOpcode() == ISD::ADD || Node->getOpcode() == ISD::SUB || 2133349cc55cSDimitry Andric Node->getOpcode() == ISD::MUL || Node->getOpcode() == ISD::SHL || 2134349cc55cSDimitry Andric Node->getOpcode() == ISD::SRL || 2135349cc55cSDimitry Andric Node->getOpcode() == ISD::SIGN_EXTEND_INREG || 213681ad6265SDimitry Andric Node->getOpcode() == RISCVISD::GREV || 213781ad6265SDimitry Andric Node->getOpcode() == RISCVISD::GORC || 2138349cc55cSDimitry Andric isa<ConstantSDNode>(Node)) && 2139349cc55cSDimitry Andric "Unexpected opcode"); 2140349cc55cSDimitry Andric 2141349cc55cSDimitry Andric for (auto UI = Node->use_begin(), UE = Node->use_end(); UI != UE; ++UI) { 2142349cc55cSDimitry Andric SDNode *User = *UI; 2143349cc55cSDimitry Andric // Users of this node should have already been instruction selected 2144349cc55cSDimitry Andric if (!User->isMachineOpcode()) 2145349cc55cSDimitry Andric return false; 2146349cc55cSDimitry Andric 2147349cc55cSDimitry Andric // TODO: Add more opcodes? 2148349cc55cSDimitry Andric switch (User->getMachineOpcode()) { 2149349cc55cSDimitry Andric default: 2150349cc55cSDimitry Andric return false; 2151349cc55cSDimitry Andric case RISCV::ADDW: 2152349cc55cSDimitry Andric case RISCV::ADDIW: 2153349cc55cSDimitry Andric case RISCV::SUBW: 2154349cc55cSDimitry Andric case RISCV::MULW: 2155349cc55cSDimitry Andric case RISCV::SLLW: 2156349cc55cSDimitry Andric case RISCV::SLLIW: 2157349cc55cSDimitry Andric case RISCV::SRAW: 2158349cc55cSDimitry Andric case RISCV::SRAIW: 2159349cc55cSDimitry Andric case RISCV::SRLW: 2160349cc55cSDimitry Andric case RISCV::SRLIW: 2161349cc55cSDimitry Andric case RISCV::DIVW: 2162349cc55cSDimitry Andric case RISCV::DIVUW: 2163349cc55cSDimitry Andric case RISCV::REMW: 2164349cc55cSDimitry Andric case RISCV::REMUW: 2165349cc55cSDimitry Andric case RISCV::ROLW: 2166349cc55cSDimitry Andric case RISCV::RORW: 2167349cc55cSDimitry Andric case RISCV::RORIW: 2168349cc55cSDimitry Andric case RISCV::CLZW: 2169349cc55cSDimitry Andric case RISCV::CTZW: 2170349cc55cSDimitry Andric case RISCV::CPOPW: 21711fd87a68SDimitry Andric case RISCV::SLLI_UW: 217281ad6265SDimitry Andric case RISCV::FMV_W_X: 2173349cc55cSDimitry Andric case RISCV::FCVT_H_W: 2174349cc55cSDimitry Andric case RISCV::FCVT_H_WU: 2175349cc55cSDimitry Andric case RISCV::FCVT_S_W: 2176349cc55cSDimitry Andric case RISCV::FCVT_S_WU: 2177349cc55cSDimitry Andric case RISCV::FCVT_D_W: 2178349cc55cSDimitry Andric case RISCV::FCVT_D_WU: 2179349cc55cSDimitry Andric if (Bits < 32) 2180349cc55cSDimitry Andric return false; 2181349cc55cSDimitry Andric break; 2182349cc55cSDimitry Andric case RISCV::SLLI: 2183349cc55cSDimitry Andric // SLLI only uses the lower (XLen - ShAmt) bits. 2184349cc55cSDimitry Andric if (Bits < Subtarget->getXLen() - User->getConstantOperandVal(1)) 2185349cc55cSDimitry Andric return false; 2186349cc55cSDimitry Andric break; 218704eeddc0SDimitry Andric case RISCV::ANDI: 218804eeddc0SDimitry Andric if (Bits < (64 - countLeadingZeros(User->getConstantOperandVal(1)))) 218904eeddc0SDimitry Andric return false; 219004eeddc0SDimitry Andric break; 21911fd87a68SDimitry Andric case RISCV::SEXT_B: 219204eeddc0SDimitry Andric if (Bits < 8) 219304eeddc0SDimitry Andric return false; 219404eeddc0SDimitry Andric break; 21951fd87a68SDimitry Andric case RISCV::SEXT_H: 219681ad6265SDimitry Andric case RISCV::FMV_H_X: 21971fd87a68SDimitry Andric case RISCV::ZEXT_H_RV32: 21981fd87a68SDimitry Andric case RISCV::ZEXT_H_RV64: 219904eeddc0SDimitry Andric if (Bits < 16) 220004eeddc0SDimitry Andric return false; 220104eeddc0SDimitry Andric break; 22021fd87a68SDimitry Andric case RISCV::ADD_UW: 22031fd87a68SDimitry Andric case RISCV::SH1ADD_UW: 22041fd87a68SDimitry Andric case RISCV::SH2ADD_UW: 22051fd87a68SDimitry Andric case RISCV::SH3ADD_UW: 2206349cc55cSDimitry Andric // The first operand to add.uw/shXadd.uw is implicitly zero extended from 2207349cc55cSDimitry Andric // 32 bits. 2208349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 32) 2209349cc55cSDimitry Andric return false; 2210349cc55cSDimitry Andric break; 2211349cc55cSDimitry Andric case RISCV::SB: 2212349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 8) 2213349cc55cSDimitry Andric return false; 2214349cc55cSDimitry Andric break; 2215349cc55cSDimitry Andric case RISCV::SH: 2216349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 16) 2217349cc55cSDimitry Andric return false; 2218349cc55cSDimitry Andric break; 2219349cc55cSDimitry Andric case RISCV::SW: 2220349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 32) 2221349cc55cSDimitry Andric return false; 2222349cc55cSDimitry Andric break; 2223349cc55cSDimitry Andric } 2224349cc55cSDimitry Andric } 2225349cc55cSDimitry Andric 2226349cc55cSDimitry Andric return true; 2227349cc55cSDimitry Andric } 2228349cc55cSDimitry Andric 2229fe6060f1SDimitry Andric // Select VL as a 5 bit immediate or a value that will become a register. This 2230fe6060f1SDimitry Andric // allows us to choose betwen VSETIVLI or VSETVLI later. 2231d409305fSDimitry Andric bool RISCVDAGToDAGISel::selectVLOp(SDValue N, SDValue &VL) { 2232d409305fSDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N); 223381ad6265SDimitry Andric if (C && isUInt<5>(C->getZExtValue())) { 2234fe6060f1SDimitry Andric VL = CurDAG->getTargetConstant(C->getZExtValue(), SDLoc(N), 2235fe6060f1SDimitry Andric N->getValueType(0)); 223681ad6265SDimitry Andric } else if (C && C->isAllOnesValue()) { 223781ad6265SDimitry Andric // Treat all ones as VLMax. 223881ad6265SDimitry Andric VL = CurDAG->getTargetConstant(RISCV::VLMaxSentinel, SDLoc(N), 223981ad6265SDimitry Andric N->getValueType(0)); 224081ad6265SDimitry Andric } else if (isa<RegisterSDNode>(N) && 224181ad6265SDimitry Andric cast<RegisterSDNode>(N)->getReg() == RISCV::X0) { 224281ad6265SDimitry Andric // All our VL operands use an operand that allows GPRNoX0 or an immediate 224381ad6265SDimitry Andric // as the register class. Convert X0 to a special immediate to pass the 224481ad6265SDimitry Andric // MachineVerifier. This is recognized specially by the vsetvli insertion 224581ad6265SDimitry Andric // pass. 224681ad6265SDimitry Andric VL = CurDAG->getTargetConstant(RISCV::VLMaxSentinel, SDLoc(N), 224781ad6265SDimitry Andric N->getValueType(0)); 224881ad6265SDimitry Andric } else { 2249d409305fSDimitry Andric VL = N; 225081ad6265SDimitry Andric } 2251d409305fSDimitry Andric 2252d409305fSDimitry Andric return true; 2253d409305fSDimitry Andric } 2254d409305fSDimitry Andric 2255e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::selectVSplat(SDValue N, SDValue &SplatVal) { 225681ad6265SDimitry Andric if (N.getOpcode() != RISCVISD::VMV_V_X_VL || !N.getOperand(0).isUndef()) 2257e8d8bef9SDimitry Andric return false; 225881ad6265SDimitry Andric SplatVal = N.getOperand(1); 2259979e22ffSDimitry Andric return true; 2260979e22ffSDimitry Andric } 2261e8d8bef9SDimitry Andric 2262fe6060f1SDimitry Andric using ValidateFn = bool (*)(int64_t); 2263fe6060f1SDimitry Andric 2264fe6060f1SDimitry Andric static bool selectVSplatSimmHelper(SDValue N, SDValue &SplatVal, 2265fe6060f1SDimitry Andric SelectionDAG &DAG, 2266fe6060f1SDimitry Andric const RISCVSubtarget &Subtarget, 2267fe6060f1SDimitry Andric ValidateFn ValidateImm) { 226881ad6265SDimitry Andric if (N.getOpcode() != RISCVISD::VMV_V_X_VL || !N.getOperand(0).isUndef() || 226981ad6265SDimitry Andric !isa<ConstantSDNode>(N.getOperand(1))) 2270979e22ffSDimitry Andric return false; 2271e8d8bef9SDimitry Andric 227281ad6265SDimitry Andric int64_t SplatImm = 227381ad6265SDimitry Andric cast<ConstantSDNode>(N.getOperand(1))->getSExtValue(); 2274e8d8bef9SDimitry Andric 227581ad6265SDimitry Andric // The semantics of RISCVISD::VMV_V_X_VL is that when the operand 227681ad6265SDimitry Andric // type is wider than the resulting vector element type: an implicit 227781ad6265SDimitry Andric // truncation first takes place. Therefore, perform a manual 227881ad6265SDimitry Andric // truncation/sign-extension in order to ignore any truncated bits and catch 227981ad6265SDimitry Andric // any zero-extended immediate. 2280e8d8bef9SDimitry Andric // For example, we wish to match (i8 -1) -> (XLenVT 255) as a simm5 by first 2281e8d8bef9SDimitry Andric // sign-extending to (XLenVT -1). 2282fe6060f1SDimitry Andric MVT XLenVT = Subtarget.getXLenVT(); 228381ad6265SDimitry Andric assert(XLenVT == N.getOperand(1).getSimpleValueType() && 2284e8d8bef9SDimitry Andric "Unexpected splat operand type"); 2285fe6060f1SDimitry Andric MVT EltVT = N.getSimpleValueType().getVectorElementType(); 2286fe6060f1SDimitry Andric if (EltVT.bitsLT(XLenVT)) 2287e8d8bef9SDimitry Andric SplatImm = SignExtend64(SplatImm, EltVT.getSizeInBits()); 2288979e22ffSDimitry Andric 2289fe6060f1SDimitry Andric if (!ValidateImm(SplatImm)) 2290e8d8bef9SDimitry Andric return false; 2291979e22ffSDimitry Andric 2292fe6060f1SDimitry Andric SplatVal = DAG.getTargetConstant(SplatImm, SDLoc(N), XLenVT); 2293979e22ffSDimitry Andric return true; 2294979e22ffSDimitry Andric } 2295e8d8bef9SDimitry Andric 2296fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5(SDValue N, SDValue &SplatVal) { 2297fe6060f1SDimitry Andric return selectVSplatSimmHelper(N, SplatVal, *CurDAG, *Subtarget, 2298fe6060f1SDimitry Andric [](int64_t Imm) { return isInt<5>(Imm); }); 2299fe6060f1SDimitry Andric } 2300fe6060f1SDimitry Andric 2301fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5Plus1(SDValue N, SDValue &SplatVal) { 2302fe6060f1SDimitry Andric return selectVSplatSimmHelper( 2303fe6060f1SDimitry Andric N, SplatVal, *CurDAG, *Subtarget, 2304fe6060f1SDimitry Andric [](int64_t Imm) { return (isInt<5>(Imm) && Imm != -16) || Imm == 16; }); 2305fe6060f1SDimitry Andric } 2306fe6060f1SDimitry Andric 2307fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5Plus1NonZero(SDValue N, 2308fe6060f1SDimitry Andric SDValue &SplatVal) { 2309fe6060f1SDimitry Andric return selectVSplatSimmHelper( 2310fe6060f1SDimitry Andric N, SplatVal, *CurDAG, *Subtarget, [](int64_t Imm) { 2311fe6060f1SDimitry Andric return Imm != 0 && ((isInt<5>(Imm) && Imm != -16) || Imm == 16); 2312fe6060f1SDimitry Andric }); 2313fe6060f1SDimitry Andric } 2314fe6060f1SDimitry Andric 2315e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatUimm5(SDValue N, SDValue &SplatVal) { 231681ad6265SDimitry Andric if (N.getOpcode() != RISCVISD::VMV_V_X_VL || !N.getOperand(0).isUndef() || 231781ad6265SDimitry Andric !isa<ConstantSDNode>(N.getOperand(1))) 2318979e22ffSDimitry Andric return false; 2319979e22ffSDimitry Andric 232081ad6265SDimitry Andric int64_t SplatImm = 232181ad6265SDimitry Andric cast<ConstantSDNode>(N.getOperand(1))->getSExtValue(); 2322979e22ffSDimitry Andric 2323e8d8bef9SDimitry Andric if (!isUInt<5>(SplatImm)) 2324e8d8bef9SDimitry Andric return false; 2325e8d8bef9SDimitry Andric 2326e8d8bef9SDimitry Andric SplatVal = 2327e8d8bef9SDimitry Andric CurDAG->getTargetConstant(SplatImm, SDLoc(N), Subtarget->getXLenVT()); 2328e8d8bef9SDimitry Andric 2329979e22ffSDimitry Andric return true; 2330979e22ffSDimitry Andric } 2331979e22ffSDimitry Andric 2332fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectRVVSimm5(SDValue N, unsigned Width, 2333fe6060f1SDimitry Andric SDValue &Imm) { 2334fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(N)) { 2335fe6060f1SDimitry Andric int64_t ImmVal = SignExtend64(C->getSExtValue(), Width); 2336fe6060f1SDimitry Andric 2337fe6060f1SDimitry Andric if (!isInt<5>(ImmVal)) 2338fe6060f1SDimitry Andric return false; 2339fe6060f1SDimitry Andric 2340fe6060f1SDimitry Andric Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), Subtarget->getXLenVT()); 2341fe6060f1SDimitry Andric return true; 2342fe6060f1SDimitry Andric } 2343fe6060f1SDimitry Andric 2344fe6060f1SDimitry Andric return false; 2345fe6060f1SDimitry Andric } 2346fe6060f1SDimitry Andric 2347349cc55cSDimitry Andric // Try to remove sext.w if the input is a W instruction or can be made into 2348349cc55cSDimitry Andric // a W instruction cheaply. 2349349cc55cSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeSExtW(SDNode *N) { 2350349cc55cSDimitry Andric // Look for the sext.w pattern, addiw rd, rs1, 0. 2351349cc55cSDimitry Andric if (N->getMachineOpcode() != RISCV::ADDIW || 2352349cc55cSDimitry Andric !isNullConstant(N->getOperand(1))) 2353349cc55cSDimitry Andric return false; 2354349cc55cSDimitry Andric 2355349cc55cSDimitry Andric SDValue N0 = N->getOperand(0); 2356349cc55cSDimitry Andric if (!N0.isMachineOpcode()) 2357349cc55cSDimitry Andric return false; 2358349cc55cSDimitry Andric 2359349cc55cSDimitry Andric switch (N0.getMachineOpcode()) { 2360349cc55cSDimitry Andric default: 2361349cc55cSDimitry Andric break; 2362349cc55cSDimitry Andric case RISCV::ADD: 2363349cc55cSDimitry Andric case RISCV::ADDI: 2364349cc55cSDimitry Andric case RISCV::SUB: 2365349cc55cSDimitry Andric case RISCV::MUL: 2366349cc55cSDimitry Andric case RISCV::SLLI: { 2367349cc55cSDimitry Andric // Convert sext.w+add/sub/mul to their W instructions. This will create 2368349cc55cSDimitry Andric // a new independent instruction. This improves latency. 2369349cc55cSDimitry Andric unsigned Opc; 2370349cc55cSDimitry Andric switch (N0.getMachineOpcode()) { 2371349cc55cSDimitry Andric default: 2372349cc55cSDimitry Andric llvm_unreachable("Unexpected opcode!"); 2373349cc55cSDimitry Andric case RISCV::ADD: Opc = RISCV::ADDW; break; 2374349cc55cSDimitry Andric case RISCV::ADDI: Opc = RISCV::ADDIW; break; 2375349cc55cSDimitry Andric case RISCV::SUB: Opc = RISCV::SUBW; break; 2376349cc55cSDimitry Andric case RISCV::MUL: Opc = RISCV::MULW; break; 2377349cc55cSDimitry Andric case RISCV::SLLI: Opc = RISCV::SLLIW; break; 2378349cc55cSDimitry Andric } 2379349cc55cSDimitry Andric 2380349cc55cSDimitry Andric SDValue N00 = N0.getOperand(0); 2381349cc55cSDimitry Andric SDValue N01 = N0.getOperand(1); 2382349cc55cSDimitry Andric 2383349cc55cSDimitry Andric // Shift amount needs to be uimm5. 2384349cc55cSDimitry Andric if (N0.getMachineOpcode() == RISCV::SLLI && 2385349cc55cSDimitry Andric !isUInt<5>(cast<ConstantSDNode>(N01)->getSExtValue())) 2386349cc55cSDimitry Andric break; 2387349cc55cSDimitry Andric 2388349cc55cSDimitry Andric SDNode *Result = 2389349cc55cSDimitry Andric CurDAG->getMachineNode(Opc, SDLoc(N), N->getValueType(0), 2390349cc55cSDimitry Andric N00, N01); 2391349cc55cSDimitry Andric ReplaceUses(N, Result); 2392349cc55cSDimitry Andric return true; 2393349cc55cSDimitry Andric } 2394349cc55cSDimitry Andric case RISCV::ADDW: 2395349cc55cSDimitry Andric case RISCV::ADDIW: 2396349cc55cSDimitry Andric case RISCV::SUBW: 2397349cc55cSDimitry Andric case RISCV::MULW: 2398349cc55cSDimitry Andric case RISCV::SLLIW: 239981ad6265SDimitry Andric case RISCV::GREVIW: 240081ad6265SDimitry Andric case RISCV::GORCIW: 2401349cc55cSDimitry Andric // Result is already sign extended just remove the sext.w. 2402349cc55cSDimitry Andric // NOTE: We only handle the nodes that are selected with hasAllWUsers. 2403349cc55cSDimitry Andric ReplaceUses(N, N0.getNode()); 2404349cc55cSDimitry Andric return true; 2405349cc55cSDimitry Andric } 2406349cc55cSDimitry Andric 2407349cc55cSDimitry Andric return false; 24080b57cec5SDimitry Andric } 24090b57cec5SDimitry Andric 241081ad6265SDimitry Andric // Optimize masked RVV pseudo instructions with a known all-ones mask to their 241181ad6265SDimitry Andric // corresponding "unmasked" pseudo versions. The mask we're interested in will 241281ad6265SDimitry Andric // take the form of a V0 physical register operand, with a glued 241381ad6265SDimitry Andric // register-setting instruction. 241481ad6265SDimitry Andric bool RISCVDAGToDAGISel::doPeepholeMaskedRVV(SDNode *N) { 241581ad6265SDimitry Andric const RISCV::RISCVMaskedPseudoInfo *I = 241681ad6265SDimitry Andric RISCV::getMaskedPseudoInfo(N->getMachineOpcode()); 241781ad6265SDimitry Andric if (!I) 241881ad6265SDimitry Andric return false; 241981ad6265SDimitry Andric 242081ad6265SDimitry Andric unsigned MaskOpIdx = I->MaskOpIdx; 242181ad6265SDimitry Andric 242281ad6265SDimitry Andric // Check that we're using V0 as a mask register. 242381ad6265SDimitry Andric if (!isa<RegisterSDNode>(N->getOperand(MaskOpIdx)) || 242481ad6265SDimitry Andric cast<RegisterSDNode>(N->getOperand(MaskOpIdx))->getReg() != RISCV::V0) 242581ad6265SDimitry Andric return false; 242681ad6265SDimitry Andric 242781ad6265SDimitry Andric // The glued user defines V0. 242881ad6265SDimitry Andric const auto *Glued = N->getGluedNode(); 242981ad6265SDimitry Andric 243081ad6265SDimitry Andric if (!Glued || Glued->getOpcode() != ISD::CopyToReg) 243181ad6265SDimitry Andric return false; 243281ad6265SDimitry Andric 243381ad6265SDimitry Andric // Check that we're defining V0 as a mask register. 243481ad6265SDimitry Andric if (!isa<RegisterSDNode>(Glued->getOperand(1)) || 243581ad6265SDimitry Andric cast<RegisterSDNode>(Glued->getOperand(1))->getReg() != RISCV::V0) 243681ad6265SDimitry Andric return false; 243781ad6265SDimitry Andric 243881ad6265SDimitry Andric // Check the instruction defining V0; it needs to be a VMSET pseudo. 243981ad6265SDimitry Andric SDValue MaskSetter = Glued->getOperand(2); 244081ad6265SDimitry Andric 244181ad6265SDimitry Andric const auto IsVMSet = [](unsigned Opc) { 244281ad6265SDimitry Andric return Opc == RISCV::PseudoVMSET_M_B1 || Opc == RISCV::PseudoVMSET_M_B16 || 244381ad6265SDimitry Andric Opc == RISCV::PseudoVMSET_M_B2 || Opc == RISCV::PseudoVMSET_M_B32 || 244481ad6265SDimitry Andric Opc == RISCV::PseudoVMSET_M_B4 || Opc == RISCV::PseudoVMSET_M_B64 || 244581ad6265SDimitry Andric Opc == RISCV::PseudoVMSET_M_B8; 244681ad6265SDimitry Andric }; 244781ad6265SDimitry Andric 244881ad6265SDimitry Andric // TODO: Check that the VMSET is the expected bitwidth? The pseudo has 244981ad6265SDimitry Andric // undefined behaviour if it's the wrong bitwidth, so we could choose to 245081ad6265SDimitry Andric // assume that it's all-ones? Same applies to its VL. 245181ad6265SDimitry Andric if (!MaskSetter->isMachineOpcode() || !IsVMSet(MaskSetter.getMachineOpcode())) 245281ad6265SDimitry Andric return false; 245381ad6265SDimitry Andric 245481ad6265SDimitry Andric // Retrieve the tail policy operand index, if any. 245581ad6265SDimitry Andric Optional<unsigned> TailPolicyOpIdx; 245681ad6265SDimitry Andric const RISCVInstrInfo &TII = *Subtarget->getInstrInfo(); 245781ad6265SDimitry Andric const MCInstrDesc &MaskedMCID = TII.get(N->getMachineOpcode()); 245881ad6265SDimitry Andric 245981ad6265SDimitry Andric bool IsTA = true; 246081ad6265SDimitry Andric if (RISCVII::hasVecPolicyOp(MaskedMCID.TSFlags)) { 246181ad6265SDimitry Andric // The last operand of the pseudo is the policy op, but we might have a 246281ad6265SDimitry Andric // Glue operand last. We might also have a chain. 246381ad6265SDimitry Andric TailPolicyOpIdx = N->getNumOperands() - 1; 246481ad6265SDimitry Andric if (N->getOperand(*TailPolicyOpIdx).getValueType() == MVT::Glue) 246581ad6265SDimitry Andric (*TailPolicyOpIdx)--; 246681ad6265SDimitry Andric if (N->getOperand(*TailPolicyOpIdx).getValueType() == MVT::Other) 246781ad6265SDimitry Andric (*TailPolicyOpIdx)--; 246881ad6265SDimitry Andric 246981ad6265SDimitry Andric if (!(N->getConstantOperandVal(*TailPolicyOpIdx) & 247081ad6265SDimitry Andric RISCVII::TAIL_AGNOSTIC)) { 247181ad6265SDimitry Andric // Keep the true-masked instruction when there is no unmasked TU 247281ad6265SDimitry Andric // instruction 247381ad6265SDimitry Andric if (I->UnmaskedTUPseudo == I->MaskedPseudo && !N->getOperand(0).isUndef()) 247481ad6265SDimitry Andric return false; 247581ad6265SDimitry Andric // We can't use TA if the tie-operand is not IMPLICIT_DEF 247681ad6265SDimitry Andric if (!N->getOperand(0).isUndef()) 247781ad6265SDimitry Andric IsTA = false; 247881ad6265SDimitry Andric } 247981ad6265SDimitry Andric } 248081ad6265SDimitry Andric 248181ad6265SDimitry Andric unsigned Opc = IsTA ? I->UnmaskedPseudo : I->UnmaskedTUPseudo; 248281ad6265SDimitry Andric 248381ad6265SDimitry Andric // Check that we're dropping the mask operand and any policy operand 248481ad6265SDimitry Andric // when we transform to this unmasked pseudo. Additionally, if this insturtion 248581ad6265SDimitry Andric // is tail agnostic, the unmasked instruction should not have a merge op. 248681ad6265SDimitry Andric uint64_t TSFlags = TII.get(Opc).TSFlags; 248781ad6265SDimitry Andric assert((IsTA != RISCVII::hasMergeOp(TSFlags)) && 248881ad6265SDimitry Andric RISCVII::hasDummyMaskOp(TSFlags) && 248981ad6265SDimitry Andric !RISCVII::hasVecPolicyOp(TSFlags) && 249081ad6265SDimitry Andric "Unexpected pseudo to transform to"); 249181ad6265SDimitry Andric (void)TSFlags; 249281ad6265SDimitry Andric 249381ad6265SDimitry Andric SmallVector<SDValue, 8> Ops; 249481ad6265SDimitry Andric // Skip the merge operand at index 0 if IsTA 249581ad6265SDimitry Andric for (unsigned I = IsTA, E = N->getNumOperands(); I != E; I++) { 249681ad6265SDimitry Andric // Skip the mask, the policy, and the Glue. 249781ad6265SDimitry Andric SDValue Op = N->getOperand(I); 249881ad6265SDimitry Andric if (I == MaskOpIdx || I == TailPolicyOpIdx || 249981ad6265SDimitry Andric Op.getValueType() == MVT::Glue) 250081ad6265SDimitry Andric continue; 250181ad6265SDimitry Andric Ops.push_back(Op); 250281ad6265SDimitry Andric } 250381ad6265SDimitry Andric 250481ad6265SDimitry Andric // Transitively apply any node glued to our new node. 250581ad6265SDimitry Andric if (auto *TGlued = Glued->getGluedNode()) 250681ad6265SDimitry Andric Ops.push_back(SDValue(TGlued, TGlued->getNumValues() - 1)); 250781ad6265SDimitry Andric 250881ad6265SDimitry Andric SDNode *Result = CurDAG->getMachineNode(Opc, SDLoc(N), N->getVTList(), Ops); 250981ad6265SDimitry Andric ReplaceUses(N, Result); 251081ad6265SDimitry Andric 251181ad6265SDimitry Andric return true; 251281ad6265SDimitry Andric } 251381ad6265SDimitry Andric 25140b57cec5SDimitry Andric // This pass converts a legalized DAG into a RISCV-specific DAG, ready 25150b57cec5SDimitry Andric // for instruction scheduling. 251681ad6265SDimitry Andric FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM, 251781ad6265SDimitry Andric CodeGenOpt::Level OptLevel) { 251881ad6265SDimitry Andric return new RISCVDAGToDAGISel(TM, OptLevel); 25190b57cec5SDimitry Andric } 2520