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