10b57cec5SDimitry Andric //===-- RISCVISelDAGToDAG.cpp - A dag to dag inst selector for RISCV ------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file defines an instruction selector for the RISCV target. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 135ffd83dbSDimitry Andric #include "RISCVISelDAGToDAG.h" 140b57cec5SDimitry Andric #include "MCTargetDesc/RISCVMCTargetDesc.h" 15e8d8bef9SDimitry Andric #include "MCTargetDesc/RISCVMatInt.h" 16fe6060f1SDimitry Andric #include "RISCVISelLowering.h" 17fe6060f1SDimitry Andric #include "RISCVMachineFunctionInfo.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 19e8d8bef9SDimitry Andric #include "llvm/IR/IntrinsicsRISCV.h" 205ffd83dbSDimitry Andric #include "llvm/Support/Alignment.h" 210b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 22fe6060f1SDimitry Andric #include "llvm/Support/KnownBits.h" 230b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 240b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 255ffd83dbSDimitry Andric 260b57cec5SDimitry Andric using namespace llvm; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric #define DEBUG_TYPE "riscv-isel" 290b57cec5SDimitry Andric 30fe6060f1SDimitry Andric namespace llvm { 31fe6060f1SDimitry Andric namespace RISCV { 32fe6060f1SDimitry Andric #define GET_RISCVVSSEGTable_IMPL 33fe6060f1SDimitry Andric #define GET_RISCVVLSEGTable_IMPL 34fe6060f1SDimitry Andric #define GET_RISCVVLXSEGTable_IMPL 35fe6060f1SDimitry Andric #define GET_RISCVVSXSEGTable_IMPL 36fe6060f1SDimitry Andric #define GET_RISCVVLETable_IMPL 37fe6060f1SDimitry Andric #define GET_RISCVVSETable_IMPL 38fe6060f1SDimitry Andric #define GET_RISCVVLXTable_IMPL 39fe6060f1SDimitry Andric #define GET_RISCVVSXTable_IMPL 40fe6060f1SDimitry Andric #include "RISCVGenSearchableTables.inc" 41fe6060f1SDimitry Andric } // namespace RISCV 42fe6060f1SDimitry Andric } // namespace llvm 43fe6060f1SDimitry Andric 44fe6060f1SDimitry Andric void RISCVDAGToDAGISel::PreprocessISelDAG() { 45fe6060f1SDimitry Andric for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(), 46fe6060f1SDimitry Andric E = CurDAG->allnodes_end(); 47fe6060f1SDimitry Andric I != E;) { 48fe6060f1SDimitry Andric SDNode *N = &*I++; // Preincrement iterator to avoid invalidation issues. 49fe6060f1SDimitry Andric 50fe6060f1SDimitry Andric // Lower SPLAT_VECTOR_SPLIT_I64 to two scalar stores and a stride 0 vector 51fe6060f1SDimitry Andric // load. Done after lowering and combining so that we have a chance to 52fe6060f1SDimitry Andric // optimize this to VMV_V_X_VL when the upper bits aren't needed. 53fe6060f1SDimitry Andric if (N->getOpcode() != RISCVISD::SPLAT_VECTOR_SPLIT_I64_VL) 54fe6060f1SDimitry Andric continue; 55fe6060f1SDimitry Andric 56fe6060f1SDimitry Andric assert(N->getNumOperands() == 3 && "Unexpected number of operands"); 57fe6060f1SDimitry Andric MVT VT = N->getSimpleValueType(0); 58fe6060f1SDimitry Andric SDValue Lo = N->getOperand(0); 59fe6060f1SDimitry Andric SDValue Hi = N->getOperand(1); 60fe6060f1SDimitry Andric SDValue VL = N->getOperand(2); 61fe6060f1SDimitry Andric assert(VT.getVectorElementType() == MVT::i64 && VT.isScalableVector() && 62fe6060f1SDimitry Andric Lo.getValueType() == MVT::i32 && Hi.getValueType() == MVT::i32 && 63fe6060f1SDimitry Andric "Unexpected VTs!"); 64fe6060f1SDimitry Andric MachineFunction &MF = CurDAG->getMachineFunction(); 65fe6060f1SDimitry Andric RISCVMachineFunctionInfo *FuncInfo = MF.getInfo<RISCVMachineFunctionInfo>(); 66fe6060f1SDimitry Andric SDLoc DL(N); 67fe6060f1SDimitry Andric 68fe6060f1SDimitry Andric // We use the same frame index we use for moving two i32s into 64-bit FPR. 69fe6060f1SDimitry Andric // This is an analogous operation. 70fe6060f1SDimitry Andric int FI = FuncInfo->getMoveF64FrameIndex(MF); 71fe6060f1SDimitry Andric MachinePointerInfo MPI = MachinePointerInfo::getFixedStack(MF, FI); 72fe6060f1SDimitry Andric const TargetLowering &TLI = CurDAG->getTargetLoweringInfo(); 73fe6060f1SDimitry Andric SDValue StackSlot = 74fe6060f1SDimitry Andric CurDAG->getFrameIndex(FI, TLI.getPointerTy(CurDAG->getDataLayout())); 75fe6060f1SDimitry Andric 76fe6060f1SDimitry Andric SDValue Chain = CurDAG->getEntryNode(); 77fe6060f1SDimitry Andric Lo = CurDAG->getStore(Chain, DL, Lo, StackSlot, MPI, Align(8)); 78fe6060f1SDimitry Andric 79fe6060f1SDimitry Andric SDValue OffsetSlot = 80fe6060f1SDimitry Andric CurDAG->getMemBasePlusOffset(StackSlot, TypeSize::Fixed(4), DL); 81fe6060f1SDimitry Andric Hi = CurDAG->getStore(Chain, DL, Hi, OffsetSlot, MPI.getWithOffset(4), 82fe6060f1SDimitry Andric Align(8)); 83fe6060f1SDimitry Andric 84fe6060f1SDimitry Andric Chain = CurDAG->getNode(ISD::TokenFactor, DL, MVT::Other, Lo, Hi); 85fe6060f1SDimitry Andric 86fe6060f1SDimitry Andric SDVTList VTs = CurDAG->getVTList({VT, MVT::Other}); 87fe6060f1SDimitry Andric SDValue IntID = 88fe6060f1SDimitry Andric CurDAG->getTargetConstant(Intrinsic::riscv_vlse, DL, MVT::i64); 89fe6060f1SDimitry Andric SDValue Ops[] = {Chain, IntID, StackSlot, 90fe6060f1SDimitry Andric CurDAG->getRegister(RISCV::X0, MVT::i64), VL}; 91fe6060f1SDimitry Andric 92fe6060f1SDimitry Andric SDValue Result = CurDAG->getMemIntrinsicNode( 93fe6060f1SDimitry Andric ISD::INTRINSIC_W_CHAIN, DL, VTs, Ops, MVT::i64, MPI, Align(8), 94fe6060f1SDimitry Andric MachineMemOperand::MOLoad); 95fe6060f1SDimitry Andric 96fe6060f1SDimitry Andric // We're about to replace all uses of the SPLAT_VECTOR_SPLIT_I64 with the 97fe6060f1SDimitry Andric // vlse we created. This will cause general havok on the dag because 98fe6060f1SDimitry Andric // anything below the conversion could be folded into other existing nodes. 99fe6060f1SDimitry Andric // To avoid invalidating 'I', back it up to the convert node. 100fe6060f1SDimitry Andric --I; 101fe6060f1SDimitry Andric CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0), Result); 102fe6060f1SDimitry Andric 103fe6060f1SDimitry Andric // Now that we did that, the node is dead. Increment the iterator to the 104fe6060f1SDimitry Andric // next node to process, then delete N. 105fe6060f1SDimitry Andric ++I; 106fe6060f1SDimitry Andric CurDAG->DeleteNode(N); 107fe6060f1SDimitry Andric } 108fe6060f1SDimitry Andric } 109fe6060f1SDimitry Andric 1100b57cec5SDimitry Andric void RISCVDAGToDAGISel::PostprocessISelDAG() { 111349cc55cSDimitry Andric SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); 112349cc55cSDimitry Andric 113349cc55cSDimitry Andric bool MadeChange = false; 114349cc55cSDimitry Andric while (Position != CurDAG->allnodes_begin()) { 115349cc55cSDimitry Andric SDNode *N = &*--Position; 116349cc55cSDimitry Andric // Skip dead nodes and any non-machine opcodes. 117349cc55cSDimitry Andric if (N->use_empty() || !N->isMachineOpcode()) 118349cc55cSDimitry Andric continue; 119349cc55cSDimitry Andric 120349cc55cSDimitry Andric MadeChange |= doPeepholeSExtW(N); 121349cc55cSDimitry Andric MadeChange |= doPeepholeLoadStoreADDI(N); 122349cc55cSDimitry Andric } 123349cc55cSDimitry Andric 124349cc55cSDimitry Andric if (MadeChange) 125349cc55cSDimitry Andric CurDAG->RemoveDeadNodes(); 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric static SDNode *selectImm(SelectionDAG *CurDAG, const SDLoc &DL, int64_t Imm, 129fe6060f1SDimitry Andric const RISCVSubtarget &Subtarget) { 130fe6060f1SDimitry Andric MVT XLenVT = Subtarget.getXLenVT(); 131fe6060f1SDimitry Andric RISCVMatInt::InstSeq Seq = 132fe6060f1SDimitry Andric RISCVMatInt::generateInstSeq(Imm, Subtarget.getFeatureBits()); 1330b57cec5SDimitry Andric 1348bcb0991SDimitry Andric SDNode *Result = nullptr; 1350b57cec5SDimitry Andric SDValue SrcReg = CurDAG->getRegister(RISCV::X0, XLenVT); 1360b57cec5SDimitry Andric for (RISCVMatInt::Inst &Inst : Seq) { 1370b57cec5SDimitry Andric SDValue SDImm = CurDAG->getTargetConstant(Inst.Imm, DL, XLenVT); 1380b57cec5SDimitry Andric if (Inst.Opc == RISCV::LUI) 1390b57cec5SDimitry Andric Result = CurDAG->getMachineNode(RISCV::LUI, DL, XLenVT, SDImm); 140fe6060f1SDimitry Andric else if (Inst.Opc == RISCV::ADDUW) 141fe6060f1SDimitry Andric Result = CurDAG->getMachineNode(RISCV::ADDUW, DL, XLenVT, SrcReg, 142fe6060f1SDimitry Andric CurDAG->getRegister(RISCV::X0, XLenVT)); 143349cc55cSDimitry Andric else if (Inst.Opc == RISCV::SH1ADD || Inst.Opc == RISCV::SH2ADD || 144349cc55cSDimitry Andric Inst.Opc == RISCV::SH3ADD) 145349cc55cSDimitry Andric Result = CurDAG->getMachineNode(Inst.Opc, DL, XLenVT, SrcReg, SrcReg); 1460b57cec5SDimitry Andric else 1470b57cec5SDimitry Andric Result = CurDAG->getMachineNode(Inst.Opc, DL, XLenVT, SrcReg, SDImm); 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric // Only the first instruction has X0 as its source. 1500b57cec5SDimitry Andric SrcReg = SDValue(Result, 0); 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric return Result; 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric 156e8d8bef9SDimitry Andric static SDValue createTupleImpl(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs, 157e8d8bef9SDimitry Andric unsigned RegClassID, unsigned SubReg0) { 158e8d8bef9SDimitry Andric assert(Regs.size() >= 2 && Regs.size() <= 8); 159e8d8bef9SDimitry Andric 160e8d8bef9SDimitry Andric SDLoc DL(Regs[0]); 161e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Ops; 162e8d8bef9SDimitry Andric 163e8d8bef9SDimitry Andric Ops.push_back(CurDAG.getTargetConstant(RegClassID, DL, MVT::i32)); 164e8d8bef9SDimitry Andric 165e8d8bef9SDimitry Andric for (unsigned I = 0; I < Regs.size(); ++I) { 166e8d8bef9SDimitry Andric Ops.push_back(Regs[I]); 167e8d8bef9SDimitry Andric Ops.push_back(CurDAG.getTargetConstant(SubReg0 + I, DL, MVT::i32)); 168e8d8bef9SDimitry Andric } 169e8d8bef9SDimitry Andric SDNode *N = 170e8d8bef9SDimitry Andric CurDAG.getMachineNode(TargetOpcode::REG_SEQUENCE, DL, MVT::Untyped, Ops); 171e8d8bef9SDimitry Andric return SDValue(N, 0); 172e8d8bef9SDimitry Andric } 173e8d8bef9SDimitry Andric 174e8d8bef9SDimitry Andric static SDValue createM1Tuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs, 175e8d8bef9SDimitry Andric unsigned NF) { 176e8d8bef9SDimitry Andric static const unsigned RegClassIDs[] = { 177e8d8bef9SDimitry Andric RISCV::VRN2M1RegClassID, RISCV::VRN3M1RegClassID, RISCV::VRN4M1RegClassID, 178e8d8bef9SDimitry Andric RISCV::VRN5M1RegClassID, RISCV::VRN6M1RegClassID, RISCV::VRN7M1RegClassID, 179e8d8bef9SDimitry Andric RISCV::VRN8M1RegClassID}; 180e8d8bef9SDimitry Andric 181e8d8bef9SDimitry Andric return createTupleImpl(CurDAG, Regs, RegClassIDs[NF - 2], RISCV::sub_vrm1_0); 182e8d8bef9SDimitry Andric } 183e8d8bef9SDimitry Andric 184e8d8bef9SDimitry Andric static SDValue createM2Tuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs, 185e8d8bef9SDimitry Andric unsigned NF) { 186e8d8bef9SDimitry Andric static const unsigned RegClassIDs[] = {RISCV::VRN2M2RegClassID, 187e8d8bef9SDimitry Andric RISCV::VRN3M2RegClassID, 188e8d8bef9SDimitry Andric RISCV::VRN4M2RegClassID}; 189e8d8bef9SDimitry Andric 190e8d8bef9SDimitry Andric return createTupleImpl(CurDAG, Regs, RegClassIDs[NF - 2], RISCV::sub_vrm2_0); 191e8d8bef9SDimitry Andric } 192e8d8bef9SDimitry Andric 193e8d8bef9SDimitry Andric static SDValue createM4Tuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs, 194e8d8bef9SDimitry Andric unsigned NF) { 195e8d8bef9SDimitry Andric return createTupleImpl(CurDAG, Regs, RISCV::VRN2M4RegClassID, 196e8d8bef9SDimitry Andric RISCV::sub_vrm4_0); 197e8d8bef9SDimitry Andric } 198e8d8bef9SDimitry Andric 199e8d8bef9SDimitry Andric static SDValue createTuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs, 200fe6060f1SDimitry Andric unsigned NF, RISCVII::VLMUL LMUL) { 201e8d8bef9SDimitry Andric switch (LMUL) { 202e8d8bef9SDimitry Andric default: 203e8d8bef9SDimitry Andric llvm_unreachable("Invalid LMUL."); 204fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_F8: 205fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_F4: 206fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_F2: 207fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_1: 208e8d8bef9SDimitry Andric return createM1Tuple(CurDAG, Regs, NF); 209fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_2: 210e8d8bef9SDimitry Andric return createM2Tuple(CurDAG, Regs, NF); 211fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_4: 212e8d8bef9SDimitry Andric return createM4Tuple(CurDAG, Regs, NF); 213e8d8bef9SDimitry Andric } 214e8d8bef9SDimitry Andric } 215e8d8bef9SDimitry Andric 216fe6060f1SDimitry Andric void RISCVDAGToDAGISel::addVectorLoadStoreOperands( 217fe6060f1SDimitry Andric SDNode *Node, unsigned Log2SEW, const SDLoc &DL, unsigned CurOp, 218fe6060f1SDimitry Andric bool IsMasked, bool IsStridedOrIndexed, SmallVectorImpl<SDValue> &Operands, 219349cc55cSDimitry Andric bool IsLoad, MVT *IndexVT) { 220fe6060f1SDimitry Andric SDValue Chain = Node->getOperand(0); 221fe6060f1SDimitry Andric SDValue Glue; 222fe6060f1SDimitry Andric 223fe6060f1SDimitry Andric SDValue Base; 224fe6060f1SDimitry Andric SelectBaseAddr(Node->getOperand(CurOp++), Base); 225fe6060f1SDimitry Andric Operands.push_back(Base); // Base pointer. 226fe6060f1SDimitry Andric 227fe6060f1SDimitry Andric if (IsStridedOrIndexed) { 228fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Index. 229fe6060f1SDimitry Andric if (IndexVT) 230fe6060f1SDimitry Andric *IndexVT = Operands.back()->getSimpleValueType(0); 231fe6060f1SDimitry Andric } 232fe6060f1SDimitry Andric 233fe6060f1SDimitry Andric if (IsMasked) { 234fe6060f1SDimitry Andric // Mask needs to be copied to V0. 235fe6060f1SDimitry Andric SDValue Mask = Node->getOperand(CurOp++); 236fe6060f1SDimitry Andric Chain = CurDAG->getCopyToReg(Chain, DL, RISCV::V0, Mask, SDValue()); 237fe6060f1SDimitry Andric Glue = Chain.getValue(1); 238fe6060f1SDimitry Andric Operands.push_back(CurDAG->getRegister(RISCV::V0, Mask.getValueType())); 239fe6060f1SDimitry Andric } 240fe6060f1SDimitry Andric SDValue VL; 241fe6060f1SDimitry Andric selectVLOp(Node->getOperand(CurOp++), VL); 242fe6060f1SDimitry Andric Operands.push_back(VL); 243fe6060f1SDimitry Andric 244fe6060f1SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 245fe6060f1SDimitry Andric SDValue SEWOp = CurDAG->getTargetConstant(Log2SEW, DL, XLenVT); 246fe6060f1SDimitry Andric Operands.push_back(SEWOp); 247fe6060f1SDimitry Andric 248349cc55cSDimitry Andric // Masked load has the tail policy argument. 249349cc55cSDimitry Andric if (IsMasked && IsLoad) { 250349cc55cSDimitry Andric // Policy must be a constant. 251349cc55cSDimitry Andric uint64_t Policy = Node->getConstantOperandVal(CurOp++); 252349cc55cSDimitry Andric SDValue PolicyOp = CurDAG->getTargetConstant(Policy, DL, XLenVT); 253349cc55cSDimitry Andric Operands.push_back(PolicyOp); 254349cc55cSDimitry Andric } 255349cc55cSDimitry Andric 256fe6060f1SDimitry Andric Operands.push_back(Chain); // Chain. 257fe6060f1SDimitry Andric if (Glue) 258fe6060f1SDimitry Andric Operands.push_back(Glue); 259fe6060f1SDimitry Andric } 260fe6060f1SDimitry Andric 261fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLSEG(SDNode *Node, bool IsMasked, 262e8d8bef9SDimitry Andric bool IsStrided) { 263e8d8bef9SDimitry Andric SDLoc DL(Node); 264e8d8bef9SDimitry Andric unsigned NF = Node->getNumValues() - 1; 265fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 266fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 267fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 268e8d8bef9SDimitry Andric 269fe6060f1SDimitry Andric unsigned CurOp = 2; 270fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 271fe6060f1SDimitry Andric if (IsMasked) { 272fe6060f1SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp, 273fe6060f1SDimitry Andric Node->op_begin() + CurOp + NF); 274e8d8bef9SDimitry Andric SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL); 275e8d8bef9SDimitry Andric Operands.push_back(MaskedOff); 276fe6060f1SDimitry Andric CurOp += NF; 277e8d8bef9SDimitry Andric } 278fe6060f1SDimitry Andric 279fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 280349cc55cSDimitry Andric Operands, /*IsLoad=*/true); 281fe6060f1SDimitry Andric 282fe6060f1SDimitry Andric const RISCV::VLSEGPseudo *P = 283fe6060f1SDimitry Andric RISCV::getVLSEGPseudo(NF, IsMasked, IsStrided, /*FF*/ false, Log2SEW, 284fe6060f1SDimitry Andric static_cast<unsigned>(LMUL)); 285fe6060f1SDimitry Andric MachineSDNode *Load = 286e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands); 287fe6060f1SDimitry Andric 288fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 289fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 290fe6060f1SDimitry Andric 291e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 292fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) { 293fe6060f1SDimitry Andric unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I); 294e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 295fe6060f1SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg)); 296fe6060f1SDimitry Andric } 297e8d8bef9SDimitry Andric 298e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); 299e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 300e8d8bef9SDimitry Andric } 301e8d8bef9SDimitry Andric 302fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLSEGFF(SDNode *Node, bool IsMasked) { 303e8d8bef9SDimitry Andric SDLoc DL(Node); 304fe6060f1SDimitry Andric unsigned NF = Node->getNumValues() - 2; // Do not count VL and Chain. 305fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 306e8d8bef9SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 307fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 308fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 309e8d8bef9SDimitry Andric 310fe6060f1SDimitry Andric unsigned CurOp = 2; 311e8d8bef9SDimitry Andric SmallVector<SDValue, 7> Operands; 312fe6060f1SDimitry Andric if (IsMasked) { 313fe6060f1SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp, 314fe6060f1SDimitry Andric Node->op_begin() + CurOp + NF); 315e8d8bef9SDimitry Andric SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL); 316fe6060f1SDimitry Andric Operands.push_back(MaskedOff); 317fe6060f1SDimitry Andric CurOp += NF; 318fe6060f1SDimitry Andric } 319e8d8bef9SDimitry Andric 320fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 321349cc55cSDimitry Andric /*IsStridedOrIndexed*/ false, Operands, 322349cc55cSDimitry Andric /*IsLoad=*/true); 323fe6060f1SDimitry Andric 324fe6060f1SDimitry Andric const RISCV::VLSEGPseudo *P = 325fe6060f1SDimitry Andric RISCV::getVLSEGPseudo(NF, IsMasked, /*Strided*/ false, /*FF*/ true, 326fe6060f1SDimitry Andric Log2SEW, static_cast<unsigned>(LMUL)); 327fe6060f1SDimitry Andric MachineSDNode *Load = CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, 328fe6060f1SDimitry Andric MVT::Other, MVT::Glue, Operands); 329fe6060f1SDimitry Andric SDNode *ReadVL = CurDAG->getMachineNode(RISCV::PseudoReadVL, DL, XLenVT, 330fe6060f1SDimitry Andric /*Glue*/ SDValue(Load, 2)); 331fe6060f1SDimitry Andric 332fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 333fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 334fe6060f1SDimitry Andric 335e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 336fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) { 337fe6060f1SDimitry Andric unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I); 338e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 339fe6060f1SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg)); 340fe6060f1SDimitry Andric } 341fe6060f1SDimitry Andric 342fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(ReadVL, 0)); // VL 343fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, NF + 1), SDValue(Load, 1)); // Chain 344fe6060f1SDimitry Andric CurDAG->RemoveDeadNode(Node); 345fe6060f1SDimitry Andric } 346fe6060f1SDimitry Andric 347fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLXSEG(SDNode *Node, bool IsMasked, 348fe6060f1SDimitry Andric bool IsOrdered) { 349fe6060f1SDimitry Andric SDLoc DL(Node); 350fe6060f1SDimitry Andric unsigned NF = Node->getNumValues() - 1; 351fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 352fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 353fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 354fe6060f1SDimitry Andric 355fe6060f1SDimitry Andric unsigned CurOp = 2; 356fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 357fe6060f1SDimitry Andric if (IsMasked) { 358fe6060f1SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp, 359fe6060f1SDimitry Andric Node->op_begin() + CurOp + NF); 360fe6060f1SDimitry Andric SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL); 361fe6060f1SDimitry Andric Operands.push_back(MaskedOff); 362fe6060f1SDimitry Andric CurOp += NF; 363fe6060f1SDimitry Andric } 364fe6060f1SDimitry Andric 365fe6060f1SDimitry Andric MVT IndexVT; 366fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 367349cc55cSDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 368349cc55cSDimitry Andric /*IsLoad=*/true, &IndexVT); 369fe6060f1SDimitry Andric 370fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 371fe6060f1SDimitry Andric "Element count mismatch"); 372fe6060f1SDimitry Andric 373fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 374fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 375fe6060f1SDimitry Andric const RISCV::VLXSEGPseudo *P = RISCV::getVLXSEGPseudo( 376fe6060f1SDimitry Andric NF, IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 377fe6060f1SDimitry Andric static_cast<unsigned>(IndexLMUL)); 378fe6060f1SDimitry Andric MachineSDNode *Load = 379fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands); 380fe6060f1SDimitry Andric 381fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 382fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 383fe6060f1SDimitry Andric 384fe6060f1SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 385fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) { 386fe6060f1SDimitry Andric unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I); 387fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, I), 388fe6060f1SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg)); 389fe6060f1SDimitry Andric } 390e8d8bef9SDimitry Andric 391e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); 392e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 393e8d8bef9SDimitry Andric } 394e8d8bef9SDimitry Andric 395fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVSSEG(SDNode *Node, bool IsMasked, 396e8d8bef9SDimitry Andric bool IsStrided) { 397e8d8bef9SDimitry Andric SDLoc DL(Node); 398e8d8bef9SDimitry Andric unsigned NF = Node->getNumOperands() - 4; 399e8d8bef9SDimitry Andric if (IsStrided) 400e8d8bef9SDimitry Andric NF--; 401fe6060f1SDimitry Andric if (IsMasked) 402e8d8bef9SDimitry Andric NF--; 403fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 404fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 405fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 406e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 407e8d8bef9SDimitry Andric SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL); 408fe6060f1SDimitry Andric 409fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 410e8d8bef9SDimitry Andric Operands.push_back(StoreVal); 411fe6060f1SDimitry Andric unsigned CurOp = 2 + NF; 412fe6060f1SDimitry Andric 413fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 414fe6060f1SDimitry Andric Operands); 415fe6060f1SDimitry Andric 416fe6060f1SDimitry Andric const RISCV::VSSEGPseudo *P = RISCV::getVSSEGPseudo( 417fe6060f1SDimitry Andric NF, IsMasked, IsStrided, Log2SEW, static_cast<unsigned>(LMUL)); 418fe6060f1SDimitry Andric MachineSDNode *Store = 419e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands); 420fe6060f1SDimitry Andric 421fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 422fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 423fe6060f1SDimitry Andric 424e8d8bef9SDimitry Andric ReplaceNode(Node, Store); 425e8d8bef9SDimitry Andric } 426e8d8bef9SDimitry Andric 427fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVSXSEG(SDNode *Node, bool IsMasked, 428fe6060f1SDimitry Andric bool IsOrdered) { 429e8d8bef9SDimitry Andric SDLoc DL(Node); 430e8d8bef9SDimitry Andric unsigned NF = Node->getNumOperands() - 5; 431fe6060f1SDimitry Andric if (IsMasked) 432fe6060f1SDimitry Andric --NF; 433fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 434fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 435fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 436e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 437e8d8bef9SDimitry Andric SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL); 438e8d8bef9SDimitry Andric 439fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 440fe6060f1SDimitry Andric Operands.push_back(StoreVal); 441fe6060f1SDimitry Andric unsigned CurOp = 2 + NF; 442fe6060f1SDimitry Andric 443fe6060f1SDimitry Andric MVT IndexVT; 444fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 445349cc55cSDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 446349cc55cSDimitry Andric /*IsLoad=*/false, &IndexVT); 447fe6060f1SDimitry Andric 448fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 449fe6060f1SDimitry Andric "Element count mismatch"); 450fe6060f1SDimitry Andric 451fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 452fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 453fe6060f1SDimitry Andric const RISCV::VSXSEGPseudo *P = RISCV::getVSXSEGPseudo( 454fe6060f1SDimitry Andric NF, IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 455e8d8bef9SDimitry Andric static_cast<unsigned>(IndexLMUL)); 456fe6060f1SDimitry Andric MachineSDNode *Store = 457e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands); 458fe6060f1SDimitry Andric 459fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 460fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 461fe6060f1SDimitry Andric 462e8d8bef9SDimitry Andric ReplaceNode(Node, Store); 463e8d8bef9SDimitry Andric } 464e8d8bef9SDimitry Andric 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric void RISCVDAGToDAGISel::Select(SDNode *Node) { 4670b57cec5SDimitry Andric // If we have a custom node, we have already selected. 4680b57cec5SDimitry Andric if (Node->isMachineOpcode()) { 4690b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n"); 4700b57cec5SDimitry Andric Node->setNodeId(-1); 4710b57cec5SDimitry Andric return; 4720b57cec5SDimitry Andric } 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric // Instruction Selection not handled by the auto-generated tablegen selection 4750b57cec5SDimitry Andric // should be handled here. 4760b57cec5SDimitry Andric unsigned Opcode = Node->getOpcode(); 4770b57cec5SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 4780b57cec5SDimitry Andric SDLoc DL(Node); 479fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 4800b57cec5SDimitry Andric 4810b57cec5SDimitry Andric switch (Opcode) { 4820b57cec5SDimitry Andric case ISD::Constant: { 483fe6060f1SDimitry Andric auto *ConstNode = cast<ConstantSDNode>(Node); 484349cc55cSDimitry Andric if (VT == XLenVT && ConstNode->isZero()) { 485e8d8bef9SDimitry Andric SDValue New = 486e8d8bef9SDimitry Andric CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, RISCV::X0, XLenVT); 4870b57cec5SDimitry Andric ReplaceNode(Node, New.getNode()); 4880b57cec5SDimitry Andric return; 4890b57cec5SDimitry Andric } 490349cc55cSDimitry Andric int64_t Imm = ConstNode->getSExtValue(); 491349cc55cSDimitry Andric // If the upper XLen-16 bits are not used, try to convert this to a simm12 492349cc55cSDimitry Andric // by sign extending bit 15. 493349cc55cSDimitry Andric if (isUInt<16>(Imm) && isInt<12>(SignExtend64(Imm, 16)) && 494349cc55cSDimitry Andric hasAllHUsers(Node)) 495349cc55cSDimitry Andric Imm = SignExtend64(Imm, 16); 496349cc55cSDimitry Andric // If the upper 32-bits are not used try to convert this into a simm32 by 497349cc55cSDimitry Andric // sign extending bit 32. 498349cc55cSDimitry Andric if (!isInt<32>(Imm) && isUInt<32>(Imm) && hasAllWUsers(Node)) 499349cc55cSDimitry Andric Imm = SignExtend64(Imm, 32); 500349cc55cSDimitry Andric 501349cc55cSDimitry Andric ReplaceNode(Node, selectImm(CurDAG, DL, Imm, *Subtarget)); 5020b57cec5SDimitry Andric return; 5030b57cec5SDimitry Andric } 5040b57cec5SDimitry Andric case ISD::FrameIndex: { 5050b57cec5SDimitry Andric SDValue Imm = CurDAG->getTargetConstant(0, DL, XLenVT); 5060b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Node)->getIndex(); 5070b57cec5SDimitry Andric SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); 5080b57cec5SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ADDI, DL, VT, TFI, Imm)); 5090b57cec5SDimitry Andric return; 5100b57cec5SDimitry Andric } 511fe6060f1SDimitry Andric case ISD::SRL: { 512fe6060f1SDimitry Andric // We don't need this transform if zext.h is supported. 513fe6060f1SDimitry Andric if (Subtarget->hasStdExtZbb() || Subtarget->hasStdExtZbp()) 514fe6060f1SDimitry Andric break; 515fe6060f1SDimitry Andric // Optimize (srl (and X, 0xffff), C) -> 516fe6060f1SDimitry Andric // (srli (slli X, (XLen-16), (XLen-16) + C) 517fe6060f1SDimitry Andric // Taking into account that the 0xffff may have had lower bits unset by 518fe6060f1SDimitry Andric // SimplifyDemandedBits. This avoids materializing the 0xffff immediate. 519fe6060f1SDimitry Andric // This pattern occurs when type legalizing i16 right shifts. 520fe6060f1SDimitry Andric // FIXME: This could be extended to other AND masks. 521fe6060f1SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 522fe6060f1SDimitry Andric if (N1C) { 523fe6060f1SDimitry Andric uint64_t ShAmt = N1C->getZExtValue(); 524fe6060f1SDimitry Andric SDValue N0 = Node->getOperand(0); 525fe6060f1SDimitry Andric if (ShAmt < 16 && N0.getOpcode() == ISD::AND && N0.hasOneUse() && 526fe6060f1SDimitry Andric isa<ConstantSDNode>(N0.getOperand(1))) { 527fe6060f1SDimitry Andric uint64_t Mask = N0.getConstantOperandVal(1); 528fe6060f1SDimitry Andric Mask |= maskTrailingOnes<uint64_t>(ShAmt); 529fe6060f1SDimitry Andric if (Mask == 0xffff) { 530fe6060f1SDimitry Andric unsigned LShAmt = Subtarget->getXLen() - 16; 531fe6060f1SDimitry Andric SDNode *SLLI = 532fe6060f1SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0->getOperand(0), 533fe6060f1SDimitry Andric CurDAG->getTargetConstant(LShAmt, DL, VT)); 534fe6060f1SDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 535fe6060f1SDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 536fe6060f1SDimitry Andric CurDAG->getTargetConstant(LShAmt + ShAmt, DL, VT)); 537fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 538fe6060f1SDimitry Andric return; 539fe6060f1SDimitry Andric } 540fe6060f1SDimitry Andric } 541fe6060f1SDimitry Andric } 542fe6060f1SDimitry Andric 543fe6060f1SDimitry Andric break; 544fe6060f1SDimitry Andric } 545fe6060f1SDimitry Andric case ISD::AND: { 546fe6060f1SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 547fe6060f1SDimitry Andric if (!N1C) 548fe6060f1SDimitry Andric break; 549fe6060f1SDimitry Andric 550fe6060f1SDimitry Andric SDValue N0 = Node->getOperand(0); 551fe6060f1SDimitry Andric 552fe6060f1SDimitry Andric bool LeftShift = N0.getOpcode() == ISD::SHL; 553fe6060f1SDimitry Andric if (!LeftShift && N0.getOpcode() != ISD::SRL) 554fe6060f1SDimitry Andric break; 555fe6060f1SDimitry Andric 556fe6060f1SDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N0.getOperand(1)); 557fe6060f1SDimitry Andric if (!C) 558fe6060f1SDimitry Andric break; 559fe6060f1SDimitry Andric uint64_t C2 = C->getZExtValue(); 560fe6060f1SDimitry Andric unsigned XLen = Subtarget->getXLen(); 561fe6060f1SDimitry Andric if (!C2 || C2 >= XLen) 562fe6060f1SDimitry Andric break; 563fe6060f1SDimitry Andric 564fe6060f1SDimitry Andric uint64_t C1 = N1C->getZExtValue(); 565fe6060f1SDimitry Andric 566fe6060f1SDimitry Andric // Keep track of whether this is a andi, zext.h, or zext.w. 567fe6060f1SDimitry Andric bool ZExtOrANDI = isInt<12>(N1C->getSExtValue()); 568fe6060f1SDimitry Andric if (C1 == UINT64_C(0xFFFF) && 569fe6060f1SDimitry Andric (Subtarget->hasStdExtZbb() || Subtarget->hasStdExtZbp())) 570fe6060f1SDimitry Andric ZExtOrANDI = true; 571fe6060f1SDimitry Andric if (C1 == UINT64_C(0xFFFFFFFF) && Subtarget->hasStdExtZba()) 572fe6060f1SDimitry Andric ZExtOrANDI = true; 573fe6060f1SDimitry Andric 574fe6060f1SDimitry Andric // Clear irrelevant bits in the mask. 575fe6060f1SDimitry Andric if (LeftShift) 576fe6060f1SDimitry Andric C1 &= maskTrailingZeros<uint64_t>(C2); 577fe6060f1SDimitry Andric else 578fe6060f1SDimitry Andric C1 &= maskTrailingOnes<uint64_t>(XLen - C2); 579fe6060f1SDimitry Andric 580fe6060f1SDimitry Andric // Some transforms should only be done if the shift has a single use or 581fe6060f1SDimitry Andric // the AND would become (srli (slli X, 32), 32) 582fe6060f1SDimitry Andric bool OneUseOrZExtW = N0.hasOneUse() || C1 == UINT64_C(0xFFFFFFFF); 583fe6060f1SDimitry Andric 584fe6060f1SDimitry Andric SDValue X = N0.getOperand(0); 585fe6060f1SDimitry Andric 586fe6060f1SDimitry Andric // Turn (and (srl x, c2) c1) -> (srli (slli x, c3-c2), c3) if c1 is a mask 587fe6060f1SDimitry Andric // with c3 leading zeros. 588fe6060f1SDimitry Andric if (!LeftShift && isMask_64(C1)) { 589fe6060f1SDimitry Andric uint64_t C3 = XLen - (64 - countLeadingZeros(C1)); 590fe6060f1SDimitry Andric if (C2 < C3) { 591fe6060f1SDimitry Andric // If the number of leading zeros is C2+32 this can be SRLIW. 592fe6060f1SDimitry Andric if (C2 + 32 == C3) { 593fe6060f1SDimitry Andric SDNode *SRLIW = 594fe6060f1SDimitry Andric CurDAG->getMachineNode(RISCV::SRLIW, DL, XLenVT, X, 595fe6060f1SDimitry Andric CurDAG->getTargetConstant(C2, DL, XLenVT)); 596fe6060f1SDimitry Andric ReplaceNode(Node, SRLIW); 597fe6060f1SDimitry Andric return; 598fe6060f1SDimitry Andric } 599fe6060f1SDimitry Andric 600fe6060f1SDimitry Andric // (and (srl (sexti32 Y), c2), c1) -> (srliw (sraiw Y, 31), c3 - 32) if 601fe6060f1SDimitry Andric // c1 is a mask with c3 leading zeros and c2 >= 32 and c3-c2==1. 602fe6060f1SDimitry Andric // 603fe6060f1SDimitry Andric // This pattern occurs when (i32 (srl (sra 31), c3 - 32)) is type 604fe6060f1SDimitry Andric // legalized and goes through DAG combine. 605fe6060f1SDimitry Andric SDValue Y; 606fe6060f1SDimitry Andric if (C2 >= 32 && (C3 - C2) == 1 && N0.hasOneUse() && 607fe6060f1SDimitry Andric selectSExti32(X, Y)) { 608fe6060f1SDimitry Andric SDNode *SRAIW = 609fe6060f1SDimitry Andric CurDAG->getMachineNode(RISCV::SRAIW, DL, XLenVT, Y, 610fe6060f1SDimitry Andric CurDAG->getTargetConstant(31, DL, XLenVT)); 611fe6060f1SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 612fe6060f1SDimitry Andric RISCV::SRLIW, DL, XLenVT, SDValue(SRAIW, 0), 613fe6060f1SDimitry Andric CurDAG->getTargetConstant(C3 - 32, DL, XLenVT)); 614fe6060f1SDimitry Andric ReplaceNode(Node, SRLIW); 615fe6060f1SDimitry Andric return; 616fe6060f1SDimitry Andric } 617fe6060f1SDimitry Andric 618fe6060f1SDimitry Andric // (srli (slli x, c3-c2), c3). 619fe6060f1SDimitry Andric if (OneUseOrZExtW && !ZExtOrANDI) { 620fe6060f1SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 621fe6060f1SDimitry Andric RISCV::SLLI, DL, XLenVT, X, 622fe6060f1SDimitry Andric CurDAG->getTargetConstant(C3 - C2, DL, XLenVT)); 623fe6060f1SDimitry Andric SDNode *SRLI = 624fe6060f1SDimitry Andric CurDAG->getMachineNode(RISCV::SRLI, DL, XLenVT, SDValue(SLLI, 0), 625fe6060f1SDimitry Andric CurDAG->getTargetConstant(C3, DL, XLenVT)); 626fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 627fe6060f1SDimitry Andric return; 628fe6060f1SDimitry Andric } 629fe6060f1SDimitry Andric } 630fe6060f1SDimitry Andric } 631fe6060f1SDimitry Andric 632349cc55cSDimitry Andric // Turn (and (shl x, c2), c1) -> (srli (slli c2+c3), c3) if c1 is a mask 633fe6060f1SDimitry Andric // shifted by c2 bits with c3 leading zeros. 634fe6060f1SDimitry Andric if (LeftShift && isShiftedMask_64(C1)) { 635fe6060f1SDimitry Andric uint64_t C3 = XLen - (64 - countLeadingZeros(C1)); 636fe6060f1SDimitry Andric 637fe6060f1SDimitry Andric if (C2 + C3 < XLen && 638fe6060f1SDimitry Andric C1 == (maskTrailingOnes<uint64_t>(XLen - (C2 + C3)) << C2)) { 639fe6060f1SDimitry Andric // Use slli.uw when possible. 640fe6060f1SDimitry Andric if ((XLen - (C2 + C3)) == 32 && Subtarget->hasStdExtZba()) { 641fe6060f1SDimitry Andric SDNode *SLLIUW = 642fe6060f1SDimitry Andric CurDAG->getMachineNode(RISCV::SLLIUW, DL, XLenVT, X, 643fe6060f1SDimitry Andric CurDAG->getTargetConstant(C2, DL, XLenVT)); 644fe6060f1SDimitry Andric ReplaceNode(Node, SLLIUW); 645fe6060f1SDimitry Andric return; 646fe6060f1SDimitry Andric } 647fe6060f1SDimitry Andric 648fe6060f1SDimitry Andric // (srli (slli c2+c3), c3) 649fe6060f1SDimitry Andric if (OneUseOrZExtW && !ZExtOrANDI) { 650fe6060f1SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 651fe6060f1SDimitry Andric RISCV::SLLI, DL, XLenVT, X, 652fe6060f1SDimitry Andric CurDAG->getTargetConstant(C2 + C3, DL, XLenVT)); 653fe6060f1SDimitry Andric SDNode *SRLI = 654fe6060f1SDimitry Andric CurDAG->getMachineNode(RISCV::SRLI, DL, XLenVT, SDValue(SLLI, 0), 655fe6060f1SDimitry Andric CurDAG->getTargetConstant(C3, DL, XLenVT)); 656fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 657fe6060f1SDimitry Andric return; 658fe6060f1SDimitry Andric } 659fe6060f1SDimitry Andric } 660fe6060f1SDimitry Andric } 661fe6060f1SDimitry Andric 662349cc55cSDimitry Andric // Turn (and (shr x, c2), c1) -> (slli (srli x, c2+c3), c3) if c1 is a 663349cc55cSDimitry Andric // shifted mask with c2 leading zeros and c3 trailing zeros. 664349cc55cSDimitry Andric if (!LeftShift && isShiftedMask_64(C1)) { 665349cc55cSDimitry Andric uint64_t Leading = XLen - (64 - countLeadingZeros(C1)); 666349cc55cSDimitry Andric uint64_t C3 = countTrailingZeros(C1); 667349cc55cSDimitry Andric if (Leading == C2 && C2 + C3 < XLen && OneUseOrZExtW && !ZExtOrANDI) { 668349cc55cSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 669349cc55cSDimitry Andric RISCV::SRLI, DL, XLenVT, X, 670349cc55cSDimitry Andric CurDAG->getTargetConstant(C2 + C3, DL, XLenVT)); 671349cc55cSDimitry Andric SDNode *SLLI = 672349cc55cSDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, XLenVT, SDValue(SRLI, 0), 673349cc55cSDimitry Andric CurDAG->getTargetConstant(C3, DL, XLenVT)); 674349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 675349cc55cSDimitry Andric return; 676349cc55cSDimitry Andric } 677349cc55cSDimitry Andric // If the leading zero count is C2+32, we can use SRLIW instead of SRLI. 678349cc55cSDimitry Andric if (Leading > 32 && (Leading - 32) == C2 && C2 + C3 < 32 && 679349cc55cSDimitry Andric OneUseOrZExtW && !ZExtOrANDI) { 680349cc55cSDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 681349cc55cSDimitry Andric RISCV::SRLIW, DL, XLenVT, X, 682349cc55cSDimitry Andric CurDAG->getTargetConstant(C2 + C3, DL, XLenVT)); 683349cc55cSDimitry Andric SDNode *SLLI = 684349cc55cSDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, XLenVT, SDValue(SRLIW, 0), 685349cc55cSDimitry Andric CurDAG->getTargetConstant(C3, DL, XLenVT)); 686349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 687349cc55cSDimitry Andric return; 688349cc55cSDimitry Andric } 689349cc55cSDimitry Andric } 690349cc55cSDimitry Andric 691349cc55cSDimitry Andric // Turn (and (shl x, c2), c1) -> (slli (srli x, c3-c2), c3) if c1 is a 692349cc55cSDimitry Andric // shifted mask with no leading zeros and c3 trailing zeros. 693349cc55cSDimitry Andric if (LeftShift && isShiftedMask_64(C1)) { 694349cc55cSDimitry Andric uint64_t Leading = XLen - (64 - countLeadingZeros(C1)); 695349cc55cSDimitry Andric uint64_t C3 = countTrailingZeros(C1); 696349cc55cSDimitry Andric if (Leading == 0 && C2 < C3 && OneUseOrZExtW && !ZExtOrANDI) { 697349cc55cSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 698349cc55cSDimitry Andric RISCV::SRLI, DL, XLenVT, X, 699349cc55cSDimitry Andric CurDAG->getTargetConstant(C3 - C2, DL, XLenVT)); 700349cc55cSDimitry Andric SDNode *SLLI = 701349cc55cSDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, XLenVT, SDValue(SRLI, 0), 702349cc55cSDimitry Andric CurDAG->getTargetConstant(C3, DL, XLenVT)); 703349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 704349cc55cSDimitry Andric return; 705349cc55cSDimitry Andric } 706349cc55cSDimitry Andric // If we have (32-C2) leading zeros, we can use SRLIW instead of SRLI. 707349cc55cSDimitry Andric if (C2 < C3 && Leading + C2 == 32 && OneUseOrZExtW && !ZExtOrANDI) { 708349cc55cSDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 709349cc55cSDimitry Andric RISCV::SRLIW, DL, XLenVT, X, 710349cc55cSDimitry Andric CurDAG->getTargetConstant(C3 - C2, DL, XLenVT)); 711349cc55cSDimitry Andric SDNode *SLLI = 712349cc55cSDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, XLenVT, SDValue(SRLIW, 0), 713349cc55cSDimitry Andric CurDAG->getTargetConstant(C3, DL, XLenVT)); 714349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 715349cc55cSDimitry Andric return; 716349cc55cSDimitry Andric } 717349cc55cSDimitry Andric } 718349cc55cSDimitry Andric 719fe6060f1SDimitry Andric break; 720fe6060f1SDimitry Andric } 721*0eae32dcSDimitry Andric case ISD::MUL: { 722*0eae32dcSDimitry Andric // Special case for calculating (mul (and X, C2), C1) where the full product 723*0eae32dcSDimitry Andric // fits in XLen bits. We can shift X left by the number of leading zeros in 724*0eae32dcSDimitry Andric // C2 and shift C1 left by XLen-lzcnt(C2). This will ensure the final 725*0eae32dcSDimitry Andric // product has XLen trailing zeros, putting it in the output of MULHU. This 726*0eae32dcSDimitry Andric // can avoid materializing a constant in a register for C2. 727*0eae32dcSDimitry Andric 728*0eae32dcSDimitry Andric // RHS should be a constant. 729*0eae32dcSDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 730*0eae32dcSDimitry Andric if (!N1C || !N1C->hasOneUse()) 731*0eae32dcSDimitry Andric break; 732*0eae32dcSDimitry Andric 733*0eae32dcSDimitry Andric // LHS should be an AND with constant. 734*0eae32dcSDimitry Andric SDValue N0 = Node->getOperand(0); 735*0eae32dcSDimitry Andric if (N0.getOpcode() != ISD::AND || !isa<ConstantSDNode>(N0.getOperand(1))) 736*0eae32dcSDimitry Andric break; 737*0eae32dcSDimitry Andric 738*0eae32dcSDimitry Andric uint64_t C2 = cast<ConstantSDNode>(N0.getOperand(1))->getZExtValue(); 739*0eae32dcSDimitry Andric 740*0eae32dcSDimitry Andric // Constant should be a mask. 741*0eae32dcSDimitry Andric if (!isMask_64(C2)) 742*0eae32dcSDimitry Andric break; 743*0eae32dcSDimitry Andric 744*0eae32dcSDimitry Andric // This should be the only use of the AND unless we will use 745*0eae32dcSDimitry Andric // (SRLI (SLLI X, 32), 32). We don't use a shift pair for other AND 746*0eae32dcSDimitry Andric // constants. 747*0eae32dcSDimitry Andric if (!N0.hasOneUse() && C2 != UINT64_C(0xFFFFFFFF)) 748*0eae32dcSDimitry Andric break; 749*0eae32dcSDimitry Andric 750*0eae32dcSDimitry Andric // If this can be an ANDI, ZEXT.H or ZEXT.W we don't need to do this 751*0eae32dcSDimitry Andric // optimization. 752*0eae32dcSDimitry Andric if (isInt<12>(C2) || 753*0eae32dcSDimitry Andric (C2 == UINT64_C(0xFFFF) && 754*0eae32dcSDimitry Andric (Subtarget->hasStdExtZbb() || Subtarget->hasStdExtZbp())) || 755*0eae32dcSDimitry Andric (C2 == UINT64_C(0xFFFFFFFF) && Subtarget->hasStdExtZba())) 756*0eae32dcSDimitry Andric break; 757*0eae32dcSDimitry Andric 758*0eae32dcSDimitry Andric // We need to shift left the AND input and C1 by a total of XLen bits. 759*0eae32dcSDimitry Andric 760*0eae32dcSDimitry Andric // How far left do we need to shift the AND input? 761*0eae32dcSDimitry Andric unsigned XLen = Subtarget->getXLen(); 762*0eae32dcSDimitry Andric unsigned LeadingZeros = XLen - (64 - countLeadingZeros(C2)); 763*0eae32dcSDimitry Andric 764*0eae32dcSDimitry Andric // The constant gets shifted by the remaining amount unless that would 765*0eae32dcSDimitry Andric // shift bits out. 766*0eae32dcSDimitry Andric uint64_t C1 = N1C->getZExtValue(); 767*0eae32dcSDimitry Andric unsigned ConstantShift = XLen - LeadingZeros; 768*0eae32dcSDimitry Andric if (ConstantShift > (XLen - (64 - countLeadingZeros(C1)))) 769*0eae32dcSDimitry Andric break; 770*0eae32dcSDimitry Andric 771*0eae32dcSDimitry Andric uint64_t ShiftedC1 = C1 << ConstantShift; 772*0eae32dcSDimitry Andric // If this RV32, we need to sign extend the constant. 773*0eae32dcSDimitry Andric if (XLen == 32) 774*0eae32dcSDimitry Andric ShiftedC1 = SignExtend64(ShiftedC1, 32); 775*0eae32dcSDimitry Andric 776*0eae32dcSDimitry Andric // Create (mulhu (slli X, lzcnt(C2)), C1 << (XLen - lzcnt(C2))). 777*0eae32dcSDimitry Andric SDNode *Imm = selectImm(CurDAG, DL, ShiftedC1, *Subtarget); 778*0eae32dcSDimitry Andric SDNode *SLLI = 779*0eae32dcSDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0.getOperand(0), 780*0eae32dcSDimitry Andric CurDAG->getTargetConstant(LeadingZeros, DL, VT)); 781*0eae32dcSDimitry Andric SDNode *MULHU = CurDAG->getMachineNode(RISCV::MULHU, DL, VT, 782*0eae32dcSDimitry Andric SDValue(SLLI, 0), SDValue(Imm, 0)); 783*0eae32dcSDimitry Andric ReplaceNode(Node, MULHU); 784*0eae32dcSDimitry Andric return; 785*0eae32dcSDimitry Andric } 786fe6060f1SDimitry Andric case ISD::INTRINSIC_WO_CHAIN: { 787fe6060f1SDimitry Andric unsigned IntNo = Node->getConstantOperandVal(0); 788fe6060f1SDimitry Andric switch (IntNo) { 789fe6060f1SDimitry Andric // By default we do not custom select any intrinsic. 790fe6060f1SDimitry Andric default: 791fe6060f1SDimitry Andric break; 792fe6060f1SDimitry Andric case Intrinsic::riscv_vmsgeu: 793fe6060f1SDimitry Andric case Intrinsic::riscv_vmsge: { 794fe6060f1SDimitry Andric SDValue Src1 = Node->getOperand(1); 795fe6060f1SDimitry Andric SDValue Src2 = Node->getOperand(2); 796fe6060f1SDimitry Andric // Only custom select scalar second operand. 797fe6060f1SDimitry Andric if (Src2.getValueType() != XLenVT) 798fe6060f1SDimitry Andric break; 799fe6060f1SDimitry Andric // Small constants are handled with patterns. 800fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Src2)) { 801fe6060f1SDimitry Andric int64_t CVal = C->getSExtValue(); 802fe6060f1SDimitry Andric if (CVal >= -15 && CVal <= 16) 803fe6060f1SDimitry Andric break; 804fe6060f1SDimitry Andric } 805fe6060f1SDimitry Andric bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu; 806fe6060f1SDimitry Andric MVT Src1VT = Src1.getSimpleValueType(); 807fe6060f1SDimitry Andric unsigned VMSLTOpcode, VMNANDOpcode; 808fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(Src1VT)) { 809fe6060f1SDimitry Andric default: 810fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 811fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_F8: 812fe6060f1SDimitry Andric VMSLTOpcode = 813fe6060f1SDimitry Andric IsUnsigned ? RISCV::PseudoVMSLTU_VX_MF8 : RISCV::PseudoVMSLT_VX_MF8; 814fe6060f1SDimitry Andric VMNANDOpcode = RISCV::PseudoVMNAND_MM_MF8; 815fe6060f1SDimitry Andric break; 816fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_F4: 817fe6060f1SDimitry Andric VMSLTOpcode = 818fe6060f1SDimitry Andric IsUnsigned ? RISCV::PseudoVMSLTU_VX_MF4 : RISCV::PseudoVMSLT_VX_MF4; 819fe6060f1SDimitry Andric VMNANDOpcode = RISCV::PseudoVMNAND_MM_MF4; 820fe6060f1SDimitry Andric break; 821fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_F2: 822fe6060f1SDimitry Andric VMSLTOpcode = 823fe6060f1SDimitry Andric IsUnsigned ? RISCV::PseudoVMSLTU_VX_MF2 : RISCV::PseudoVMSLT_VX_MF2; 824fe6060f1SDimitry Andric VMNANDOpcode = RISCV::PseudoVMNAND_MM_MF2; 825fe6060f1SDimitry Andric break; 826fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_1: 827fe6060f1SDimitry Andric VMSLTOpcode = 828fe6060f1SDimitry Andric IsUnsigned ? RISCV::PseudoVMSLTU_VX_M1 : RISCV::PseudoVMSLT_VX_M1; 829fe6060f1SDimitry Andric VMNANDOpcode = RISCV::PseudoVMNAND_MM_M1; 830fe6060f1SDimitry Andric break; 831fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_2: 832fe6060f1SDimitry Andric VMSLTOpcode = 833fe6060f1SDimitry Andric IsUnsigned ? RISCV::PseudoVMSLTU_VX_M2 : RISCV::PseudoVMSLT_VX_M2; 834fe6060f1SDimitry Andric VMNANDOpcode = RISCV::PseudoVMNAND_MM_M2; 835fe6060f1SDimitry Andric break; 836fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_4: 837fe6060f1SDimitry Andric VMSLTOpcode = 838fe6060f1SDimitry Andric IsUnsigned ? RISCV::PseudoVMSLTU_VX_M4 : RISCV::PseudoVMSLT_VX_M4; 839fe6060f1SDimitry Andric VMNANDOpcode = RISCV::PseudoVMNAND_MM_M4; 840fe6060f1SDimitry Andric break; 841fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_8: 842fe6060f1SDimitry Andric VMSLTOpcode = 843fe6060f1SDimitry Andric IsUnsigned ? RISCV::PseudoVMSLTU_VX_M8 : RISCV::PseudoVMSLT_VX_M8; 844fe6060f1SDimitry Andric VMNANDOpcode = RISCV::PseudoVMNAND_MM_M8; 845fe6060f1SDimitry Andric break; 846fe6060f1SDimitry Andric } 847fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant( 848fe6060f1SDimitry Andric Log2_32(Src1VT.getScalarSizeInBits()), DL, XLenVT); 849fe6060f1SDimitry Andric SDValue VL; 850fe6060f1SDimitry Andric selectVLOp(Node->getOperand(3), VL); 851fe6060f1SDimitry Andric 852fe6060f1SDimitry Andric // Expand to 853fe6060f1SDimitry Andric // vmslt{u}.vx vd, va, x; vmnand.mm vd, vd, vd 854fe6060f1SDimitry Andric SDValue Cmp = SDValue( 855fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTOpcode, DL, VT, {Src1, Src2, VL, SEW}), 856fe6060f1SDimitry Andric 0); 857fe6060f1SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMNANDOpcode, DL, VT, 858fe6060f1SDimitry Andric {Cmp, Cmp, VL, SEW})); 859fe6060f1SDimitry Andric return; 860fe6060f1SDimitry Andric } 861fe6060f1SDimitry Andric case Intrinsic::riscv_vmsgeu_mask: 862fe6060f1SDimitry Andric case Intrinsic::riscv_vmsge_mask: { 863fe6060f1SDimitry Andric SDValue Src1 = Node->getOperand(2); 864fe6060f1SDimitry Andric SDValue Src2 = Node->getOperand(3); 865fe6060f1SDimitry Andric // Only custom select scalar second operand. 866fe6060f1SDimitry Andric if (Src2.getValueType() != XLenVT) 867fe6060f1SDimitry Andric break; 868fe6060f1SDimitry Andric // Small constants are handled with patterns. 869fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Src2)) { 870fe6060f1SDimitry Andric int64_t CVal = C->getSExtValue(); 871fe6060f1SDimitry Andric if (CVal >= -15 && CVal <= 16) 872fe6060f1SDimitry Andric break; 873fe6060f1SDimitry Andric } 874fe6060f1SDimitry Andric bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu_mask; 875fe6060f1SDimitry Andric MVT Src1VT = Src1.getSimpleValueType(); 876349cc55cSDimitry Andric unsigned VMSLTOpcode, VMSLTMaskOpcode, VMXOROpcode, VMANDNOpcode; 877fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(Src1VT)) { 878fe6060f1SDimitry Andric default: 879fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 880fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_F8: 881fe6060f1SDimitry Andric VMSLTOpcode = 882fe6060f1SDimitry Andric IsUnsigned ? RISCV::PseudoVMSLTU_VX_MF8 : RISCV::PseudoVMSLT_VX_MF8; 883fe6060f1SDimitry Andric VMSLTMaskOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_MF8_MASK 884fe6060f1SDimitry Andric : RISCV::PseudoVMSLT_VX_MF8_MASK; 885fe6060f1SDimitry Andric break; 886fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_F4: 887fe6060f1SDimitry Andric VMSLTOpcode = 888fe6060f1SDimitry Andric IsUnsigned ? RISCV::PseudoVMSLTU_VX_MF4 : RISCV::PseudoVMSLT_VX_MF4; 889fe6060f1SDimitry Andric VMSLTMaskOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_MF4_MASK 890fe6060f1SDimitry Andric : RISCV::PseudoVMSLT_VX_MF4_MASK; 891fe6060f1SDimitry Andric break; 892fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_F2: 893fe6060f1SDimitry Andric VMSLTOpcode = 894fe6060f1SDimitry Andric IsUnsigned ? RISCV::PseudoVMSLTU_VX_MF2 : RISCV::PseudoVMSLT_VX_MF2; 895fe6060f1SDimitry Andric VMSLTMaskOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_MF2_MASK 896fe6060f1SDimitry Andric : RISCV::PseudoVMSLT_VX_MF2_MASK; 897fe6060f1SDimitry Andric break; 898fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_1: 899fe6060f1SDimitry Andric VMSLTOpcode = 900fe6060f1SDimitry Andric IsUnsigned ? RISCV::PseudoVMSLTU_VX_M1 : RISCV::PseudoVMSLT_VX_M1; 901fe6060f1SDimitry Andric VMSLTMaskOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_M1_MASK 902fe6060f1SDimitry Andric : RISCV::PseudoVMSLT_VX_M1_MASK; 903fe6060f1SDimitry Andric break; 904fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_2: 905fe6060f1SDimitry Andric VMSLTOpcode = 906fe6060f1SDimitry Andric IsUnsigned ? RISCV::PseudoVMSLTU_VX_M2 : RISCV::PseudoVMSLT_VX_M2; 907fe6060f1SDimitry Andric VMSLTMaskOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_M2_MASK 908fe6060f1SDimitry Andric : RISCV::PseudoVMSLT_VX_M2_MASK; 909fe6060f1SDimitry Andric break; 910fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_4: 911fe6060f1SDimitry Andric VMSLTOpcode = 912fe6060f1SDimitry Andric IsUnsigned ? RISCV::PseudoVMSLTU_VX_M4 : RISCV::PseudoVMSLT_VX_M4; 913fe6060f1SDimitry Andric VMSLTMaskOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_M4_MASK 914fe6060f1SDimitry Andric : RISCV::PseudoVMSLT_VX_M4_MASK; 915fe6060f1SDimitry Andric break; 916fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_8: 917fe6060f1SDimitry Andric VMSLTOpcode = 918fe6060f1SDimitry Andric IsUnsigned ? RISCV::PseudoVMSLTU_VX_M8 : RISCV::PseudoVMSLT_VX_M8; 919fe6060f1SDimitry Andric VMSLTMaskOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_M8_MASK 920fe6060f1SDimitry Andric : RISCV::PseudoVMSLT_VX_M8_MASK; 921fe6060f1SDimitry Andric break; 922fe6060f1SDimitry Andric } 923fe6060f1SDimitry Andric // Mask operations use the LMUL from the mask type. 924fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(VT)) { 925fe6060f1SDimitry Andric default: 926fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 927fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_F8: 928fe6060f1SDimitry Andric VMXOROpcode = RISCV::PseudoVMXOR_MM_MF8; 929349cc55cSDimitry Andric VMANDNOpcode = RISCV::PseudoVMANDN_MM_MF8; 930fe6060f1SDimitry Andric break; 931fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_F4: 932fe6060f1SDimitry Andric VMXOROpcode = RISCV::PseudoVMXOR_MM_MF4; 933349cc55cSDimitry Andric VMANDNOpcode = RISCV::PseudoVMANDN_MM_MF4; 934fe6060f1SDimitry Andric break; 935fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_F2: 936fe6060f1SDimitry Andric VMXOROpcode = RISCV::PseudoVMXOR_MM_MF2; 937349cc55cSDimitry Andric VMANDNOpcode = RISCV::PseudoVMANDN_MM_MF2; 938fe6060f1SDimitry Andric break; 939fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_1: 940fe6060f1SDimitry Andric VMXOROpcode = RISCV::PseudoVMXOR_MM_M1; 941349cc55cSDimitry Andric VMANDNOpcode = RISCV::PseudoVMANDN_MM_M1; 942fe6060f1SDimitry Andric break; 943fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_2: 944fe6060f1SDimitry Andric VMXOROpcode = RISCV::PseudoVMXOR_MM_M2; 945349cc55cSDimitry Andric VMANDNOpcode = RISCV::PseudoVMANDN_MM_M2; 946fe6060f1SDimitry Andric break; 947fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_4: 948fe6060f1SDimitry Andric VMXOROpcode = RISCV::PseudoVMXOR_MM_M4; 949349cc55cSDimitry Andric VMANDNOpcode = RISCV::PseudoVMANDN_MM_M4; 950fe6060f1SDimitry Andric break; 951fe6060f1SDimitry Andric case RISCVII::VLMUL::LMUL_8: 952fe6060f1SDimitry Andric VMXOROpcode = RISCV::PseudoVMXOR_MM_M8; 953349cc55cSDimitry Andric VMANDNOpcode = RISCV::PseudoVMANDN_MM_M8; 954fe6060f1SDimitry Andric break; 955fe6060f1SDimitry Andric } 956fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant( 957fe6060f1SDimitry Andric Log2_32(Src1VT.getScalarSizeInBits()), DL, XLenVT); 958fe6060f1SDimitry Andric SDValue MaskSEW = CurDAG->getTargetConstant(0, DL, XLenVT); 959fe6060f1SDimitry Andric SDValue VL; 960fe6060f1SDimitry Andric selectVLOp(Node->getOperand(5), VL); 961fe6060f1SDimitry Andric SDValue MaskedOff = Node->getOperand(1); 962fe6060f1SDimitry Andric SDValue Mask = Node->getOperand(4); 963fe6060f1SDimitry Andric // If the MaskedOff value and the Mask are the same value use 964349cc55cSDimitry Andric // vmslt{u}.vx vt, va, x; vmandn.mm vd, vd, vt 965fe6060f1SDimitry Andric // This avoids needing to copy v0 to vd before starting the next sequence. 966fe6060f1SDimitry Andric if (Mask == MaskedOff) { 967fe6060f1SDimitry Andric SDValue Cmp = SDValue( 968fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTOpcode, DL, VT, {Src1, Src2, VL, SEW}), 969fe6060f1SDimitry Andric 0); 970349cc55cSDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMANDNOpcode, DL, VT, 971fe6060f1SDimitry Andric {Mask, Cmp, VL, MaskSEW})); 972fe6060f1SDimitry Andric return; 973fe6060f1SDimitry Andric } 974fe6060f1SDimitry Andric 975fe6060f1SDimitry Andric // Mask needs to be copied to V0. 976fe6060f1SDimitry Andric SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, 977fe6060f1SDimitry Andric RISCV::V0, Mask, SDValue()); 978fe6060f1SDimitry Andric SDValue Glue = Chain.getValue(1); 979fe6060f1SDimitry Andric SDValue V0 = CurDAG->getRegister(RISCV::V0, VT); 980fe6060f1SDimitry Andric 981fe6060f1SDimitry Andric // Otherwise use 982fe6060f1SDimitry Andric // vmslt{u}.vx vd, va, x, v0.t; vmxor.mm vd, vd, v0 983fe6060f1SDimitry Andric SDValue Cmp = SDValue( 984fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTMaskOpcode, DL, VT, 985fe6060f1SDimitry Andric {MaskedOff, Src1, Src2, V0, VL, SEW, Glue}), 986fe6060f1SDimitry Andric 0); 987fe6060f1SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMXOROpcode, DL, VT, 988fe6060f1SDimitry Andric {Cmp, Mask, VL, MaskSEW})); 989fe6060f1SDimitry Andric return; 990fe6060f1SDimitry Andric } 991fe6060f1SDimitry Andric } 992fe6060f1SDimitry Andric break; 993fe6060f1SDimitry Andric } 994e8d8bef9SDimitry Andric case ISD::INTRINSIC_W_CHAIN: { 995e8d8bef9SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 996e8d8bef9SDimitry Andric switch (IntNo) { 997e8d8bef9SDimitry Andric // By default we do not custom select any intrinsic. 998e8d8bef9SDimitry Andric default: 9990b57cec5SDimitry Andric break; 10000b57cec5SDimitry Andric 1001fe6060f1SDimitry Andric case Intrinsic::riscv_vsetvli: 1002fe6060f1SDimitry Andric case Intrinsic::riscv_vsetvlimax: { 1003349cc55cSDimitry Andric if (!Subtarget->hasVInstructions()) 1004e8d8bef9SDimitry Andric break; 1005e8d8bef9SDimitry Andric 1006fe6060f1SDimitry Andric bool VLMax = IntNo == Intrinsic::riscv_vsetvlimax; 1007fe6060f1SDimitry Andric unsigned Offset = VLMax ? 2 : 3; 1008e8d8bef9SDimitry Andric 1009fe6060f1SDimitry Andric assert(Node->getNumOperands() == Offset + 2 && 1010fe6060f1SDimitry Andric "Unexpected number of operands"); 1011fe6060f1SDimitry Andric 1012fe6060f1SDimitry Andric unsigned SEW = 1013fe6060f1SDimitry Andric RISCVVType::decodeVSEW(Node->getConstantOperandVal(Offset) & 0x7); 1014fe6060f1SDimitry Andric RISCVII::VLMUL VLMul = static_cast<RISCVII::VLMUL>( 1015fe6060f1SDimitry Andric Node->getConstantOperandVal(Offset + 1) & 0x7); 1016e8d8bef9SDimitry Andric 1017e8d8bef9SDimitry Andric unsigned VTypeI = RISCVVType::encodeVTYPE( 1018fe6060f1SDimitry Andric VLMul, SEW, /*TailAgnostic*/ true, /*MaskAgnostic*/ false); 1019e8d8bef9SDimitry Andric SDValue VTypeIOp = CurDAG->getTargetConstant(VTypeI, DL, XLenVT); 1020e8d8bef9SDimitry Andric 1021fe6060f1SDimitry Andric SDValue VLOperand; 1022349cc55cSDimitry Andric unsigned Opcode = RISCV::PseudoVSETVLI; 1023fe6060f1SDimitry Andric if (VLMax) { 1024fe6060f1SDimitry Andric VLOperand = CurDAG->getRegister(RISCV::X0, XLenVT); 1025349cc55cSDimitry Andric Opcode = RISCV::PseudoVSETVLIX0; 1026fe6060f1SDimitry Andric } else { 1027fe6060f1SDimitry Andric VLOperand = Node->getOperand(2); 1028fe6060f1SDimitry Andric 1029e8d8bef9SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(VLOperand)) { 1030d409305fSDimitry Andric uint64_t AVL = C->getZExtValue(); 1031d409305fSDimitry Andric if (isUInt<5>(AVL)) { 1032d409305fSDimitry Andric SDValue VLImm = CurDAG->getTargetConstant(AVL, DL, XLenVT); 1033fe6060f1SDimitry Andric ReplaceNode( 1034fe6060f1SDimitry Andric Node, CurDAG->getMachineNode(RISCV::PseudoVSETIVLI, DL, XLenVT, 1035d409305fSDimitry Andric MVT::Other, VLImm, VTypeIOp, 1036d409305fSDimitry Andric /* Chain */ Node->getOperand(0))); 1037d409305fSDimitry Andric return; 1038e8d8bef9SDimitry Andric } 1039e8d8bef9SDimitry Andric } 1040e8d8bef9SDimitry Andric } 1041e8d8bef9SDimitry Andric 1042e8d8bef9SDimitry Andric ReplaceNode(Node, 1043349cc55cSDimitry Andric CurDAG->getMachineNode(Opcode, DL, XLenVT, 1044e8d8bef9SDimitry Andric MVT::Other, VLOperand, VTypeIOp, 1045e8d8bef9SDimitry Andric /* Chain */ Node->getOperand(0))); 1046e8d8bef9SDimitry Andric return; 1047e8d8bef9SDimitry Andric } 1048e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg2: 1049e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg3: 1050e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg4: 1051e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg5: 1052e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg6: 1053e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg7: 1054e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg8: { 1055fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ false, /*IsStrided*/ false); 1056e8d8bef9SDimitry Andric return; 1057e8d8bef9SDimitry Andric } 1058e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg2_mask: 1059e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg3_mask: 1060e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg4_mask: 1061e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg5_mask: 1062e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg6_mask: 1063e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg7_mask: 1064e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg8_mask: { 1065fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ true, /*IsStrided*/ false); 1066e8d8bef9SDimitry Andric return; 1067e8d8bef9SDimitry Andric } 1068e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg2: 1069e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg3: 1070e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg4: 1071e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg5: 1072e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg6: 1073e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg7: 1074e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg8: { 1075fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ false, /*IsStrided*/ true); 1076e8d8bef9SDimitry Andric return; 1077e8d8bef9SDimitry Andric } 1078e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg2_mask: 1079e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg3_mask: 1080e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg4_mask: 1081e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg5_mask: 1082e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg6_mask: 1083e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg7_mask: 1084e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg8_mask: { 1085fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ true, /*IsStrided*/ true); 1086e8d8bef9SDimitry Andric return; 1087e8d8bef9SDimitry Andric } 1088e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg2: 1089e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg3: 1090e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg4: 1091e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg5: 1092e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg6: 1093e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg7: 1094e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg8: 1095fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ true); 1096fe6060f1SDimitry Andric return; 1097e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg2: 1098e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg3: 1099e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg4: 1100e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg5: 1101e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg6: 1102e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg7: 1103fe6060f1SDimitry Andric case Intrinsic::riscv_vluxseg8: 1104fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ false); 1105e8d8bef9SDimitry Andric return; 1106e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg2_mask: 1107e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg3_mask: 1108e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg4_mask: 1109e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg5_mask: 1110e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg6_mask: 1111e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg7_mask: 1112e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg8_mask: 1113fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ true); 1114fe6060f1SDimitry Andric return; 1115e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg2_mask: 1116e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg3_mask: 1117e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg4_mask: 1118e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg5_mask: 1119e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg6_mask: 1120e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg7_mask: 1121fe6060f1SDimitry Andric case Intrinsic::riscv_vluxseg8_mask: 1122fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ false); 1123fe6060f1SDimitry Andric return; 1124fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg8ff: 1125fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg7ff: 1126fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg6ff: 1127fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg5ff: 1128fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg4ff: 1129fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg3ff: 1130fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg2ff: { 1131fe6060f1SDimitry Andric selectVLSEGFF(Node, /*IsMasked*/ false); 1132fe6060f1SDimitry Andric return; 1133fe6060f1SDimitry Andric } 1134fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg8ff_mask: 1135fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg7ff_mask: 1136fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg6ff_mask: 1137fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg5ff_mask: 1138fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg4ff_mask: 1139fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg3ff_mask: 1140fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg2ff_mask: { 1141fe6060f1SDimitry Andric selectVLSEGFF(Node, /*IsMasked*/ true); 1142fe6060f1SDimitry Andric return; 1143fe6060f1SDimitry Andric } 1144fe6060f1SDimitry Andric case Intrinsic::riscv_vloxei: 1145fe6060f1SDimitry Andric case Intrinsic::riscv_vloxei_mask: 1146fe6060f1SDimitry Andric case Intrinsic::riscv_vluxei: 1147fe6060f1SDimitry Andric case Intrinsic::riscv_vluxei_mask: { 1148fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vloxei_mask || 1149fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vluxei_mask; 1150fe6060f1SDimitry Andric bool IsOrdered = IntNo == Intrinsic::riscv_vloxei || 1151fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vloxei_mask; 1152fe6060f1SDimitry Andric 1153fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1154fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1155fe6060f1SDimitry Andric 1156fe6060f1SDimitry Andric unsigned CurOp = 2; 1157fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 1158fe6060f1SDimitry Andric if (IsMasked) 1159fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 1160fe6060f1SDimitry Andric 1161fe6060f1SDimitry Andric MVT IndexVT; 1162fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1163fe6060f1SDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 1164349cc55cSDimitry Andric /*IsLoad=*/true, &IndexVT); 1165fe6060f1SDimitry Andric 1166fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 1167fe6060f1SDimitry Andric "Element count mismatch"); 1168fe6060f1SDimitry Andric 1169fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1170fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 1171fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 1172fe6060f1SDimitry Andric const RISCV::VLX_VSXPseudo *P = RISCV::getVLXPseudo( 1173fe6060f1SDimitry Andric IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 1174fe6060f1SDimitry Andric static_cast<unsigned>(IndexLMUL)); 1175fe6060f1SDimitry Andric MachineSDNode *Load = 1176fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1177fe6060f1SDimitry Andric 1178fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1179fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1180fe6060f1SDimitry Andric 1181fe6060f1SDimitry Andric ReplaceNode(Node, Load); 1182fe6060f1SDimitry Andric return; 1183fe6060f1SDimitry Andric } 1184349cc55cSDimitry Andric case Intrinsic::riscv_vlm: 1185fe6060f1SDimitry Andric case Intrinsic::riscv_vle: 1186fe6060f1SDimitry Andric case Intrinsic::riscv_vle_mask: 1187fe6060f1SDimitry Andric case Intrinsic::riscv_vlse: 1188fe6060f1SDimitry Andric case Intrinsic::riscv_vlse_mask: { 1189fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vle_mask || 1190fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vlse_mask; 1191fe6060f1SDimitry Andric bool IsStrided = 1192fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vlse || IntNo == Intrinsic::riscv_vlse_mask; 1193fe6060f1SDimitry Andric 1194fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1195fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1196fe6060f1SDimitry Andric 1197fe6060f1SDimitry Andric unsigned CurOp = 2; 1198fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 1199fe6060f1SDimitry Andric if (IsMasked) 1200fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 1201fe6060f1SDimitry Andric 1202fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 1203349cc55cSDimitry Andric Operands, /*IsLoad=*/true); 1204fe6060f1SDimitry Andric 1205fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1206fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = 1207fe6060f1SDimitry Andric RISCV::getVLEPseudo(IsMasked, IsStrided, /*FF*/ false, Log2SEW, 1208fe6060f1SDimitry Andric static_cast<unsigned>(LMUL)); 1209fe6060f1SDimitry Andric MachineSDNode *Load = 1210fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1211fe6060f1SDimitry Andric 1212fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1213fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1214fe6060f1SDimitry Andric 1215fe6060f1SDimitry Andric ReplaceNode(Node, Load); 1216fe6060f1SDimitry Andric return; 1217fe6060f1SDimitry Andric } 1218fe6060f1SDimitry Andric case Intrinsic::riscv_vleff: 1219fe6060f1SDimitry Andric case Intrinsic::riscv_vleff_mask: { 1220fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vleff_mask; 1221fe6060f1SDimitry Andric 1222fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1223fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1224fe6060f1SDimitry Andric 1225fe6060f1SDimitry Andric unsigned CurOp = 2; 1226fe6060f1SDimitry Andric SmallVector<SDValue, 7> Operands; 1227fe6060f1SDimitry Andric if (IsMasked) 1228fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 1229fe6060f1SDimitry Andric 1230fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1231349cc55cSDimitry Andric /*IsStridedOrIndexed*/ false, Operands, 1232349cc55cSDimitry Andric /*IsLoad=*/true); 1233fe6060f1SDimitry Andric 1234fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1235fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = 1236fe6060f1SDimitry Andric RISCV::getVLEPseudo(IsMasked, /*Strided*/ false, /*FF*/ true, Log2SEW, 1237fe6060f1SDimitry Andric static_cast<unsigned>(LMUL)); 1238fe6060f1SDimitry Andric MachineSDNode *Load = 1239fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), 1240fe6060f1SDimitry Andric MVT::Other, MVT::Glue, Operands); 1241fe6060f1SDimitry Andric SDNode *ReadVL = CurDAG->getMachineNode(RISCV::PseudoReadVL, DL, XLenVT, 1242fe6060f1SDimitry Andric /*Glue*/ SDValue(Load, 2)); 1243fe6060f1SDimitry Andric 1244fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1245fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1246fe6060f1SDimitry Andric 1247fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, 0), SDValue(Load, 0)); 1248fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, 1), SDValue(ReadVL, 0)); // VL 1249fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, 2), SDValue(Load, 1)); // Chain 1250fe6060f1SDimitry Andric CurDAG->RemoveDeadNode(Node); 12510b57cec5SDimitry Andric return; 12520b57cec5SDimitry Andric } 12530b57cec5SDimitry Andric } 12540b57cec5SDimitry Andric break; 12550b57cec5SDimitry Andric } 1256e8d8bef9SDimitry Andric case ISD::INTRINSIC_VOID: { 1257e8d8bef9SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 1258e8d8bef9SDimitry Andric switch (IntNo) { 1259e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg2: 1260e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg3: 1261e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg4: 1262e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg5: 1263e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg6: 1264e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg7: 1265e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg8: { 1266fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ false, /*IsStrided*/ false); 12670b57cec5SDimitry Andric return; 12680b57cec5SDimitry Andric } 1269e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg2_mask: 1270e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg3_mask: 1271e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg4_mask: 1272e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg5_mask: 1273e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg6_mask: 1274e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg7_mask: 1275e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg8_mask: { 1276fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ true, /*IsStrided*/ false); 1277e8d8bef9SDimitry Andric return; 1278e8d8bef9SDimitry Andric } 1279e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg2: 1280e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg3: 1281e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg4: 1282e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg5: 1283e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg6: 1284e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg7: 1285e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg8: { 1286fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ false, /*IsStrided*/ true); 1287e8d8bef9SDimitry Andric return; 1288e8d8bef9SDimitry Andric } 1289e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg2_mask: 1290e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg3_mask: 1291e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg4_mask: 1292e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg5_mask: 1293e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg6_mask: 1294e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg7_mask: 1295e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg8_mask: { 1296fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ true, /*IsStrided*/ true); 1297e8d8bef9SDimitry Andric return; 1298e8d8bef9SDimitry Andric } 1299e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg2: 1300e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg3: 1301e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg4: 1302e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg5: 1303e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg6: 1304e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg7: 1305e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg8: 1306fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ true); 1307fe6060f1SDimitry Andric return; 1308e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg2: 1309e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg3: 1310e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg4: 1311e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg5: 1312e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg6: 1313e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg7: 1314fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxseg8: 1315fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ false); 1316e8d8bef9SDimitry Andric return; 1317e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg2_mask: 1318e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg3_mask: 1319e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg4_mask: 1320e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg5_mask: 1321e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg6_mask: 1322e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg7_mask: 1323e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg8_mask: 1324fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ true); 1325fe6060f1SDimitry Andric return; 1326e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg2_mask: 1327e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg3_mask: 1328e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg4_mask: 1329e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg5_mask: 1330e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg6_mask: 1331e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg7_mask: 1332fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxseg8_mask: 1333fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ false); 1334fe6060f1SDimitry Andric return; 1335fe6060f1SDimitry Andric case Intrinsic::riscv_vsoxei: 1336fe6060f1SDimitry Andric case Intrinsic::riscv_vsoxei_mask: 1337fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxei: 1338fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxei_mask: { 1339fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vsoxei_mask || 1340fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsuxei_mask; 1341fe6060f1SDimitry Andric bool IsOrdered = IntNo == Intrinsic::riscv_vsoxei || 1342fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsoxei_mask; 1343fe6060f1SDimitry Andric 1344fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 1345fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1346fe6060f1SDimitry Andric 1347fe6060f1SDimitry Andric unsigned CurOp = 2; 1348fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 1349fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Store value. 1350fe6060f1SDimitry Andric 1351fe6060f1SDimitry Andric MVT IndexVT; 1352fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1353fe6060f1SDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 1354349cc55cSDimitry Andric /*IsLoad=*/false, &IndexVT); 1355fe6060f1SDimitry Andric 1356fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 1357fe6060f1SDimitry Andric "Element count mismatch"); 1358fe6060f1SDimitry Andric 1359fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1360fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 1361fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 1362fe6060f1SDimitry Andric const RISCV::VLX_VSXPseudo *P = RISCV::getVSXPseudo( 1363fe6060f1SDimitry Andric IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 1364fe6060f1SDimitry Andric static_cast<unsigned>(IndexLMUL)); 1365fe6060f1SDimitry Andric MachineSDNode *Store = 1366fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1367fe6060f1SDimitry Andric 1368fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1369fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 1370fe6060f1SDimitry Andric 1371fe6060f1SDimitry Andric ReplaceNode(Node, Store); 1372fe6060f1SDimitry Andric return; 1373fe6060f1SDimitry Andric } 1374349cc55cSDimitry Andric case Intrinsic::riscv_vsm: 1375fe6060f1SDimitry Andric case Intrinsic::riscv_vse: 1376fe6060f1SDimitry Andric case Intrinsic::riscv_vse_mask: 1377fe6060f1SDimitry Andric case Intrinsic::riscv_vsse: 1378fe6060f1SDimitry Andric case Intrinsic::riscv_vsse_mask: { 1379fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vse_mask || 1380fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsse_mask; 1381fe6060f1SDimitry Andric bool IsStrided = 1382fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsse || IntNo == Intrinsic::riscv_vsse_mask; 1383fe6060f1SDimitry Andric 1384fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 1385fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1386fe6060f1SDimitry Andric 1387fe6060f1SDimitry Andric unsigned CurOp = 2; 1388fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 1389fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Store value. 1390fe6060f1SDimitry Andric 1391fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 1392fe6060f1SDimitry Andric Operands); 1393fe6060f1SDimitry Andric 1394fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1395fe6060f1SDimitry Andric const RISCV::VSEPseudo *P = RISCV::getVSEPseudo( 1396fe6060f1SDimitry Andric IsMasked, IsStrided, Log2SEW, static_cast<unsigned>(LMUL)); 1397fe6060f1SDimitry Andric MachineSDNode *Store = 1398fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1399fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1400fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 1401fe6060f1SDimitry Andric 1402fe6060f1SDimitry Andric ReplaceNode(Node, Store); 1403e8d8bef9SDimitry Andric return; 1404e8d8bef9SDimitry Andric } 1405e8d8bef9SDimitry Andric } 1406e8d8bef9SDimitry Andric break; 1407e8d8bef9SDimitry Andric } 1408fe6060f1SDimitry Andric case ISD::BITCAST: { 1409fe6060f1SDimitry Andric MVT SrcVT = Node->getOperand(0).getSimpleValueType(); 1410fe6060f1SDimitry Andric // Just drop bitcasts between vectors if both are fixed or both are 1411fe6060f1SDimitry Andric // scalable. 1412fe6060f1SDimitry Andric if ((VT.isScalableVector() && SrcVT.isScalableVector()) || 1413fe6060f1SDimitry Andric (VT.isFixedLengthVector() && SrcVT.isFixedLengthVector())) { 1414fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, 0), Node->getOperand(0)); 1415fe6060f1SDimitry Andric CurDAG->RemoveDeadNode(Node); 1416e8d8bef9SDimitry Andric return; 1417e8d8bef9SDimitry Andric } 1418fe6060f1SDimitry Andric break; 1419fe6060f1SDimitry Andric } 1420fe6060f1SDimitry Andric case ISD::INSERT_SUBVECTOR: { 1421fe6060f1SDimitry Andric SDValue V = Node->getOperand(0); 1422fe6060f1SDimitry Andric SDValue SubV = Node->getOperand(1); 1423fe6060f1SDimitry Andric SDLoc DL(SubV); 1424fe6060f1SDimitry Andric auto Idx = Node->getConstantOperandVal(2); 1425fe6060f1SDimitry Andric MVT SubVecVT = SubV.getSimpleValueType(); 1426fe6060f1SDimitry Andric 1427fe6060f1SDimitry Andric const RISCVTargetLowering &TLI = *Subtarget->getTargetLowering(); 1428fe6060f1SDimitry Andric MVT SubVecContainerVT = SubVecVT; 1429fe6060f1SDimitry Andric // Establish the correct scalable-vector types for any fixed-length type. 1430fe6060f1SDimitry Andric if (SubVecVT.isFixedLengthVector()) 1431fe6060f1SDimitry Andric SubVecContainerVT = TLI.getContainerForFixedLengthVector(SubVecVT); 1432fe6060f1SDimitry Andric if (VT.isFixedLengthVector()) 1433fe6060f1SDimitry Andric VT = TLI.getContainerForFixedLengthVector(VT); 1434fe6060f1SDimitry Andric 1435fe6060f1SDimitry Andric const auto *TRI = Subtarget->getRegisterInfo(); 1436fe6060f1SDimitry Andric unsigned SubRegIdx; 1437fe6060f1SDimitry Andric std::tie(SubRegIdx, Idx) = 1438fe6060f1SDimitry Andric RISCVTargetLowering::decomposeSubvectorInsertExtractToSubRegs( 1439fe6060f1SDimitry Andric VT, SubVecContainerVT, Idx, TRI); 1440fe6060f1SDimitry Andric 1441fe6060f1SDimitry Andric // If the Idx hasn't been completely eliminated then this is a subvector 1442fe6060f1SDimitry Andric // insert which doesn't naturally align to a vector register. These must 1443fe6060f1SDimitry Andric // be handled using instructions to manipulate the vector registers. 1444fe6060f1SDimitry Andric if (Idx != 0) 1445fe6060f1SDimitry Andric break; 1446fe6060f1SDimitry Andric 1447fe6060f1SDimitry Andric RISCVII::VLMUL SubVecLMUL = RISCVTargetLowering::getLMUL(SubVecContainerVT); 1448fe6060f1SDimitry Andric bool IsSubVecPartReg = SubVecLMUL == RISCVII::VLMUL::LMUL_F2 || 1449fe6060f1SDimitry Andric SubVecLMUL == RISCVII::VLMUL::LMUL_F4 || 1450fe6060f1SDimitry Andric SubVecLMUL == RISCVII::VLMUL::LMUL_F8; 1451fe6060f1SDimitry Andric (void)IsSubVecPartReg; // Silence unused variable warning without asserts. 1452fe6060f1SDimitry Andric assert((!IsSubVecPartReg || V.isUndef()) && 1453fe6060f1SDimitry Andric "Expecting lowering to have created legal INSERT_SUBVECTORs when " 1454fe6060f1SDimitry Andric "the subvector is smaller than a full-sized register"); 1455fe6060f1SDimitry Andric 1456fe6060f1SDimitry Andric // If we haven't set a SubRegIdx, then we must be going between 1457fe6060f1SDimitry Andric // equally-sized LMUL groups (e.g. VR -> VR). This can be done as a copy. 1458fe6060f1SDimitry Andric if (SubRegIdx == RISCV::NoSubRegister) { 1459fe6060f1SDimitry Andric unsigned InRegClassID = RISCVTargetLowering::getRegClassIDForVecVT(VT); 1460fe6060f1SDimitry Andric assert(RISCVTargetLowering::getRegClassIDForVecVT(SubVecContainerVT) == 1461fe6060f1SDimitry Andric InRegClassID && 1462fe6060f1SDimitry Andric "Unexpected subvector extraction"); 1463fe6060f1SDimitry Andric SDValue RC = CurDAG->getTargetConstant(InRegClassID, DL, XLenVT); 1464fe6060f1SDimitry Andric SDNode *NewNode = CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, 1465fe6060f1SDimitry Andric DL, VT, SubV, RC); 1466fe6060f1SDimitry Andric ReplaceNode(Node, NewNode); 1467fe6060f1SDimitry Andric return; 1468fe6060f1SDimitry Andric } 1469fe6060f1SDimitry Andric 1470fe6060f1SDimitry Andric SDValue Insert = CurDAG->getTargetInsertSubreg(SubRegIdx, DL, VT, V, SubV); 1471fe6060f1SDimitry Andric ReplaceNode(Node, Insert.getNode()); 1472fe6060f1SDimitry Andric return; 1473fe6060f1SDimitry Andric } 1474fe6060f1SDimitry Andric case ISD::EXTRACT_SUBVECTOR: { 1475fe6060f1SDimitry Andric SDValue V = Node->getOperand(0); 1476fe6060f1SDimitry Andric auto Idx = Node->getConstantOperandVal(1); 1477fe6060f1SDimitry Andric MVT InVT = V.getSimpleValueType(); 1478fe6060f1SDimitry Andric SDLoc DL(V); 1479fe6060f1SDimitry Andric 1480fe6060f1SDimitry Andric const RISCVTargetLowering &TLI = *Subtarget->getTargetLowering(); 1481fe6060f1SDimitry Andric MVT SubVecContainerVT = VT; 1482fe6060f1SDimitry Andric // Establish the correct scalable-vector types for any fixed-length type. 1483fe6060f1SDimitry Andric if (VT.isFixedLengthVector()) 1484fe6060f1SDimitry Andric SubVecContainerVT = TLI.getContainerForFixedLengthVector(VT); 1485fe6060f1SDimitry Andric if (InVT.isFixedLengthVector()) 1486fe6060f1SDimitry Andric InVT = TLI.getContainerForFixedLengthVector(InVT); 1487fe6060f1SDimitry Andric 1488fe6060f1SDimitry Andric const auto *TRI = Subtarget->getRegisterInfo(); 1489fe6060f1SDimitry Andric unsigned SubRegIdx; 1490fe6060f1SDimitry Andric std::tie(SubRegIdx, Idx) = 1491fe6060f1SDimitry Andric RISCVTargetLowering::decomposeSubvectorInsertExtractToSubRegs( 1492fe6060f1SDimitry Andric InVT, SubVecContainerVT, Idx, TRI); 1493fe6060f1SDimitry Andric 1494fe6060f1SDimitry Andric // If the Idx hasn't been completely eliminated then this is a subvector 1495fe6060f1SDimitry Andric // extract which doesn't naturally align to a vector register. These must 1496fe6060f1SDimitry Andric // be handled using instructions to manipulate the vector registers. 1497fe6060f1SDimitry Andric if (Idx != 0) 1498fe6060f1SDimitry Andric break; 1499fe6060f1SDimitry Andric 1500fe6060f1SDimitry Andric // If we haven't set a SubRegIdx, then we must be going between 1501fe6060f1SDimitry Andric // equally-sized LMUL types (e.g. VR -> VR). This can be done as a copy. 1502fe6060f1SDimitry Andric if (SubRegIdx == RISCV::NoSubRegister) { 1503fe6060f1SDimitry Andric unsigned InRegClassID = RISCVTargetLowering::getRegClassIDForVecVT(InVT); 1504fe6060f1SDimitry Andric assert(RISCVTargetLowering::getRegClassIDForVecVT(SubVecContainerVT) == 1505fe6060f1SDimitry Andric InRegClassID && 1506fe6060f1SDimitry Andric "Unexpected subvector extraction"); 1507fe6060f1SDimitry Andric SDValue RC = CurDAG->getTargetConstant(InRegClassID, DL, XLenVT); 1508fe6060f1SDimitry Andric SDNode *NewNode = 1509fe6060f1SDimitry Andric CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, VT, V, RC); 1510fe6060f1SDimitry Andric ReplaceNode(Node, NewNode); 1511fe6060f1SDimitry Andric return; 1512fe6060f1SDimitry Andric } 1513fe6060f1SDimitry Andric 1514fe6060f1SDimitry Andric SDValue Extract = CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, V); 1515fe6060f1SDimitry Andric ReplaceNode(Node, Extract.getNode()); 1516fe6060f1SDimitry Andric return; 1517fe6060f1SDimitry Andric } 1518*0eae32dcSDimitry Andric case ISD::SPLAT_VECTOR: 1519fe6060f1SDimitry Andric case RISCVISD::VMV_V_X_VL: 1520fe6060f1SDimitry Andric case RISCVISD::VFMV_V_F_VL: { 1521fe6060f1SDimitry Andric // Try to match splat of a scalar load to a strided load with stride of x0. 1522fe6060f1SDimitry Andric SDValue Src = Node->getOperand(0); 1523fe6060f1SDimitry Andric auto *Ld = dyn_cast<LoadSDNode>(Src); 1524fe6060f1SDimitry Andric if (!Ld) 1525fe6060f1SDimitry Andric break; 1526fe6060f1SDimitry Andric EVT MemVT = Ld->getMemoryVT(); 1527fe6060f1SDimitry Andric // The memory VT should be the same size as the element type. 1528fe6060f1SDimitry Andric if (MemVT.getStoreSize() != VT.getVectorElementType().getStoreSize()) 1529fe6060f1SDimitry Andric break; 1530fe6060f1SDimitry Andric if (!IsProfitableToFold(Src, Node, Node) || 1531fe6060f1SDimitry Andric !IsLegalToFold(Src, Node, Node, TM.getOptLevel())) 1532fe6060f1SDimitry Andric break; 1533fe6060f1SDimitry Andric 1534fe6060f1SDimitry Andric SDValue VL; 1535*0eae32dcSDimitry Andric if (Node->getOpcode() == ISD::SPLAT_VECTOR) 1536*0eae32dcSDimitry Andric VL = CurDAG->getTargetConstant(RISCV::VLMaxSentinel, DL, XLenVT); 1537*0eae32dcSDimitry Andric else 1538fe6060f1SDimitry Andric selectVLOp(Node->getOperand(1), VL); 1539fe6060f1SDimitry Andric 1540fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1541fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(Log2SEW, DL, XLenVT); 1542fe6060f1SDimitry Andric 1543fe6060f1SDimitry Andric SDValue Operands[] = {Ld->getBasePtr(), 1544fe6060f1SDimitry Andric CurDAG->getRegister(RISCV::X0, XLenVT), VL, SEW, 1545fe6060f1SDimitry Andric Ld->getChain()}; 1546fe6060f1SDimitry Andric 1547fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1548fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = RISCV::getVLEPseudo( 1549fe6060f1SDimitry Andric /*IsMasked*/ false, /*IsStrided*/ true, /*FF*/ false, Log2SEW, 1550fe6060f1SDimitry Andric static_cast<unsigned>(LMUL)); 1551fe6060f1SDimitry Andric MachineSDNode *Load = 1552fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1553fe6060f1SDimitry Andric 1554fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1555fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1556fe6060f1SDimitry Andric 1557fe6060f1SDimitry Andric ReplaceNode(Node, Load); 1558e8d8bef9SDimitry Andric return; 1559e8d8bef9SDimitry Andric } 1560e8d8bef9SDimitry Andric } 15610b57cec5SDimitry Andric 15620b57cec5SDimitry Andric // Select the default instruction. 15630b57cec5SDimitry Andric SelectCode(Node); 15640b57cec5SDimitry Andric } 15650b57cec5SDimitry Andric 15660b57cec5SDimitry Andric bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand( 15670b57cec5SDimitry Andric const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { 15680b57cec5SDimitry Andric switch (ConstraintID) { 15690b57cec5SDimitry Andric case InlineAsm::Constraint_m: 15700b57cec5SDimitry Andric // We just support simple memory operands that have a single address 15710b57cec5SDimitry Andric // operand and need no special handling. 15720b57cec5SDimitry Andric OutOps.push_back(Op); 15730b57cec5SDimitry Andric return false; 15740b57cec5SDimitry Andric case InlineAsm::Constraint_A: 15750b57cec5SDimitry Andric OutOps.push_back(Op); 15760b57cec5SDimitry Andric return false; 15770b57cec5SDimitry Andric default: 15780b57cec5SDimitry Andric break; 15790b57cec5SDimitry Andric } 15800b57cec5SDimitry Andric 15810b57cec5SDimitry Andric return true; 15820b57cec5SDimitry Andric } 15830b57cec5SDimitry Andric 15840b57cec5SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) { 1585fe6060f1SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 15860b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT()); 15870b57cec5SDimitry Andric return true; 15880b57cec5SDimitry Andric } 15890b57cec5SDimitry Andric return false; 15900b57cec5SDimitry Andric } 15910b57cec5SDimitry Andric 1592fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::SelectBaseAddr(SDValue Addr, SDValue &Base) { 1593fe6060f1SDimitry Andric // If this is FrameIndex, select it directly. Otherwise just let it get 1594fe6060f1SDimitry Andric // selected to a register independently. 1595fe6060f1SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr)) 1596fe6060f1SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT()); 1597fe6060f1SDimitry Andric else 1598fe6060f1SDimitry Andric Base = Addr; 1599fe6060f1SDimitry Andric return true; 1600e8d8bef9SDimitry Andric } 1601e8d8bef9SDimitry Andric 1602fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth, 1603fe6060f1SDimitry Andric SDValue &ShAmt) { 1604fe6060f1SDimitry Andric // Shift instructions on RISCV only read the lower 5 or 6 bits of the shift 1605fe6060f1SDimitry Andric // amount. If there is an AND on the shift amount, we can bypass it if it 1606fe6060f1SDimitry Andric // doesn't affect any of those bits. 1607fe6060f1SDimitry Andric if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) { 1608fe6060f1SDimitry Andric const APInt &AndMask = N->getConstantOperandAPInt(1); 1609979e22ffSDimitry Andric 1610fe6060f1SDimitry Andric // Since the max shift amount is a power of 2 we can subtract 1 to make a 1611fe6060f1SDimitry Andric // mask that covers the bits needed to represent all shift amounts. 1612fe6060f1SDimitry Andric assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!"); 1613fe6060f1SDimitry Andric APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1); 1614e8d8bef9SDimitry Andric 1615fe6060f1SDimitry Andric if (ShMask.isSubsetOf(AndMask)) { 1616fe6060f1SDimitry Andric ShAmt = N.getOperand(0); 1617fe6060f1SDimitry Andric return true; 1618e8d8bef9SDimitry Andric } 1619e8d8bef9SDimitry Andric 1620fe6060f1SDimitry Andric // SimplifyDemandedBits may have optimized the mask so try restoring any 1621fe6060f1SDimitry Andric // bits that are known zero. 1622fe6060f1SDimitry Andric KnownBits Known = CurDAG->computeKnownBits(N->getOperand(0)); 1623fe6060f1SDimitry Andric if (ShMask.isSubsetOf(AndMask | Known.Zero)) { 1624fe6060f1SDimitry Andric ShAmt = N.getOperand(0); 1625fe6060f1SDimitry Andric return true; 1626fe6060f1SDimitry Andric } 1627fe6060f1SDimitry Andric } 1628fe6060f1SDimitry Andric 1629fe6060f1SDimitry Andric ShAmt = N; 1630fe6060f1SDimitry Andric return true; 1631fe6060f1SDimitry Andric } 1632fe6060f1SDimitry Andric 1633fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) { 1634fe6060f1SDimitry Andric if (N.getOpcode() == ISD::SIGN_EXTEND_INREG && 1635fe6060f1SDimitry Andric cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) { 1636fe6060f1SDimitry Andric Val = N.getOperand(0); 1637fe6060f1SDimitry Andric return true; 1638fe6060f1SDimitry Andric } 1639fe6060f1SDimitry Andric MVT VT = N.getSimpleValueType(); 1640fe6060f1SDimitry Andric if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) { 1641fe6060f1SDimitry Andric Val = N; 1642fe6060f1SDimitry Andric return true; 1643fe6060f1SDimitry Andric } 1644fe6060f1SDimitry Andric 1645fe6060f1SDimitry Andric return false; 1646fe6060f1SDimitry Andric } 1647fe6060f1SDimitry Andric 1648fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectZExti32(SDValue N, SDValue &Val) { 1649fe6060f1SDimitry Andric if (N.getOpcode() == ISD::AND) { 1650fe6060f1SDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1)); 1651fe6060f1SDimitry Andric if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) { 1652fe6060f1SDimitry Andric Val = N.getOperand(0); 1653fe6060f1SDimitry Andric return true; 1654fe6060f1SDimitry Andric } 1655fe6060f1SDimitry Andric } 1656fe6060f1SDimitry Andric MVT VT = N.getSimpleValueType(); 1657fe6060f1SDimitry Andric APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), 32); 1658fe6060f1SDimitry Andric if (CurDAG->MaskedValueIsZero(N, Mask)) { 1659fe6060f1SDimitry Andric Val = N; 1660fe6060f1SDimitry Andric return true; 1661fe6060f1SDimitry Andric } 1662fe6060f1SDimitry Andric 1663fe6060f1SDimitry Andric return false; 1664fe6060f1SDimitry Andric } 1665fe6060f1SDimitry Andric 1666349cc55cSDimitry Andric // Return true if all users of this SDNode* only consume the lower \p Bits. 1667349cc55cSDimitry Andric // This can be used to form W instructions for add/sub/mul/shl even when the 1668349cc55cSDimitry Andric // root isn't a sext_inreg. This can allow the ADDW/SUBW/MULW/SLLIW to CSE if 1669349cc55cSDimitry Andric // SimplifyDemandedBits has made it so some users see a sext_inreg and some 1670349cc55cSDimitry Andric // don't. The sext_inreg+add/sub/mul/shl will get selected, but still leave 1671349cc55cSDimitry Andric // the add/sub/mul/shl to become non-W instructions. By checking the users we 1672349cc55cSDimitry Andric // may be able to use a W instruction and CSE with the other instruction if 1673349cc55cSDimitry Andric // this has happened. We could try to detect that the CSE opportunity exists 1674349cc55cSDimitry Andric // before doing this, but that would be more complicated. 1675349cc55cSDimitry Andric // TODO: Does this need to look through AND/OR/XOR to their users to find more 1676349cc55cSDimitry Andric // opportunities. 1677349cc55cSDimitry Andric bool RISCVDAGToDAGISel::hasAllNBitUsers(SDNode *Node, unsigned Bits) const { 1678349cc55cSDimitry Andric assert((Node->getOpcode() == ISD::ADD || Node->getOpcode() == ISD::SUB || 1679349cc55cSDimitry Andric Node->getOpcode() == ISD::MUL || Node->getOpcode() == ISD::SHL || 1680349cc55cSDimitry Andric Node->getOpcode() == ISD::SRL || 1681349cc55cSDimitry Andric Node->getOpcode() == ISD::SIGN_EXTEND_INREG || 1682349cc55cSDimitry Andric isa<ConstantSDNode>(Node)) && 1683349cc55cSDimitry Andric "Unexpected opcode"); 1684349cc55cSDimitry Andric 1685349cc55cSDimitry Andric for (auto UI = Node->use_begin(), UE = Node->use_end(); UI != UE; ++UI) { 1686349cc55cSDimitry Andric SDNode *User = *UI; 1687349cc55cSDimitry Andric // Users of this node should have already been instruction selected 1688349cc55cSDimitry Andric if (!User->isMachineOpcode()) 1689349cc55cSDimitry Andric return false; 1690349cc55cSDimitry Andric 1691349cc55cSDimitry Andric // TODO: Add more opcodes? 1692349cc55cSDimitry Andric switch (User->getMachineOpcode()) { 1693349cc55cSDimitry Andric default: 1694349cc55cSDimitry Andric return false; 1695349cc55cSDimitry Andric case RISCV::ADDW: 1696349cc55cSDimitry Andric case RISCV::ADDIW: 1697349cc55cSDimitry Andric case RISCV::SUBW: 1698349cc55cSDimitry Andric case RISCV::MULW: 1699349cc55cSDimitry Andric case RISCV::SLLW: 1700349cc55cSDimitry Andric case RISCV::SLLIW: 1701349cc55cSDimitry Andric case RISCV::SRAW: 1702349cc55cSDimitry Andric case RISCV::SRAIW: 1703349cc55cSDimitry Andric case RISCV::SRLW: 1704349cc55cSDimitry Andric case RISCV::SRLIW: 1705349cc55cSDimitry Andric case RISCV::DIVW: 1706349cc55cSDimitry Andric case RISCV::DIVUW: 1707349cc55cSDimitry Andric case RISCV::REMW: 1708349cc55cSDimitry Andric case RISCV::REMUW: 1709349cc55cSDimitry Andric case RISCV::ROLW: 1710349cc55cSDimitry Andric case RISCV::RORW: 1711349cc55cSDimitry Andric case RISCV::RORIW: 1712349cc55cSDimitry Andric case RISCV::CLZW: 1713349cc55cSDimitry Andric case RISCV::CTZW: 1714349cc55cSDimitry Andric case RISCV::CPOPW: 1715349cc55cSDimitry Andric case RISCV::SLLIUW: 1716349cc55cSDimitry Andric case RISCV::FCVT_H_W: 1717349cc55cSDimitry Andric case RISCV::FCVT_H_WU: 1718349cc55cSDimitry Andric case RISCV::FCVT_S_W: 1719349cc55cSDimitry Andric case RISCV::FCVT_S_WU: 1720349cc55cSDimitry Andric case RISCV::FCVT_D_W: 1721349cc55cSDimitry Andric case RISCV::FCVT_D_WU: 1722349cc55cSDimitry Andric if (Bits < 32) 1723349cc55cSDimitry Andric return false; 1724349cc55cSDimitry Andric break; 1725349cc55cSDimitry Andric case RISCV::SLLI: 1726349cc55cSDimitry Andric // SLLI only uses the lower (XLen - ShAmt) bits. 1727349cc55cSDimitry Andric if (Bits < Subtarget->getXLen() - User->getConstantOperandVal(1)) 1728349cc55cSDimitry Andric return false; 1729349cc55cSDimitry Andric break; 1730349cc55cSDimitry Andric case RISCV::ADDUW: 1731349cc55cSDimitry Andric case RISCV::SH1ADDUW: 1732349cc55cSDimitry Andric case RISCV::SH2ADDUW: 1733349cc55cSDimitry Andric case RISCV::SH3ADDUW: 1734349cc55cSDimitry Andric // The first operand to add.uw/shXadd.uw is implicitly zero extended from 1735349cc55cSDimitry Andric // 32 bits. 1736349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 32) 1737349cc55cSDimitry Andric return false; 1738349cc55cSDimitry Andric break; 1739349cc55cSDimitry Andric case RISCV::SB: 1740349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 8) 1741349cc55cSDimitry Andric return false; 1742349cc55cSDimitry Andric break; 1743349cc55cSDimitry Andric case RISCV::SH: 1744349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 16) 1745349cc55cSDimitry Andric return false; 1746349cc55cSDimitry Andric break; 1747349cc55cSDimitry Andric case RISCV::SW: 1748349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 32) 1749349cc55cSDimitry Andric return false; 1750349cc55cSDimitry Andric break; 1751349cc55cSDimitry Andric } 1752349cc55cSDimitry Andric } 1753349cc55cSDimitry Andric 1754349cc55cSDimitry Andric return true; 1755349cc55cSDimitry Andric } 1756349cc55cSDimitry Andric 1757fe6060f1SDimitry Andric // Select VL as a 5 bit immediate or a value that will become a register. This 1758fe6060f1SDimitry Andric // allows us to choose betwen VSETIVLI or VSETVLI later. 1759d409305fSDimitry Andric bool RISCVDAGToDAGISel::selectVLOp(SDValue N, SDValue &VL) { 1760d409305fSDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N); 1761fe6060f1SDimitry Andric if (C && isUInt<5>(C->getZExtValue())) 1762fe6060f1SDimitry Andric VL = CurDAG->getTargetConstant(C->getZExtValue(), SDLoc(N), 1763fe6060f1SDimitry Andric N->getValueType(0)); 1764d409305fSDimitry Andric else 1765d409305fSDimitry Andric VL = N; 1766d409305fSDimitry Andric 1767d409305fSDimitry Andric return true; 1768d409305fSDimitry Andric } 1769d409305fSDimitry Andric 1770e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::selectVSplat(SDValue N, SDValue &SplatVal) { 1771e8d8bef9SDimitry Andric if (N.getOpcode() != ISD::SPLAT_VECTOR && 1772fe6060f1SDimitry Andric N.getOpcode() != RISCVISD::SPLAT_VECTOR_I64 && 1773fe6060f1SDimitry Andric N.getOpcode() != RISCVISD::VMV_V_X_VL) 1774e8d8bef9SDimitry Andric return false; 1775e8d8bef9SDimitry Andric SplatVal = N.getOperand(0); 1776979e22ffSDimitry Andric return true; 1777979e22ffSDimitry Andric } 1778e8d8bef9SDimitry Andric 1779fe6060f1SDimitry Andric using ValidateFn = bool (*)(int64_t); 1780fe6060f1SDimitry Andric 1781fe6060f1SDimitry Andric static bool selectVSplatSimmHelper(SDValue N, SDValue &SplatVal, 1782fe6060f1SDimitry Andric SelectionDAG &DAG, 1783fe6060f1SDimitry Andric const RISCVSubtarget &Subtarget, 1784fe6060f1SDimitry Andric ValidateFn ValidateImm) { 1785e8d8bef9SDimitry Andric if ((N.getOpcode() != ISD::SPLAT_VECTOR && 1786fe6060f1SDimitry Andric N.getOpcode() != RISCVISD::SPLAT_VECTOR_I64 && 1787fe6060f1SDimitry Andric N.getOpcode() != RISCVISD::VMV_V_X_VL) || 1788e8d8bef9SDimitry Andric !isa<ConstantSDNode>(N.getOperand(0))) 1789979e22ffSDimitry Andric return false; 1790e8d8bef9SDimitry Andric 1791e8d8bef9SDimitry Andric int64_t SplatImm = cast<ConstantSDNode>(N.getOperand(0))->getSExtValue(); 1792e8d8bef9SDimitry Andric 1793fe6060f1SDimitry Andric // ISD::SPLAT_VECTOR, RISCVISD::SPLAT_VECTOR_I64 and RISCVISD::VMV_V_X_VL 1794fe6060f1SDimitry Andric // share semantics when the operand type is wider than the resulting vector 1795fe6060f1SDimitry Andric // element type: an implicit truncation first takes place. Therefore, perform 1796fe6060f1SDimitry Andric // a manual truncation/sign-extension in order to ignore any truncated bits 1797fe6060f1SDimitry Andric // and catch any zero-extended immediate. 1798e8d8bef9SDimitry Andric // For example, we wish to match (i8 -1) -> (XLenVT 255) as a simm5 by first 1799e8d8bef9SDimitry Andric // sign-extending to (XLenVT -1). 1800fe6060f1SDimitry Andric MVT XLenVT = Subtarget.getXLenVT(); 1801e8d8bef9SDimitry Andric assert(XLenVT == N.getOperand(0).getSimpleValueType() && 1802e8d8bef9SDimitry Andric "Unexpected splat operand type"); 1803fe6060f1SDimitry Andric MVT EltVT = N.getSimpleValueType().getVectorElementType(); 1804fe6060f1SDimitry Andric if (EltVT.bitsLT(XLenVT)) 1805e8d8bef9SDimitry Andric SplatImm = SignExtend64(SplatImm, EltVT.getSizeInBits()); 1806979e22ffSDimitry Andric 1807fe6060f1SDimitry Andric if (!ValidateImm(SplatImm)) 1808e8d8bef9SDimitry Andric return false; 1809979e22ffSDimitry Andric 1810fe6060f1SDimitry Andric SplatVal = DAG.getTargetConstant(SplatImm, SDLoc(N), XLenVT); 1811979e22ffSDimitry Andric return true; 1812979e22ffSDimitry Andric } 1813e8d8bef9SDimitry Andric 1814fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5(SDValue N, SDValue &SplatVal) { 1815fe6060f1SDimitry Andric return selectVSplatSimmHelper(N, SplatVal, *CurDAG, *Subtarget, 1816fe6060f1SDimitry Andric [](int64_t Imm) { return isInt<5>(Imm); }); 1817fe6060f1SDimitry Andric } 1818fe6060f1SDimitry Andric 1819fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5Plus1(SDValue N, SDValue &SplatVal) { 1820fe6060f1SDimitry Andric return selectVSplatSimmHelper( 1821fe6060f1SDimitry Andric N, SplatVal, *CurDAG, *Subtarget, 1822fe6060f1SDimitry Andric [](int64_t Imm) { return (isInt<5>(Imm) && Imm != -16) || Imm == 16; }); 1823fe6060f1SDimitry Andric } 1824fe6060f1SDimitry Andric 1825fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5Plus1NonZero(SDValue N, 1826fe6060f1SDimitry Andric SDValue &SplatVal) { 1827fe6060f1SDimitry Andric return selectVSplatSimmHelper( 1828fe6060f1SDimitry Andric N, SplatVal, *CurDAG, *Subtarget, [](int64_t Imm) { 1829fe6060f1SDimitry Andric return Imm != 0 && ((isInt<5>(Imm) && Imm != -16) || Imm == 16); 1830fe6060f1SDimitry Andric }); 1831fe6060f1SDimitry Andric } 1832fe6060f1SDimitry Andric 1833e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatUimm5(SDValue N, SDValue &SplatVal) { 1834e8d8bef9SDimitry Andric if ((N.getOpcode() != ISD::SPLAT_VECTOR && 1835fe6060f1SDimitry Andric N.getOpcode() != RISCVISD::SPLAT_VECTOR_I64 && 1836fe6060f1SDimitry Andric N.getOpcode() != RISCVISD::VMV_V_X_VL) || 1837e8d8bef9SDimitry Andric !isa<ConstantSDNode>(N.getOperand(0))) 1838979e22ffSDimitry Andric return false; 1839979e22ffSDimitry Andric 1840e8d8bef9SDimitry Andric int64_t SplatImm = cast<ConstantSDNode>(N.getOperand(0))->getSExtValue(); 1841979e22ffSDimitry Andric 1842e8d8bef9SDimitry Andric if (!isUInt<5>(SplatImm)) 1843e8d8bef9SDimitry Andric return false; 1844e8d8bef9SDimitry Andric 1845e8d8bef9SDimitry Andric SplatVal = 1846e8d8bef9SDimitry Andric CurDAG->getTargetConstant(SplatImm, SDLoc(N), Subtarget->getXLenVT()); 1847e8d8bef9SDimitry Andric 1848979e22ffSDimitry Andric return true; 1849979e22ffSDimitry Andric } 1850979e22ffSDimitry Andric 1851fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectRVVSimm5(SDValue N, unsigned Width, 1852fe6060f1SDimitry Andric SDValue &Imm) { 1853fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(N)) { 1854fe6060f1SDimitry Andric int64_t ImmVal = SignExtend64(C->getSExtValue(), Width); 1855fe6060f1SDimitry Andric 1856fe6060f1SDimitry Andric if (!isInt<5>(ImmVal)) 1857fe6060f1SDimitry Andric return false; 1858fe6060f1SDimitry Andric 1859fe6060f1SDimitry Andric Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), Subtarget->getXLenVT()); 1860fe6060f1SDimitry Andric return true; 1861fe6060f1SDimitry Andric } 1862fe6060f1SDimitry Andric 1863fe6060f1SDimitry Andric return false; 1864fe6060f1SDimitry Andric } 1865fe6060f1SDimitry Andric 18660b57cec5SDimitry Andric // Merge an ADDI into the offset of a load/store instruction where possible. 18675ffd83dbSDimitry Andric // (load (addi base, off1), off2) -> (load base, off1+off2) 18685ffd83dbSDimitry Andric // (store val, (addi base, off1), off2) -> (store val, base, off1+off2) 18695ffd83dbSDimitry Andric // This is possible when off1+off2 fits a 12-bit immediate. 1870349cc55cSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeLoadStoreADDI(SDNode *N) { 18710b57cec5SDimitry Andric int OffsetOpIdx; 18720b57cec5SDimitry Andric int BaseOpIdx; 18730b57cec5SDimitry Andric 18740b57cec5SDimitry Andric // Only attempt this optimisation for I-type loads and S-type stores. 18750b57cec5SDimitry Andric switch (N->getMachineOpcode()) { 18760b57cec5SDimitry Andric default: 1877349cc55cSDimitry Andric return false; 18780b57cec5SDimitry Andric case RISCV::LB: 18790b57cec5SDimitry Andric case RISCV::LH: 18800b57cec5SDimitry Andric case RISCV::LW: 18810b57cec5SDimitry Andric case RISCV::LBU: 18820b57cec5SDimitry Andric case RISCV::LHU: 18830b57cec5SDimitry Andric case RISCV::LWU: 18840b57cec5SDimitry Andric case RISCV::LD: 1885e8d8bef9SDimitry Andric case RISCV::FLH: 18860b57cec5SDimitry Andric case RISCV::FLW: 18870b57cec5SDimitry Andric case RISCV::FLD: 18880b57cec5SDimitry Andric BaseOpIdx = 0; 18890b57cec5SDimitry Andric OffsetOpIdx = 1; 18900b57cec5SDimitry Andric break; 18910b57cec5SDimitry Andric case RISCV::SB: 18920b57cec5SDimitry Andric case RISCV::SH: 18930b57cec5SDimitry Andric case RISCV::SW: 18940b57cec5SDimitry Andric case RISCV::SD: 1895e8d8bef9SDimitry Andric case RISCV::FSH: 18960b57cec5SDimitry Andric case RISCV::FSW: 18970b57cec5SDimitry Andric case RISCV::FSD: 18980b57cec5SDimitry Andric BaseOpIdx = 1; 18990b57cec5SDimitry Andric OffsetOpIdx = 2; 19000b57cec5SDimitry Andric break; 19010b57cec5SDimitry Andric } 19020b57cec5SDimitry Andric 19035ffd83dbSDimitry Andric if (!isa<ConstantSDNode>(N->getOperand(OffsetOpIdx))) 1904349cc55cSDimitry Andric return false; 19050b57cec5SDimitry Andric 19060b57cec5SDimitry Andric SDValue Base = N->getOperand(BaseOpIdx); 19070b57cec5SDimitry Andric 19080b57cec5SDimitry Andric // If the base is an ADDI, we can merge it in to the load/store. 19090b57cec5SDimitry Andric if (!Base.isMachineOpcode() || Base.getMachineOpcode() != RISCV::ADDI) 1910349cc55cSDimitry Andric return false; 19110b57cec5SDimitry Andric 19120b57cec5SDimitry Andric SDValue ImmOperand = Base.getOperand(1); 19135ffd83dbSDimitry Andric uint64_t Offset2 = N->getConstantOperandVal(OffsetOpIdx); 19140b57cec5SDimitry Andric 1915fe6060f1SDimitry Andric if (auto *Const = dyn_cast<ConstantSDNode>(ImmOperand)) { 19165ffd83dbSDimitry Andric int64_t Offset1 = Const->getSExtValue(); 19175ffd83dbSDimitry Andric int64_t CombinedOffset = Offset1 + Offset2; 19185ffd83dbSDimitry Andric if (!isInt<12>(CombinedOffset)) 1919349cc55cSDimitry Andric return false; 19205ffd83dbSDimitry Andric ImmOperand = CurDAG->getTargetConstant(CombinedOffset, SDLoc(ImmOperand), 19215ffd83dbSDimitry Andric ImmOperand.getValueType()); 1922fe6060f1SDimitry Andric } else if (auto *GA = dyn_cast<GlobalAddressSDNode>(ImmOperand)) { 19235ffd83dbSDimitry Andric // If the off1 in (addi base, off1) is a global variable's address (its 19245ffd83dbSDimitry Andric // low part, really), then we can rely on the alignment of that variable 19255ffd83dbSDimitry Andric // to provide a margin of safety before off1 can overflow the 12 bits. 19265ffd83dbSDimitry Andric // Check if off2 falls within that margin; if so off1+off2 can't overflow. 19275ffd83dbSDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 19285ffd83dbSDimitry Andric Align Alignment = GA->getGlobal()->getPointerAlignment(DL); 19295ffd83dbSDimitry Andric if (Offset2 != 0 && Alignment <= Offset2) 1930349cc55cSDimitry Andric return false; 19315ffd83dbSDimitry Andric int64_t Offset1 = GA->getOffset(); 19325ffd83dbSDimitry Andric int64_t CombinedOffset = Offset1 + Offset2; 19330b57cec5SDimitry Andric ImmOperand = CurDAG->getTargetGlobalAddress( 19340b57cec5SDimitry Andric GA->getGlobal(), SDLoc(ImmOperand), ImmOperand.getValueType(), 19355ffd83dbSDimitry Andric CombinedOffset, GA->getTargetFlags()); 1936fe6060f1SDimitry Andric } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(ImmOperand)) { 19375ffd83dbSDimitry Andric // Ditto. 19385ffd83dbSDimitry Andric Align Alignment = CP->getAlign(); 19395ffd83dbSDimitry Andric if (Offset2 != 0 && Alignment <= Offset2) 1940349cc55cSDimitry Andric return false; 19415ffd83dbSDimitry Andric int64_t Offset1 = CP->getOffset(); 19425ffd83dbSDimitry Andric int64_t CombinedOffset = Offset1 + Offset2; 19435ffd83dbSDimitry Andric ImmOperand = CurDAG->getTargetConstantPool( 19445ffd83dbSDimitry Andric CP->getConstVal(), ImmOperand.getValueType(), CP->getAlign(), 19455ffd83dbSDimitry Andric CombinedOffset, CP->getTargetFlags()); 19460b57cec5SDimitry Andric } else { 1947349cc55cSDimitry Andric return false; 19480b57cec5SDimitry Andric } 19490b57cec5SDimitry Andric 19500b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Folding add-immediate into mem-op:\nBase: "); 19510b57cec5SDimitry Andric LLVM_DEBUG(Base->dump(CurDAG)); 19520b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\nN: "); 19530b57cec5SDimitry Andric LLVM_DEBUG(N->dump(CurDAG)); 19540b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\n"); 19550b57cec5SDimitry Andric 19560b57cec5SDimitry Andric // Modify the offset operand of the load/store. 19570b57cec5SDimitry Andric if (BaseOpIdx == 0) // Load 19580b57cec5SDimitry Andric CurDAG->UpdateNodeOperands(N, Base.getOperand(0), ImmOperand, 19590b57cec5SDimitry Andric N->getOperand(2)); 19600b57cec5SDimitry Andric else // Store 19610b57cec5SDimitry Andric CurDAG->UpdateNodeOperands(N, N->getOperand(0), Base.getOperand(0), 19620b57cec5SDimitry Andric ImmOperand, N->getOperand(3)); 19630b57cec5SDimitry Andric 1964349cc55cSDimitry Andric return true; 19650b57cec5SDimitry Andric } 1966349cc55cSDimitry Andric 1967349cc55cSDimitry Andric // Try to remove sext.w if the input is a W instruction or can be made into 1968349cc55cSDimitry Andric // a W instruction cheaply. 1969349cc55cSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeSExtW(SDNode *N) { 1970349cc55cSDimitry Andric // Look for the sext.w pattern, addiw rd, rs1, 0. 1971349cc55cSDimitry Andric if (N->getMachineOpcode() != RISCV::ADDIW || 1972349cc55cSDimitry Andric !isNullConstant(N->getOperand(1))) 1973349cc55cSDimitry Andric return false; 1974349cc55cSDimitry Andric 1975349cc55cSDimitry Andric SDValue N0 = N->getOperand(0); 1976349cc55cSDimitry Andric if (!N0.isMachineOpcode()) 1977349cc55cSDimitry Andric return false; 1978349cc55cSDimitry Andric 1979349cc55cSDimitry Andric switch (N0.getMachineOpcode()) { 1980349cc55cSDimitry Andric default: 1981349cc55cSDimitry Andric break; 1982349cc55cSDimitry Andric case RISCV::ADD: 1983349cc55cSDimitry Andric case RISCV::ADDI: 1984349cc55cSDimitry Andric case RISCV::SUB: 1985349cc55cSDimitry Andric case RISCV::MUL: 1986349cc55cSDimitry Andric case RISCV::SLLI: { 1987349cc55cSDimitry Andric // Convert sext.w+add/sub/mul to their W instructions. This will create 1988349cc55cSDimitry Andric // a new independent instruction. This improves latency. 1989349cc55cSDimitry Andric unsigned Opc; 1990349cc55cSDimitry Andric switch (N0.getMachineOpcode()) { 1991349cc55cSDimitry Andric default: 1992349cc55cSDimitry Andric llvm_unreachable("Unexpected opcode!"); 1993349cc55cSDimitry Andric case RISCV::ADD: Opc = RISCV::ADDW; break; 1994349cc55cSDimitry Andric case RISCV::ADDI: Opc = RISCV::ADDIW; break; 1995349cc55cSDimitry Andric case RISCV::SUB: Opc = RISCV::SUBW; break; 1996349cc55cSDimitry Andric case RISCV::MUL: Opc = RISCV::MULW; break; 1997349cc55cSDimitry Andric case RISCV::SLLI: Opc = RISCV::SLLIW; break; 1998349cc55cSDimitry Andric } 1999349cc55cSDimitry Andric 2000349cc55cSDimitry Andric SDValue N00 = N0.getOperand(0); 2001349cc55cSDimitry Andric SDValue N01 = N0.getOperand(1); 2002349cc55cSDimitry Andric 2003349cc55cSDimitry Andric // Shift amount needs to be uimm5. 2004349cc55cSDimitry Andric if (N0.getMachineOpcode() == RISCV::SLLI && 2005349cc55cSDimitry Andric !isUInt<5>(cast<ConstantSDNode>(N01)->getSExtValue())) 2006349cc55cSDimitry Andric break; 2007349cc55cSDimitry Andric 2008349cc55cSDimitry Andric SDNode *Result = 2009349cc55cSDimitry Andric CurDAG->getMachineNode(Opc, SDLoc(N), N->getValueType(0), 2010349cc55cSDimitry Andric N00, N01); 2011349cc55cSDimitry Andric ReplaceUses(N, Result); 2012349cc55cSDimitry Andric return true; 2013349cc55cSDimitry Andric } 2014349cc55cSDimitry Andric case RISCV::ADDW: 2015349cc55cSDimitry Andric case RISCV::ADDIW: 2016349cc55cSDimitry Andric case RISCV::SUBW: 2017349cc55cSDimitry Andric case RISCV::MULW: 2018349cc55cSDimitry Andric case RISCV::SLLIW: 2019349cc55cSDimitry Andric // Result is already sign extended just remove the sext.w. 2020349cc55cSDimitry Andric // NOTE: We only handle the nodes that are selected with hasAllWUsers. 2021349cc55cSDimitry Andric ReplaceUses(N, N0.getNode()); 2022349cc55cSDimitry Andric return true; 2023349cc55cSDimitry Andric } 2024349cc55cSDimitry Andric 2025349cc55cSDimitry Andric return false; 20260b57cec5SDimitry Andric } 20270b57cec5SDimitry Andric 20280b57cec5SDimitry Andric // This pass converts a legalized DAG into a RISCV-specific DAG, ready 20290b57cec5SDimitry Andric // for instruction scheduling. 20300b57cec5SDimitry Andric FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) { 20310b57cec5SDimitry Andric return new RISCVDAGToDAGISel(TM); 20320b57cec5SDimitry Andric } 2033