106c3fb27SDimitry Andric //===-- RISCVISelDAGToDAG.cpp - A dag to dag inst selector for RISC-V -----===// 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 // 906c3fb27SDimitry Andric // This file defines an instruction selector for the RISC-V target. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 135ffd83dbSDimitry Andric #include "RISCVISelDAGToDAG.h" 1406c3fb27SDimitry Andric #include "MCTargetDesc/RISCVBaseInfo.h" 150b57cec5SDimitry Andric #include "MCTargetDesc/RISCVMCTargetDesc.h" 16e8d8bef9SDimitry Andric #include "MCTargetDesc/RISCVMatInt.h" 17fe6060f1SDimitry Andric #include "RISCVISelLowering.h" 18fe6060f1SDimitry Andric #include "RISCVMachineFunctionInfo.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 20e8d8bef9SDimitry Andric #include "llvm/IR/IntrinsicsRISCV.h" 215ffd83dbSDimitry Andric #include "llvm/Support/Alignment.h" 220b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 230b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 240b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 25bdd1243dSDimitry Andric #include <optional> 265ffd83dbSDimitry Andric 270b57cec5SDimitry Andric using namespace llvm; 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric #define DEBUG_TYPE "riscv-isel" 3006c3fb27SDimitry Andric #define PASS_NAME "RISC-V DAG->DAG Pattern Instruction Selection" 310b57cec5SDimitry Andric 32bdd1243dSDimitry Andric namespace llvm::RISCV { 33fe6060f1SDimitry Andric #define GET_RISCVVSSEGTable_IMPL 34fe6060f1SDimitry Andric #define GET_RISCVVLSEGTable_IMPL 35fe6060f1SDimitry Andric #define GET_RISCVVLXSEGTable_IMPL 36fe6060f1SDimitry Andric #define GET_RISCVVSXSEGTable_IMPL 37fe6060f1SDimitry Andric #define GET_RISCVVLETable_IMPL 38fe6060f1SDimitry Andric #define GET_RISCVVSETable_IMPL 39fe6060f1SDimitry Andric #define GET_RISCVVLXTable_IMPL 40fe6060f1SDimitry Andric #define GET_RISCVVSXTable_IMPL 4181ad6265SDimitry Andric #define GET_RISCVMaskedPseudosTable_IMPL 42fe6060f1SDimitry Andric #include "RISCVGenSearchableTables.inc" 43bdd1243dSDimitry Andric } // namespace llvm::RISCV 44bdd1243dSDimitry Andric 45fe6060f1SDimitry Andric void RISCVDAGToDAGISel::PreprocessISelDAG() { 46753f127fSDimitry Andric SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); 47fe6060f1SDimitry Andric 48753f127fSDimitry Andric bool MadeChange = false; 49753f127fSDimitry Andric while (Position != CurDAG->allnodes_begin()) { 50753f127fSDimitry Andric SDNode *N = &*--Position; 51753f127fSDimitry Andric if (N->use_empty()) 52753f127fSDimitry Andric continue; 53753f127fSDimitry Andric 54753f127fSDimitry Andric SDValue Result; 55753f127fSDimitry Andric switch (N->getOpcode()) { 56753f127fSDimitry Andric case ISD::SPLAT_VECTOR: { 5781ad6265SDimitry Andric // Convert integer SPLAT_VECTOR to VMV_V_X_VL and floating-point 5881ad6265SDimitry Andric // SPLAT_VECTOR to VFMV_V_F_VL to reduce isel burden. 5981ad6265SDimitry Andric MVT VT = N->getSimpleValueType(0); 6081ad6265SDimitry Andric unsigned Opc = 6181ad6265SDimitry Andric VT.isInteger() ? RISCVISD::VMV_V_X_VL : RISCVISD::VFMV_V_F_VL; 6281ad6265SDimitry Andric SDLoc DL(N); 6381ad6265SDimitry Andric SDValue VL = CurDAG->getRegister(RISCV::X0, Subtarget->getXLenVT()); 64753f127fSDimitry Andric Result = CurDAG->getNode(Opc, DL, VT, CurDAG->getUNDEF(VT), 6581ad6265SDimitry Andric N->getOperand(0), VL); 66753f127fSDimitry Andric break; 6781ad6265SDimitry Andric } 68753f127fSDimitry Andric case RISCVISD::SPLAT_VECTOR_SPLIT_I64_VL: { 69fe6060f1SDimitry Andric // Lower SPLAT_VECTOR_SPLIT_I64 to two scalar stores and a stride 0 vector 70fe6060f1SDimitry Andric // load. Done after lowering and combining so that we have a chance to 71fe6060f1SDimitry Andric // optimize this to VMV_V_X_VL when the upper bits aren't needed. 7281ad6265SDimitry Andric assert(N->getNumOperands() == 4 && "Unexpected number of operands"); 73fe6060f1SDimitry Andric MVT VT = N->getSimpleValueType(0); 7481ad6265SDimitry Andric SDValue Passthru = N->getOperand(0); 7581ad6265SDimitry Andric SDValue Lo = N->getOperand(1); 7681ad6265SDimitry Andric SDValue Hi = N->getOperand(2); 7781ad6265SDimitry Andric SDValue VL = N->getOperand(3); 78fe6060f1SDimitry Andric assert(VT.getVectorElementType() == MVT::i64 && VT.isScalableVector() && 79fe6060f1SDimitry Andric Lo.getValueType() == MVT::i32 && Hi.getValueType() == MVT::i32 && 80fe6060f1SDimitry Andric "Unexpected VTs!"); 81fe6060f1SDimitry Andric MachineFunction &MF = CurDAG->getMachineFunction(); 82fe6060f1SDimitry Andric SDLoc DL(N); 83fe6060f1SDimitry Andric 8406c3fb27SDimitry Andric // Create temporary stack for each expanding node. 85fe6060f1SDimitry Andric SDValue StackSlot = 8606c3fb27SDimitry Andric CurDAG->CreateStackTemporary(TypeSize::Fixed(8), Align(4)); 8706c3fb27SDimitry Andric int FI = cast<FrameIndexSDNode>(StackSlot.getNode())->getIndex(); 8806c3fb27SDimitry Andric MachinePointerInfo MPI = MachinePointerInfo::getFixedStack(MF, FI); 89fe6060f1SDimitry Andric 90fe6060f1SDimitry Andric SDValue Chain = CurDAG->getEntryNode(); 91fe6060f1SDimitry Andric Lo = CurDAG->getStore(Chain, DL, Lo, StackSlot, MPI, Align(8)); 92fe6060f1SDimitry Andric 93fe6060f1SDimitry Andric SDValue OffsetSlot = 94fe6060f1SDimitry Andric CurDAG->getMemBasePlusOffset(StackSlot, TypeSize::Fixed(4), DL); 95fe6060f1SDimitry Andric Hi = CurDAG->getStore(Chain, DL, Hi, OffsetSlot, MPI.getWithOffset(4), 96fe6060f1SDimitry Andric Align(8)); 97fe6060f1SDimitry Andric 98fe6060f1SDimitry Andric Chain = CurDAG->getNode(ISD::TokenFactor, DL, MVT::Other, Lo, Hi); 99fe6060f1SDimitry Andric 100fe6060f1SDimitry Andric SDVTList VTs = CurDAG->getVTList({VT, MVT::Other}); 101fe6060f1SDimitry Andric SDValue IntID = 102fe6060f1SDimitry Andric CurDAG->getTargetConstant(Intrinsic::riscv_vlse, DL, MVT::i64); 10304eeddc0SDimitry Andric SDValue Ops[] = {Chain, 10404eeddc0SDimitry Andric IntID, 10581ad6265SDimitry Andric Passthru, 10604eeddc0SDimitry Andric StackSlot, 10704eeddc0SDimitry Andric CurDAG->getRegister(RISCV::X0, MVT::i64), 10804eeddc0SDimitry Andric VL}; 109fe6060f1SDimitry Andric 110753f127fSDimitry Andric Result = CurDAG->getMemIntrinsicNode(ISD::INTRINSIC_W_CHAIN, DL, VTs, Ops, 111753f127fSDimitry Andric MVT::i64, MPI, Align(8), 112fe6060f1SDimitry Andric MachineMemOperand::MOLoad); 113753f127fSDimitry Andric break; 114fe6060f1SDimitry Andric } 115fe6060f1SDimitry Andric } 116fe6060f1SDimitry Andric 117753f127fSDimitry Andric if (Result) { 11806c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "RISC-V DAG preprocessing replacing:\nOld: "); 119753f127fSDimitry Andric LLVM_DEBUG(N->dump(CurDAG)); 120753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "\nNew: "); 121753f127fSDimitry Andric LLVM_DEBUG(Result->dump(CurDAG)); 122753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "\n"); 123753f127fSDimitry Andric 124753f127fSDimitry Andric CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0), Result); 125753f127fSDimitry Andric MadeChange = true; 126753f127fSDimitry Andric } 127753f127fSDimitry Andric } 128753f127fSDimitry Andric 129753f127fSDimitry Andric if (MadeChange) 130753f127fSDimitry Andric CurDAG->RemoveDeadNodes(); 131753f127fSDimitry Andric } 132753f127fSDimitry Andric 1330b57cec5SDimitry Andric void RISCVDAGToDAGISel::PostprocessISelDAG() { 13481ad6265SDimitry Andric HandleSDNode Dummy(CurDAG->getRoot()); 135349cc55cSDimitry Andric SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); 136349cc55cSDimitry Andric 137349cc55cSDimitry Andric bool MadeChange = false; 138349cc55cSDimitry Andric while (Position != CurDAG->allnodes_begin()) { 139349cc55cSDimitry Andric SDNode *N = &*--Position; 140349cc55cSDimitry Andric // Skip dead nodes and any non-machine opcodes. 141349cc55cSDimitry Andric if (N->use_empty() || !N->isMachineOpcode()) 142349cc55cSDimitry Andric continue; 143349cc55cSDimitry Andric 144349cc55cSDimitry Andric MadeChange |= doPeepholeSExtW(N); 14581ad6265SDimitry Andric MadeChange |= doPeepholeMaskedRVV(N); 146349cc55cSDimitry Andric } 147349cc55cSDimitry Andric 14881ad6265SDimitry Andric CurDAG->setRoot(Dummy.getValue()); 14981ad6265SDimitry Andric 150bdd1243dSDimitry Andric MadeChange |= doPeepholeMergeVVMFold(); 151bdd1243dSDimitry Andric 152349cc55cSDimitry Andric if (MadeChange) 153349cc55cSDimitry Andric CurDAG->RemoveDeadNodes(); 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric 15606c3fb27SDimitry Andric static SDValue selectImmSeq(SelectionDAG *CurDAG, const SDLoc &DL, const MVT VT, 15781ad6265SDimitry Andric RISCVMatInt::InstSeq &Seq) { 15881ad6265SDimitry Andric SDValue SrcReg = CurDAG->getRegister(RISCV::X0, VT); 15906c3fb27SDimitry Andric for (const RISCVMatInt::Inst &Inst : Seq) { 160bdd1243dSDimitry Andric SDValue SDImm = CurDAG->getTargetConstant(Inst.getImm(), DL, VT); 16106c3fb27SDimitry Andric SDNode *Result = nullptr; 16281ad6265SDimitry Andric switch (Inst.getOpndKind()) { 16381ad6265SDimitry Andric case RISCVMatInt::Imm: 164bdd1243dSDimitry Andric Result = CurDAG->getMachineNode(Inst.getOpcode(), DL, VT, SDImm); 16581ad6265SDimitry Andric break; 16681ad6265SDimitry Andric case RISCVMatInt::RegX0: 167bdd1243dSDimitry Andric Result = CurDAG->getMachineNode(Inst.getOpcode(), DL, VT, SrcReg, 16881ad6265SDimitry Andric CurDAG->getRegister(RISCV::X0, VT)); 16981ad6265SDimitry Andric break; 17081ad6265SDimitry Andric case RISCVMatInt::RegReg: 171bdd1243dSDimitry Andric Result = CurDAG->getMachineNode(Inst.getOpcode(), DL, VT, SrcReg, SrcReg); 17281ad6265SDimitry Andric break; 17381ad6265SDimitry Andric case RISCVMatInt::RegImm: 174bdd1243dSDimitry Andric Result = CurDAG->getMachineNode(Inst.getOpcode(), DL, VT, SrcReg, SDImm); 17581ad6265SDimitry Andric break; 17681ad6265SDimitry Andric } 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric // Only the first instruction has X0 as its source. 1790b57cec5SDimitry Andric SrcReg = SDValue(Result, 0); 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 18206c3fb27SDimitry Andric return SrcReg; 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric 18506c3fb27SDimitry Andric static SDValue selectImm(SelectionDAG *CurDAG, const SDLoc &DL, const MVT VT, 18681ad6265SDimitry Andric int64_t Imm, const RISCVSubtarget &Subtarget) { 18781ad6265SDimitry Andric RISCVMatInt::InstSeq Seq = 18881ad6265SDimitry Andric RISCVMatInt::generateInstSeq(Imm, Subtarget.getFeatureBits()); 18981ad6265SDimitry Andric 19006c3fb27SDimitry Andric // See if we can create this constant as (ADD (SLLI X, 32), X) where X is at 19106c3fb27SDimitry Andric // worst an LUI+ADDIW. This will require an extra register, but avoids a 19206c3fb27SDimitry Andric // constant pool. 19306c3fb27SDimitry Andric if (Seq.size() > 3) { 19406c3fb27SDimitry Andric int64_t LoVal = SignExtend64<32>(Imm); 19506c3fb27SDimitry Andric int64_t HiVal = SignExtend64<32>(((uint64_t)Imm - (uint64_t)LoVal) >> 32); 19606c3fb27SDimitry Andric if (LoVal == HiVal) { 19706c3fb27SDimitry Andric RISCVMatInt::InstSeq SeqLo = 19806c3fb27SDimitry Andric RISCVMatInt::generateInstSeq(LoVal, Subtarget.getFeatureBits()); 19906c3fb27SDimitry Andric if ((SeqLo.size() + 2) < Seq.size()) { 20006c3fb27SDimitry Andric SDValue Lo = selectImmSeq(CurDAG, DL, VT, SeqLo); 20106c3fb27SDimitry Andric 20206c3fb27SDimitry Andric SDValue SLLI = SDValue( 20306c3fb27SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, Lo, 20406c3fb27SDimitry Andric CurDAG->getTargetConstant(32, DL, VT)), 20506c3fb27SDimitry Andric 0); 20606c3fb27SDimitry Andric return SDValue(CurDAG->getMachineNode(RISCV::ADD, DL, VT, Lo, SLLI), 20706c3fb27SDimitry Andric 0); 20806c3fb27SDimitry Andric } 20906c3fb27SDimitry Andric } 21006c3fb27SDimitry Andric } 21106c3fb27SDimitry Andric 21206c3fb27SDimitry Andric // Otherwise, use the original sequence. 21381ad6265SDimitry Andric return selectImmSeq(CurDAG, DL, VT, Seq); 21481ad6265SDimitry Andric } 21581ad6265SDimitry Andric 21681ad6265SDimitry Andric static SDValue createTuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs, 21781ad6265SDimitry Andric unsigned NF, RISCVII::VLMUL LMUL) { 21881ad6265SDimitry Andric static const unsigned M1TupleRegClassIDs[] = { 21981ad6265SDimitry Andric RISCV::VRN2M1RegClassID, RISCV::VRN3M1RegClassID, RISCV::VRN4M1RegClassID, 22081ad6265SDimitry Andric RISCV::VRN5M1RegClassID, RISCV::VRN6M1RegClassID, RISCV::VRN7M1RegClassID, 22181ad6265SDimitry Andric RISCV::VRN8M1RegClassID}; 22281ad6265SDimitry Andric static const unsigned M2TupleRegClassIDs[] = {RISCV::VRN2M2RegClassID, 22381ad6265SDimitry Andric RISCV::VRN3M2RegClassID, 22481ad6265SDimitry Andric RISCV::VRN4M2RegClassID}; 22581ad6265SDimitry Andric 226e8d8bef9SDimitry Andric assert(Regs.size() >= 2 && Regs.size() <= 8); 227e8d8bef9SDimitry Andric 22881ad6265SDimitry Andric unsigned RegClassID; 22981ad6265SDimitry Andric unsigned SubReg0; 23081ad6265SDimitry Andric switch (LMUL) { 23181ad6265SDimitry Andric default: 23281ad6265SDimitry Andric llvm_unreachable("Invalid LMUL."); 23381ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_F8: 23481ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_F4: 23581ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_F2: 23681ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_1: 23781ad6265SDimitry Andric static_assert(RISCV::sub_vrm1_7 == RISCV::sub_vrm1_0 + 7, 23881ad6265SDimitry Andric "Unexpected subreg numbering"); 23981ad6265SDimitry Andric SubReg0 = RISCV::sub_vrm1_0; 24081ad6265SDimitry Andric RegClassID = M1TupleRegClassIDs[NF - 2]; 24181ad6265SDimitry Andric break; 24281ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_2: 24381ad6265SDimitry Andric static_assert(RISCV::sub_vrm2_3 == RISCV::sub_vrm2_0 + 3, 24481ad6265SDimitry Andric "Unexpected subreg numbering"); 24581ad6265SDimitry Andric SubReg0 = RISCV::sub_vrm2_0; 24681ad6265SDimitry Andric RegClassID = M2TupleRegClassIDs[NF - 2]; 24781ad6265SDimitry Andric break; 24881ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_4: 24981ad6265SDimitry Andric static_assert(RISCV::sub_vrm4_1 == RISCV::sub_vrm4_0 + 1, 25081ad6265SDimitry Andric "Unexpected subreg numbering"); 25181ad6265SDimitry Andric SubReg0 = RISCV::sub_vrm4_0; 25281ad6265SDimitry Andric RegClassID = RISCV::VRN2M4RegClassID; 25381ad6265SDimitry Andric break; 25481ad6265SDimitry Andric } 25581ad6265SDimitry Andric 256e8d8bef9SDimitry Andric SDLoc DL(Regs[0]); 257e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Ops; 258e8d8bef9SDimitry Andric 259e8d8bef9SDimitry Andric Ops.push_back(CurDAG.getTargetConstant(RegClassID, DL, MVT::i32)); 260e8d8bef9SDimitry Andric 261e8d8bef9SDimitry Andric for (unsigned I = 0; I < Regs.size(); ++I) { 262e8d8bef9SDimitry Andric Ops.push_back(Regs[I]); 263e8d8bef9SDimitry Andric Ops.push_back(CurDAG.getTargetConstant(SubReg0 + I, DL, MVT::i32)); 264e8d8bef9SDimitry Andric } 265e8d8bef9SDimitry Andric SDNode *N = 266e8d8bef9SDimitry Andric CurDAG.getMachineNode(TargetOpcode::REG_SEQUENCE, DL, MVT::Untyped, Ops); 267e8d8bef9SDimitry Andric return SDValue(N, 0); 268e8d8bef9SDimitry Andric } 269e8d8bef9SDimitry Andric 270fe6060f1SDimitry Andric void RISCVDAGToDAGISel::addVectorLoadStoreOperands( 271fe6060f1SDimitry Andric SDNode *Node, unsigned Log2SEW, const SDLoc &DL, unsigned CurOp, 272fe6060f1SDimitry Andric bool IsMasked, bool IsStridedOrIndexed, SmallVectorImpl<SDValue> &Operands, 273349cc55cSDimitry Andric bool IsLoad, MVT *IndexVT) { 274fe6060f1SDimitry Andric SDValue Chain = Node->getOperand(0); 275fe6060f1SDimitry Andric SDValue Glue; 276fe6060f1SDimitry Andric 277753f127fSDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Base pointer. 278fe6060f1SDimitry Andric 279fe6060f1SDimitry Andric if (IsStridedOrIndexed) { 280fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Index. 281fe6060f1SDimitry Andric if (IndexVT) 282fe6060f1SDimitry Andric *IndexVT = Operands.back()->getSimpleValueType(0); 283fe6060f1SDimitry Andric } 284fe6060f1SDimitry Andric 285fe6060f1SDimitry Andric if (IsMasked) { 286fe6060f1SDimitry Andric // Mask needs to be copied to V0. 287fe6060f1SDimitry Andric SDValue Mask = Node->getOperand(CurOp++); 288fe6060f1SDimitry Andric Chain = CurDAG->getCopyToReg(Chain, DL, RISCV::V0, Mask, SDValue()); 289fe6060f1SDimitry Andric Glue = Chain.getValue(1); 290fe6060f1SDimitry Andric Operands.push_back(CurDAG->getRegister(RISCV::V0, Mask.getValueType())); 291fe6060f1SDimitry Andric } 292fe6060f1SDimitry Andric SDValue VL; 293fe6060f1SDimitry Andric selectVLOp(Node->getOperand(CurOp++), VL); 294fe6060f1SDimitry Andric Operands.push_back(VL); 295fe6060f1SDimitry Andric 296fe6060f1SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 297fe6060f1SDimitry Andric SDValue SEWOp = CurDAG->getTargetConstant(Log2SEW, DL, XLenVT); 298fe6060f1SDimitry Andric Operands.push_back(SEWOp); 299fe6060f1SDimitry Andric 30006c3fb27SDimitry Andric // At the IR layer, all the masked load intrinsics have policy operands, 30106c3fb27SDimitry Andric // none of the others do. All have passthru operands. For our pseudos, 30206c3fb27SDimitry Andric // all loads have policy operands. 30306c3fb27SDimitry Andric if (IsLoad) { 30406c3fb27SDimitry Andric uint64_t Policy = RISCVII::MASK_AGNOSTIC; 30506c3fb27SDimitry Andric if (IsMasked) 30606c3fb27SDimitry Andric Policy = Node->getConstantOperandVal(CurOp++); 307349cc55cSDimitry Andric SDValue PolicyOp = CurDAG->getTargetConstant(Policy, DL, XLenVT); 308349cc55cSDimitry Andric Operands.push_back(PolicyOp); 309349cc55cSDimitry Andric } 310349cc55cSDimitry Andric 311fe6060f1SDimitry Andric Operands.push_back(Chain); // Chain. 312fe6060f1SDimitry Andric if (Glue) 313fe6060f1SDimitry Andric Operands.push_back(Glue); 314fe6060f1SDimitry Andric } 315fe6060f1SDimitry Andric 316fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLSEG(SDNode *Node, bool IsMasked, 317e8d8bef9SDimitry Andric bool IsStrided) { 318e8d8bef9SDimitry Andric SDLoc DL(Node); 319e8d8bef9SDimitry Andric unsigned NF = Node->getNumValues() - 1; 320fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 321fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 322fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 323e8d8bef9SDimitry Andric 324fe6060f1SDimitry Andric unsigned CurOp = 2; 325fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 32681ad6265SDimitry Andric 327fe6060f1SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp, 328fe6060f1SDimitry Andric Node->op_begin() + CurOp + NF); 32981ad6265SDimitry Andric SDValue Merge = createTuple(*CurDAG, Regs, NF, LMUL); 33081ad6265SDimitry Andric Operands.push_back(Merge); 33181ad6265SDimitry Andric CurOp += NF; 332fe6060f1SDimitry Andric 333fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 334349cc55cSDimitry Andric Operands, /*IsLoad=*/true); 335fe6060f1SDimitry Andric 336fe6060f1SDimitry Andric const RISCV::VLSEGPseudo *P = 33706c3fb27SDimitry Andric RISCV::getVLSEGPseudo(NF, IsMasked, IsStrided, /*FF*/ false, Log2SEW, 338fe6060f1SDimitry Andric static_cast<unsigned>(LMUL)); 339fe6060f1SDimitry Andric MachineSDNode *Load = 340e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands); 341fe6060f1SDimitry Andric 342fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 343fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 344fe6060f1SDimitry Andric 345e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 346fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) { 347fe6060f1SDimitry Andric unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I); 348e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 349fe6060f1SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg)); 350fe6060f1SDimitry Andric } 351e8d8bef9SDimitry Andric 352e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); 353e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 354e8d8bef9SDimitry Andric } 355e8d8bef9SDimitry Andric 356fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLSEGFF(SDNode *Node, bool IsMasked) { 357e8d8bef9SDimitry Andric SDLoc DL(Node); 358fe6060f1SDimitry Andric unsigned NF = Node->getNumValues() - 2; // Do not count VL and Chain. 359fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 360e8d8bef9SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 361fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 362fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 363e8d8bef9SDimitry Andric 364fe6060f1SDimitry Andric unsigned CurOp = 2; 365e8d8bef9SDimitry Andric SmallVector<SDValue, 7> Operands; 36681ad6265SDimitry Andric 367fe6060f1SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp, 368fe6060f1SDimitry Andric Node->op_begin() + CurOp + NF); 369e8d8bef9SDimitry Andric SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL); 370fe6060f1SDimitry Andric Operands.push_back(MaskedOff); 37181ad6265SDimitry Andric CurOp += NF; 372e8d8bef9SDimitry Andric 373fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 374349cc55cSDimitry Andric /*IsStridedOrIndexed*/ false, Operands, 375349cc55cSDimitry Andric /*IsLoad=*/true); 376fe6060f1SDimitry Andric 377fe6060f1SDimitry Andric const RISCV::VLSEGPseudo *P = 37806c3fb27SDimitry Andric RISCV::getVLSEGPseudo(NF, IsMasked, /*Strided*/ false, /*FF*/ true, 379fe6060f1SDimitry Andric Log2SEW, static_cast<unsigned>(LMUL)); 380fe6060f1SDimitry Andric MachineSDNode *Load = CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, 38181ad6265SDimitry Andric XLenVT, MVT::Other, Operands); 382fe6060f1SDimitry Andric 383fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 384fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 385fe6060f1SDimitry Andric 386e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 387fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) { 388fe6060f1SDimitry Andric unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I); 389e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 390fe6060f1SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg)); 391fe6060f1SDimitry Andric } 392fe6060f1SDimitry Andric 39381ad6265SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); // VL 39481ad6265SDimitry Andric ReplaceUses(SDValue(Node, NF + 1), SDValue(Load, 2)); // Chain 395fe6060f1SDimitry Andric CurDAG->RemoveDeadNode(Node); 396fe6060f1SDimitry Andric } 397fe6060f1SDimitry Andric 398fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLXSEG(SDNode *Node, bool IsMasked, 399fe6060f1SDimitry Andric bool IsOrdered) { 400fe6060f1SDimitry Andric SDLoc DL(Node); 401fe6060f1SDimitry Andric unsigned NF = Node->getNumValues() - 1; 402fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 403fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 404fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 405fe6060f1SDimitry Andric 406fe6060f1SDimitry Andric unsigned CurOp = 2; 407fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 40881ad6265SDimitry Andric 409fe6060f1SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp, 410fe6060f1SDimitry Andric Node->op_begin() + CurOp + NF); 411fe6060f1SDimitry Andric SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL); 412fe6060f1SDimitry Andric Operands.push_back(MaskedOff); 41381ad6265SDimitry Andric CurOp += NF; 414fe6060f1SDimitry Andric 415fe6060f1SDimitry Andric MVT IndexVT; 416fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 417349cc55cSDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 418349cc55cSDimitry Andric /*IsLoad=*/true, &IndexVT); 419fe6060f1SDimitry Andric 420fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 421fe6060f1SDimitry Andric "Element count mismatch"); 422fe6060f1SDimitry Andric 423fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 424fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 42504eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 42604eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 42704eeddc0SDimitry Andric "values when XLEN=32"); 42804eeddc0SDimitry Andric } 429fe6060f1SDimitry Andric const RISCV::VLXSEGPseudo *P = RISCV::getVLXSEGPseudo( 43006c3fb27SDimitry Andric NF, IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 431fe6060f1SDimitry Andric static_cast<unsigned>(IndexLMUL)); 432fe6060f1SDimitry Andric MachineSDNode *Load = 433fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands); 434fe6060f1SDimitry Andric 435fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 436fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 437fe6060f1SDimitry Andric 438fe6060f1SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 439fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) { 440fe6060f1SDimitry Andric unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I); 441fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, I), 442fe6060f1SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg)); 443fe6060f1SDimitry Andric } 444e8d8bef9SDimitry Andric 445e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); 446e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 447e8d8bef9SDimitry Andric } 448e8d8bef9SDimitry Andric 449fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVSSEG(SDNode *Node, bool IsMasked, 450e8d8bef9SDimitry Andric bool IsStrided) { 451e8d8bef9SDimitry Andric SDLoc DL(Node); 452e8d8bef9SDimitry Andric unsigned NF = Node->getNumOperands() - 4; 453e8d8bef9SDimitry Andric if (IsStrided) 454e8d8bef9SDimitry Andric NF--; 455fe6060f1SDimitry Andric if (IsMasked) 456e8d8bef9SDimitry Andric NF--; 457fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 458fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 459fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 460e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 461e8d8bef9SDimitry Andric SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL); 462fe6060f1SDimitry Andric 463fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 464e8d8bef9SDimitry Andric Operands.push_back(StoreVal); 465fe6060f1SDimitry Andric unsigned CurOp = 2 + NF; 466fe6060f1SDimitry Andric 467fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 468fe6060f1SDimitry Andric Operands); 469fe6060f1SDimitry Andric 470fe6060f1SDimitry Andric const RISCV::VSSEGPseudo *P = RISCV::getVSSEGPseudo( 471fe6060f1SDimitry Andric NF, IsMasked, IsStrided, Log2SEW, static_cast<unsigned>(LMUL)); 472fe6060f1SDimitry Andric MachineSDNode *Store = 473e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands); 474fe6060f1SDimitry Andric 475fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 476fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 477fe6060f1SDimitry Andric 478e8d8bef9SDimitry Andric ReplaceNode(Node, Store); 479e8d8bef9SDimitry Andric } 480e8d8bef9SDimitry Andric 481fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVSXSEG(SDNode *Node, bool IsMasked, 482fe6060f1SDimitry Andric bool IsOrdered) { 483e8d8bef9SDimitry Andric SDLoc DL(Node); 484e8d8bef9SDimitry Andric unsigned NF = Node->getNumOperands() - 5; 485fe6060f1SDimitry Andric if (IsMasked) 486fe6060f1SDimitry Andric --NF; 487fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 488fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 489fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 490e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 491e8d8bef9SDimitry Andric SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL); 492e8d8bef9SDimitry Andric 493fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 494fe6060f1SDimitry Andric Operands.push_back(StoreVal); 495fe6060f1SDimitry Andric unsigned CurOp = 2 + NF; 496fe6060f1SDimitry Andric 497fe6060f1SDimitry Andric MVT IndexVT; 498fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 499349cc55cSDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 500349cc55cSDimitry Andric /*IsLoad=*/false, &IndexVT); 501fe6060f1SDimitry Andric 502fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 503fe6060f1SDimitry Andric "Element count mismatch"); 504fe6060f1SDimitry Andric 505fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 506fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 50704eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 50804eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 50904eeddc0SDimitry Andric "values when XLEN=32"); 51004eeddc0SDimitry Andric } 511fe6060f1SDimitry Andric const RISCV::VSXSEGPseudo *P = RISCV::getVSXSEGPseudo( 512fe6060f1SDimitry Andric NF, IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 513e8d8bef9SDimitry Andric static_cast<unsigned>(IndexLMUL)); 514fe6060f1SDimitry Andric MachineSDNode *Store = 515e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands); 516fe6060f1SDimitry Andric 517fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 518fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 519fe6060f1SDimitry Andric 520e8d8bef9SDimitry Andric ReplaceNode(Node, Store); 521e8d8bef9SDimitry Andric } 522e8d8bef9SDimitry Andric 52304eeddc0SDimitry Andric void RISCVDAGToDAGISel::selectVSETVLI(SDNode *Node) { 52404eeddc0SDimitry Andric if (!Subtarget->hasVInstructions()) 52504eeddc0SDimitry Andric return; 52604eeddc0SDimitry Andric 52706c3fb27SDimitry Andric assert(Node->getOpcode() == ISD::INTRINSIC_WO_CHAIN && "Unexpected opcode"); 52804eeddc0SDimitry Andric 52904eeddc0SDimitry Andric SDLoc DL(Node); 53004eeddc0SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 53104eeddc0SDimitry Andric 53206c3fb27SDimitry Andric unsigned IntNo = Node->getConstantOperandVal(0); 53304eeddc0SDimitry Andric 53404eeddc0SDimitry Andric assert((IntNo == Intrinsic::riscv_vsetvli || 53506c3fb27SDimitry Andric IntNo == Intrinsic::riscv_vsetvlimax) && 53604eeddc0SDimitry Andric "Unexpected vsetvli intrinsic"); 53704eeddc0SDimitry Andric 53806c3fb27SDimitry Andric bool VLMax = IntNo == Intrinsic::riscv_vsetvlimax; 53906c3fb27SDimitry Andric unsigned Offset = (VLMax ? 1 : 2); 54004eeddc0SDimitry Andric 54104eeddc0SDimitry Andric assert(Node->getNumOperands() == Offset + 2 && 54204eeddc0SDimitry Andric "Unexpected number of operands"); 54304eeddc0SDimitry Andric 54404eeddc0SDimitry Andric unsigned SEW = 54504eeddc0SDimitry Andric RISCVVType::decodeVSEW(Node->getConstantOperandVal(Offset) & 0x7); 54604eeddc0SDimitry Andric RISCVII::VLMUL VLMul = static_cast<RISCVII::VLMUL>( 54704eeddc0SDimitry Andric Node->getConstantOperandVal(Offset + 1) & 0x7); 54804eeddc0SDimitry Andric 54904eeddc0SDimitry Andric unsigned VTypeI = RISCVVType::encodeVTYPE(VLMul, SEW, /*TailAgnostic*/ true, 55006c3fb27SDimitry Andric /*MaskAgnostic*/ true); 55104eeddc0SDimitry Andric SDValue VTypeIOp = CurDAG->getTargetConstant(VTypeI, DL, XLenVT); 55204eeddc0SDimitry Andric 55304eeddc0SDimitry Andric SDValue VLOperand; 55404eeddc0SDimitry Andric unsigned Opcode = RISCV::PseudoVSETVLI; 55506c3fb27SDimitry Andric if (VLMax || isAllOnesConstant(Node->getOperand(1))) { 55604eeddc0SDimitry Andric VLOperand = CurDAG->getRegister(RISCV::X0, XLenVT); 55704eeddc0SDimitry Andric Opcode = RISCV::PseudoVSETVLIX0; 55804eeddc0SDimitry Andric } else { 55906c3fb27SDimitry Andric VLOperand = Node->getOperand(1); 56004eeddc0SDimitry Andric 56104eeddc0SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(VLOperand)) { 56204eeddc0SDimitry Andric uint64_t AVL = C->getZExtValue(); 56304eeddc0SDimitry Andric if (isUInt<5>(AVL)) { 56404eeddc0SDimitry Andric SDValue VLImm = CurDAG->getTargetConstant(AVL, DL, XLenVT); 56506c3fb27SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(RISCV::PseudoVSETIVLI, DL, 56606c3fb27SDimitry Andric XLenVT, VLImm, VTypeIOp)); 56704eeddc0SDimitry Andric return; 56804eeddc0SDimitry Andric } 56904eeddc0SDimitry Andric } 57004eeddc0SDimitry Andric } 57104eeddc0SDimitry Andric 57206c3fb27SDimitry Andric ReplaceNode(Node, 57306c3fb27SDimitry Andric CurDAG->getMachineNode(Opcode, DL, XLenVT, VLOperand, VTypeIOp)); 57404eeddc0SDimitry Andric } 5750b57cec5SDimitry Andric 576bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::tryShrinkShlLogicImm(SDNode *Node) { 577bdd1243dSDimitry Andric MVT VT = Node->getSimpleValueType(0); 578bdd1243dSDimitry Andric unsigned Opcode = Node->getOpcode(); 579bdd1243dSDimitry Andric assert((Opcode == ISD::AND || Opcode == ISD::OR || Opcode == ISD::XOR) && 580bdd1243dSDimitry Andric "Unexpected opcode"); 581bdd1243dSDimitry Andric SDLoc DL(Node); 582bdd1243dSDimitry Andric 583bdd1243dSDimitry Andric // For operations of the form (x << C1) op C2, check if we can use 584bdd1243dSDimitry Andric // ANDI/ORI/XORI by transforming it into (x op (C2>>C1)) << C1. 585bdd1243dSDimitry Andric SDValue N0 = Node->getOperand(0); 586bdd1243dSDimitry Andric SDValue N1 = Node->getOperand(1); 587bdd1243dSDimitry Andric 588bdd1243dSDimitry Andric ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(N1); 589bdd1243dSDimitry Andric if (!Cst) 590bdd1243dSDimitry Andric return false; 591bdd1243dSDimitry Andric 592bdd1243dSDimitry Andric int64_t Val = Cst->getSExtValue(); 593bdd1243dSDimitry Andric 594bdd1243dSDimitry Andric // Check if immediate can already use ANDI/ORI/XORI. 595bdd1243dSDimitry Andric if (isInt<12>(Val)) 596bdd1243dSDimitry Andric return false; 597bdd1243dSDimitry Andric 598bdd1243dSDimitry Andric SDValue Shift = N0; 599bdd1243dSDimitry Andric 600bdd1243dSDimitry Andric // If Val is simm32 and we have a sext_inreg from i32, then the binop 601bdd1243dSDimitry Andric // produces at least 33 sign bits. We can peek through the sext_inreg and use 602bdd1243dSDimitry Andric // a SLLIW at the end. 603bdd1243dSDimitry Andric bool SignExt = false; 604bdd1243dSDimitry Andric if (isInt<32>(Val) && N0.getOpcode() == ISD::SIGN_EXTEND_INREG && 605bdd1243dSDimitry Andric N0.hasOneUse() && cast<VTSDNode>(N0.getOperand(1))->getVT() == MVT::i32) { 606bdd1243dSDimitry Andric SignExt = true; 607bdd1243dSDimitry Andric Shift = N0.getOperand(0); 608bdd1243dSDimitry Andric } 609bdd1243dSDimitry Andric 610bdd1243dSDimitry Andric if (Shift.getOpcode() != ISD::SHL || !Shift.hasOneUse()) 611bdd1243dSDimitry Andric return false; 612bdd1243dSDimitry Andric 613bdd1243dSDimitry Andric ConstantSDNode *ShlCst = dyn_cast<ConstantSDNode>(Shift.getOperand(1)); 614bdd1243dSDimitry Andric if (!ShlCst) 615bdd1243dSDimitry Andric return false; 616bdd1243dSDimitry Andric 617bdd1243dSDimitry Andric uint64_t ShAmt = ShlCst->getZExtValue(); 618bdd1243dSDimitry Andric 619bdd1243dSDimitry Andric // Make sure that we don't change the operation by removing bits. 620bdd1243dSDimitry Andric // This only matters for OR and XOR, AND is unaffected. 621bdd1243dSDimitry Andric uint64_t RemovedBitsMask = maskTrailingOnes<uint64_t>(ShAmt); 622bdd1243dSDimitry Andric if (Opcode != ISD::AND && (Val & RemovedBitsMask) != 0) 623bdd1243dSDimitry Andric return false; 624bdd1243dSDimitry Andric 625bdd1243dSDimitry Andric int64_t ShiftedVal = Val >> ShAmt; 626bdd1243dSDimitry Andric if (!isInt<12>(ShiftedVal)) 627bdd1243dSDimitry Andric return false; 628bdd1243dSDimitry Andric 629bdd1243dSDimitry Andric // If we peeked through a sext_inreg, make sure the shift is valid for SLLIW. 630bdd1243dSDimitry Andric if (SignExt && ShAmt >= 32) 631bdd1243dSDimitry Andric return false; 632bdd1243dSDimitry Andric 633bdd1243dSDimitry Andric // Ok, we can reorder to get a smaller immediate. 634bdd1243dSDimitry Andric unsigned BinOpc; 635bdd1243dSDimitry Andric switch (Opcode) { 636bdd1243dSDimitry Andric default: llvm_unreachable("Unexpected opcode"); 637bdd1243dSDimitry Andric case ISD::AND: BinOpc = RISCV::ANDI; break; 638bdd1243dSDimitry Andric case ISD::OR: BinOpc = RISCV::ORI; break; 639bdd1243dSDimitry Andric case ISD::XOR: BinOpc = RISCV::XORI; break; 640bdd1243dSDimitry Andric } 641bdd1243dSDimitry Andric 642bdd1243dSDimitry Andric unsigned ShOpc = SignExt ? RISCV::SLLIW : RISCV::SLLI; 643bdd1243dSDimitry Andric 644bdd1243dSDimitry Andric SDNode *BinOp = 645bdd1243dSDimitry Andric CurDAG->getMachineNode(BinOpc, DL, VT, Shift.getOperand(0), 646bdd1243dSDimitry Andric CurDAG->getTargetConstant(ShiftedVal, DL, VT)); 647bdd1243dSDimitry Andric SDNode *SLLI = 648bdd1243dSDimitry Andric CurDAG->getMachineNode(ShOpc, DL, VT, SDValue(BinOp, 0), 649bdd1243dSDimitry Andric CurDAG->getTargetConstant(ShAmt, DL, VT)); 650bdd1243dSDimitry Andric ReplaceNode(Node, SLLI); 651bdd1243dSDimitry Andric return true; 652bdd1243dSDimitry Andric } 653bdd1243dSDimitry Andric 65406c3fb27SDimitry Andric bool RISCVDAGToDAGISel::trySignedBitfieldExtract(SDNode *Node) { 65506c3fb27SDimitry Andric // Only supported with XTHeadBb at the moment. 65606c3fb27SDimitry Andric if (!Subtarget->hasVendorXTHeadBb()) 65706c3fb27SDimitry Andric return false; 65806c3fb27SDimitry Andric 65906c3fb27SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 66006c3fb27SDimitry Andric if (!N1C) 66106c3fb27SDimitry Andric return false; 66206c3fb27SDimitry Andric 66306c3fb27SDimitry Andric SDValue N0 = Node->getOperand(0); 66406c3fb27SDimitry Andric if (!N0.hasOneUse()) 66506c3fb27SDimitry Andric return false; 66606c3fb27SDimitry Andric 66706c3fb27SDimitry Andric auto BitfieldExtract = [&](SDValue N0, unsigned Msb, unsigned Lsb, SDLoc DL, 66806c3fb27SDimitry Andric MVT VT) { 66906c3fb27SDimitry Andric return CurDAG->getMachineNode(RISCV::TH_EXT, DL, VT, N0.getOperand(0), 67006c3fb27SDimitry Andric CurDAG->getTargetConstant(Msb, DL, VT), 67106c3fb27SDimitry Andric CurDAG->getTargetConstant(Lsb, DL, VT)); 67206c3fb27SDimitry Andric }; 67306c3fb27SDimitry Andric 67406c3fb27SDimitry Andric SDLoc DL(Node); 67506c3fb27SDimitry Andric MVT VT = Node->getSimpleValueType(0); 67606c3fb27SDimitry Andric const unsigned RightShAmt = N1C->getZExtValue(); 67706c3fb27SDimitry Andric 67806c3fb27SDimitry Andric // Transform (sra (shl X, C1) C2) with C1 < C2 67906c3fb27SDimitry Andric // -> (TH.EXT X, msb, lsb) 68006c3fb27SDimitry Andric if (N0.getOpcode() == ISD::SHL) { 68106c3fb27SDimitry Andric auto *N01C = dyn_cast<ConstantSDNode>(N0->getOperand(1)); 68206c3fb27SDimitry Andric if (!N01C) 68306c3fb27SDimitry Andric return false; 68406c3fb27SDimitry Andric 68506c3fb27SDimitry Andric const unsigned LeftShAmt = N01C->getZExtValue(); 68606c3fb27SDimitry Andric // Make sure that this is a bitfield extraction (i.e., the shift-right 68706c3fb27SDimitry Andric // amount can not be less than the left-shift). 68806c3fb27SDimitry Andric if (LeftShAmt > RightShAmt) 68906c3fb27SDimitry Andric return false; 69006c3fb27SDimitry Andric 69106c3fb27SDimitry Andric const unsigned MsbPlusOne = VT.getSizeInBits() - LeftShAmt; 69206c3fb27SDimitry Andric const unsigned Msb = MsbPlusOne - 1; 69306c3fb27SDimitry Andric const unsigned Lsb = RightShAmt - LeftShAmt; 69406c3fb27SDimitry Andric 69506c3fb27SDimitry Andric SDNode *TH_EXT = BitfieldExtract(N0, Msb, Lsb, DL, VT); 69606c3fb27SDimitry Andric ReplaceNode(Node, TH_EXT); 69706c3fb27SDimitry Andric return true; 69806c3fb27SDimitry Andric } 69906c3fb27SDimitry Andric 70006c3fb27SDimitry Andric // Transform (sra (sext_inreg X, _), C) -> 70106c3fb27SDimitry Andric // (TH.EXT X, msb, lsb) 70206c3fb27SDimitry Andric if (N0.getOpcode() == ISD::SIGN_EXTEND_INREG) { 70306c3fb27SDimitry Andric unsigned ExtSize = 70406c3fb27SDimitry Andric cast<VTSDNode>(N0.getOperand(1))->getVT().getSizeInBits(); 70506c3fb27SDimitry Andric 70606c3fb27SDimitry Andric // ExtSize of 32 should use sraiw via tablegen pattern. 70706c3fb27SDimitry Andric if (ExtSize == 32) 70806c3fb27SDimitry Andric return false; 70906c3fb27SDimitry Andric 71006c3fb27SDimitry Andric const unsigned Msb = ExtSize - 1; 71106c3fb27SDimitry Andric const unsigned Lsb = RightShAmt; 71206c3fb27SDimitry Andric 71306c3fb27SDimitry Andric SDNode *TH_EXT = BitfieldExtract(N0, Msb, Lsb, DL, VT); 71406c3fb27SDimitry Andric ReplaceNode(Node, TH_EXT); 71506c3fb27SDimitry Andric return true; 71606c3fb27SDimitry Andric } 71706c3fb27SDimitry Andric 71806c3fb27SDimitry Andric return false; 71906c3fb27SDimitry Andric } 72006c3fb27SDimitry Andric 72106c3fb27SDimitry Andric bool RISCVDAGToDAGISel::tryIndexedLoad(SDNode *Node) { 72206c3fb27SDimitry Andric // Target does not support indexed loads. 72306c3fb27SDimitry Andric if (!Subtarget->hasVendorXTHeadMemIdx()) 72406c3fb27SDimitry Andric return false; 72506c3fb27SDimitry Andric 72606c3fb27SDimitry Andric LoadSDNode *Ld = cast<LoadSDNode>(Node); 72706c3fb27SDimitry Andric ISD::MemIndexedMode AM = Ld->getAddressingMode(); 72806c3fb27SDimitry Andric if (AM == ISD::UNINDEXED) 72906c3fb27SDimitry Andric return false; 73006c3fb27SDimitry Andric 73106c3fb27SDimitry Andric const ConstantSDNode *C = dyn_cast<ConstantSDNode>(Ld->getOffset()); 73206c3fb27SDimitry Andric if (!C) 73306c3fb27SDimitry Andric return false; 73406c3fb27SDimitry Andric 73506c3fb27SDimitry Andric EVT LoadVT = Ld->getMemoryVT(); 73606c3fb27SDimitry Andric bool IsPre = (AM == ISD::PRE_INC || AM == ISD::PRE_DEC); 73706c3fb27SDimitry Andric bool IsPost = (AM == ISD::POST_INC || AM == ISD::POST_DEC); 73806c3fb27SDimitry Andric int64_t Offset = C->getSExtValue(); 73906c3fb27SDimitry Andric 74006c3fb27SDimitry Andric // Convert decrements to increments by a negative quantity. 74106c3fb27SDimitry Andric if (AM == ISD::PRE_DEC || AM == ISD::POST_DEC) 74206c3fb27SDimitry Andric Offset = -Offset; 74306c3fb27SDimitry Andric 74406c3fb27SDimitry Andric // The constants that can be encoded in the THeadMemIdx instructions 74506c3fb27SDimitry Andric // are of the form (sign_extend(imm5) << imm2). 74606c3fb27SDimitry Andric int64_t Shift; 74706c3fb27SDimitry Andric for (Shift = 0; Shift < 4; Shift++) 74806c3fb27SDimitry Andric if (isInt<5>(Offset >> Shift) && ((Offset % (1LL << Shift)) == 0)) 74906c3fb27SDimitry Andric break; 75006c3fb27SDimitry Andric 75106c3fb27SDimitry Andric // Constant cannot be encoded. 75206c3fb27SDimitry Andric if (Shift == 4) 75306c3fb27SDimitry Andric return false; 75406c3fb27SDimitry Andric 75506c3fb27SDimitry Andric bool IsZExt = (Ld->getExtensionType() == ISD::ZEXTLOAD); 75606c3fb27SDimitry Andric unsigned Opcode; 75706c3fb27SDimitry Andric if (LoadVT == MVT::i8 && IsPre) 75806c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LBUIB : RISCV::TH_LBIB; 75906c3fb27SDimitry Andric else if (LoadVT == MVT::i8 && IsPost) 76006c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LBUIA : RISCV::TH_LBIA; 76106c3fb27SDimitry Andric else if (LoadVT == MVT::i16 && IsPre) 76206c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LHUIB : RISCV::TH_LHIB; 76306c3fb27SDimitry Andric else if (LoadVT == MVT::i16 && IsPost) 76406c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LHUIA : RISCV::TH_LHIA; 76506c3fb27SDimitry Andric else if (LoadVT == MVT::i32 && IsPre) 76606c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LWUIB : RISCV::TH_LWIB; 76706c3fb27SDimitry Andric else if (LoadVT == MVT::i32 && IsPost) 76806c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LWUIA : RISCV::TH_LWIA; 76906c3fb27SDimitry Andric else if (LoadVT == MVT::i64 && IsPre) 77006c3fb27SDimitry Andric Opcode = RISCV::TH_LDIB; 77106c3fb27SDimitry Andric else if (LoadVT == MVT::i64 && IsPost) 77206c3fb27SDimitry Andric Opcode = RISCV::TH_LDIA; 77306c3fb27SDimitry Andric else 77406c3fb27SDimitry Andric return false; 77506c3fb27SDimitry Andric 77606c3fb27SDimitry Andric EVT Ty = Ld->getOffset().getValueType(); 77706c3fb27SDimitry Andric SDValue Ops[] = {Ld->getBasePtr(), 77806c3fb27SDimitry Andric CurDAG->getTargetConstant(Offset >> Shift, SDLoc(Node), Ty), 77906c3fb27SDimitry Andric CurDAG->getTargetConstant(Shift, SDLoc(Node), Ty), 78006c3fb27SDimitry Andric Ld->getChain()}; 78106c3fb27SDimitry Andric SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(Node), Ld->getValueType(0), 78206c3fb27SDimitry Andric Ld->getValueType(1), MVT::Other, Ops); 78306c3fb27SDimitry Andric 78406c3fb27SDimitry Andric MachineMemOperand *MemOp = cast<MemSDNode>(Node)->getMemOperand(); 78506c3fb27SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(New), {MemOp}); 78606c3fb27SDimitry Andric 78706c3fb27SDimitry Andric ReplaceNode(Node, New); 78806c3fb27SDimitry Andric 78906c3fb27SDimitry Andric return true; 79006c3fb27SDimitry Andric } 79106c3fb27SDimitry Andric 7920b57cec5SDimitry Andric void RISCVDAGToDAGISel::Select(SDNode *Node) { 7930b57cec5SDimitry Andric // If we have a custom node, we have already selected. 7940b57cec5SDimitry Andric if (Node->isMachineOpcode()) { 7950b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n"); 7960b57cec5SDimitry Andric Node->setNodeId(-1); 7970b57cec5SDimitry Andric return; 7980b57cec5SDimitry Andric } 7990b57cec5SDimitry Andric 8000b57cec5SDimitry Andric // Instruction Selection not handled by the auto-generated tablegen selection 8010b57cec5SDimitry Andric // should be handled here. 8020b57cec5SDimitry Andric unsigned Opcode = Node->getOpcode(); 8030b57cec5SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 8040b57cec5SDimitry Andric SDLoc DL(Node); 805fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 8060b57cec5SDimitry Andric 80706c3fb27SDimitry Andric bool HasBitTest = Subtarget->hasStdExtZbs() || Subtarget->hasVendorXTHeadBs(); 80806c3fb27SDimitry Andric 8090b57cec5SDimitry Andric switch (Opcode) { 8100b57cec5SDimitry Andric case ISD::Constant: { 81106c3fb27SDimitry Andric assert(VT == Subtarget->getXLenVT() && "Unexpected VT"); 812fe6060f1SDimitry Andric auto *ConstNode = cast<ConstantSDNode>(Node); 81306c3fb27SDimitry Andric if (ConstNode->isZero()) { 814e8d8bef9SDimitry Andric SDValue New = 81506c3fb27SDimitry Andric CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, RISCV::X0, VT); 8160b57cec5SDimitry Andric ReplaceNode(Node, New.getNode()); 8170b57cec5SDimitry Andric return; 8180b57cec5SDimitry Andric } 819349cc55cSDimitry Andric int64_t Imm = ConstNode->getSExtValue(); 820349cc55cSDimitry Andric // If the upper XLen-16 bits are not used, try to convert this to a simm12 821349cc55cSDimitry Andric // by sign extending bit 15. 82281ad6265SDimitry Andric if (isUInt<16>(Imm) && isInt<12>(SignExtend64<16>(Imm)) && 823349cc55cSDimitry Andric hasAllHUsers(Node)) 82481ad6265SDimitry Andric Imm = SignExtend64<16>(Imm); 825349cc55cSDimitry Andric // If the upper 32-bits are not used try to convert this into a simm32 by 826349cc55cSDimitry Andric // sign extending bit 32. 827349cc55cSDimitry Andric if (!isInt<32>(Imm) && isUInt<32>(Imm) && hasAllWUsers(Node)) 82881ad6265SDimitry Andric Imm = SignExtend64<32>(Imm); 829349cc55cSDimitry Andric 83006c3fb27SDimitry Andric ReplaceNode(Node, selectImm(CurDAG, DL, VT, Imm, *Subtarget).getNode()); 83106c3fb27SDimitry Andric return; 83206c3fb27SDimitry Andric } 83306c3fb27SDimitry Andric case ISD::ConstantFP: { 83406c3fb27SDimitry Andric const APFloat &APF = cast<ConstantFPSDNode>(Node)->getValueAPF(); 83506c3fb27SDimitry Andric int FPImm = static_cast<const RISCVTargetLowering *>(TLI)->getLegalZfaFPImm( 83606c3fb27SDimitry Andric APF, VT); 83706c3fb27SDimitry Andric if (FPImm >= 0) { 83806c3fb27SDimitry Andric unsigned Opc; 83906c3fb27SDimitry Andric switch (VT.SimpleTy) { 84006c3fb27SDimitry Andric default: 84106c3fb27SDimitry Andric llvm_unreachable("Unexpected size"); 84206c3fb27SDimitry Andric case MVT::f16: 84306c3fb27SDimitry Andric Opc = RISCV::FLI_H; 84406c3fb27SDimitry Andric break; 84506c3fb27SDimitry Andric case MVT::f32: 84606c3fb27SDimitry Andric Opc = RISCV::FLI_S; 84706c3fb27SDimitry Andric break; 84806c3fb27SDimitry Andric case MVT::f64: 84906c3fb27SDimitry Andric Opc = RISCV::FLI_D; 85006c3fb27SDimitry Andric break; 85106c3fb27SDimitry Andric } 85206c3fb27SDimitry Andric 85306c3fb27SDimitry Andric SDNode *Res = CurDAG->getMachineNode( 85406c3fb27SDimitry Andric Opc, DL, VT, CurDAG->getTargetConstant(FPImm, DL, XLenVT)); 85506c3fb27SDimitry Andric ReplaceNode(Node, Res); 85606c3fb27SDimitry Andric return; 85706c3fb27SDimitry Andric } 85806c3fb27SDimitry Andric 85906c3fb27SDimitry Andric bool NegZeroF64 = APF.isNegZero() && VT == MVT::f64; 86006c3fb27SDimitry Andric SDValue Imm; 86106c3fb27SDimitry Andric // For +0.0 or f64 -0.0 we need to start from X0. For all others, we will 86206c3fb27SDimitry Andric // create an integer immediate. 86306c3fb27SDimitry Andric if (APF.isPosZero() || NegZeroF64) 86406c3fb27SDimitry Andric Imm = CurDAG->getRegister(RISCV::X0, XLenVT); 86506c3fb27SDimitry Andric else 86606c3fb27SDimitry Andric Imm = selectImm(CurDAG, DL, XLenVT, APF.bitcastToAPInt().getSExtValue(), 86706c3fb27SDimitry Andric *Subtarget); 86806c3fb27SDimitry Andric 86906c3fb27SDimitry Andric unsigned Opc; 87006c3fb27SDimitry Andric switch (VT.SimpleTy) { 87106c3fb27SDimitry Andric default: 87206c3fb27SDimitry Andric llvm_unreachable("Unexpected size"); 87306c3fb27SDimitry Andric case MVT::f16: 87406c3fb27SDimitry Andric Opc = 87506c3fb27SDimitry Andric Subtarget->hasStdExtZhinxOrZhinxmin() ? RISCV::COPY : RISCV::FMV_H_X; 87606c3fb27SDimitry Andric break; 87706c3fb27SDimitry Andric case MVT::f32: 87806c3fb27SDimitry Andric Opc = Subtarget->hasStdExtZfinx() ? RISCV::COPY : RISCV::FMV_W_X; 87906c3fb27SDimitry Andric break; 88006c3fb27SDimitry Andric case MVT::f64: 88106c3fb27SDimitry Andric // For RV32, we can't move from a GPR, we need to convert instead. This 88206c3fb27SDimitry Andric // should only happen for +0.0 and -0.0. 88306c3fb27SDimitry Andric assert((Subtarget->is64Bit() || APF.isZero()) && "Unexpected constant"); 88406c3fb27SDimitry Andric bool HasZdinx = Subtarget->hasStdExtZdinx(); 88506c3fb27SDimitry Andric if (Subtarget->is64Bit()) 88606c3fb27SDimitry Andric Opc = HasZdinx ? RISCV::COPY : RISCV::FMV_D_X; 88706c3fb27SDimitry Andric else 88806c3fb27SDimitry Andric Opc = HasZdinx ? RISCV::FCVT_D_W_IN32X : RISCV::FCVT_D_W; 88906c3fb27SDimitry Andric break; 89006c3fb27SDimitry Andric } 89106c3fb27SDimitry Andric 89206c3fb27SDimitry Andric SDNode *Res = CurDAG->getMachineNode(Opc, DL, VT, Imm); 89306c3fb27SDimitry Andric 89406c3fb27SDimitry Andric // For f64 -0.0, we need to insert a fneg.d idiom. 89506c3fb27SDimitry Andric if (NegZeroF64) 89606c3fb27SDimitry Andric Res = CurDAG->getMachineNode(RISCV::FSGNJN_D, DL, VT, SDValue(Res, 0), 89706c3fb27SDimitry Andric SDValue(Res, 0)); 89806c3fb27SDimitry Andric 89906c3fb27SDimitry Andric ReplaceNode(Node, Res); 90006c3fb27SDimitry Andric return; 90106c3fb27SDimitry Andric } 90206c3fb27SDimitry Andric case RISCVISD::SplitF64: { 90306c3fb27SDimitry Andric if (!Subtarget->hasStdExtZfa()) 90406c3fb27SDimitry Andric break; 90506c3fb27SDimitry Andric assert(Subtarget->hasStdExtD() && !Subtarget->is64Bit() && 90606c3fb27SDimitry Andric "Unexpected subtarget"); 90706c3fb27SDimitry Andric 90806c3fb27SDimitry Andric // With Zfa, lower to fmv.x.w and fmvh.x.d. 90906c3fb27SDimitry Andric if (!SDValue(Node, 0).use_empty()) { 91006c3fb27SDimitry Andric SDNode *Lo = CurDAG->getMachineNode(RISCV::FMV_X_W_FPR64, DL, VT, 91106c3fb27SDimitry Andric Node->getOperand(0)); 91206c3fb27SDimitry Andric ReplaceUses(SDValue(Node, 0), SDValue(Lo, 0)); 91306c3fb27SDimitry Andric } 91406c3fb27SDimitry Andric if (!SDValue(Node, 1).use_empty()) { 91506c3fb27SDimitry Andric SDNode *Hi = CurDAG->getMachineNode(RISCV::FMVH_X_D, DL, VT, 91606c3fb27SDimitry Andric Node->getOperand(0)); 91706c3fb27SDimitry Andric ReplaceUses(SDValue(Node, 1), SDValue(Hi, 0)); 91806c3fb27SDimitry Andric } 91906c3fb27SDimitry Andric 92006c3fb27SDimitry Andric CurDAG->RemoveDeadNode(Node); 9210b57cec5SDimitry Andric return; 9220b57cec5SDimitry Andric } 92381ad6265SDimitry Andric case ISD::SHL: { 924fe6060f1SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 92504eeddc0SDimitry Andric if (!N1C) 92604eeddc0SDimitry Andric break; 927fe6060f1SDimitry Andric SDValue N0 = Node->getOperand(0); 92804eeddc0SDimitry Andric if (N0.getOpcode() != ISD::AND || !N0.hasOneUse() || 92904eeddc0SDimitry Andric !isa<ConstantSDNode>(N0.getOperand(1))) 93004eeddc0SDimitry Andric break; 93104eeddc0SDimitry Andric unsigned ShAmt = N1C->getZExtValue(); 932fe6060f1SDimitry Andric uint64_t Mask = N0.getConstantOperandVal(1); 93381ad6265SDimitry Andric 93481ad6265SDimitry Andric // Optimize (shl (and X, C2), C) -> (slli (srliw X, C3), C3+C) where C2 has 93581ad6265SDimitry Andric // 32 leading zeros and C3 trailing zeros. 93681ad6265SDimitry Andric if (ShAmt <= 32 && isShiftedMask_64(Mask)) { 93781ad6265SDimitry Andric unsigned XLen = Subtarget->getXLen(); 938bdd1243dSDimitry Andric unsigned LeadingZeros = XLen - llvm::bit_width(Mask); 93906c3fb27SDimitry Andric unsigned TrailingZeros = llvm::countr_zero(Mask); 94081ad6265SDimitry Andric if (TrailingZeros > 0 && LeadingZeros == 32) { 94181ad6265SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 94281ad6265SDimitry Andric RISCV::SRLIW, DL, VT, N0->getOperand(0), 94381ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros, DL, VT)); 94481ad6265SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 94581ad6265SDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 94681ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros + ShAmt, DL, VT)); 94781ad6265SDimitry Andric ReplaceNode(Node, SLLI); 94881ad6265SDimitry Andric return; 94981ad6265SDimitry Andric } 95081ad6265SDimitry Andric } 95181ad6265SDimitry Andric break; 95281ad6265SDimitry Andric } 95381ad6265SDimitry Andric case ISD::SRL: { 95481ad6265SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 95581ad6265SDimitry Andric if (!N1C) 95681ad6265SDimitry Andric break; 95781ad6265SDimitry Andric SDValue N0 = Node->getOperand(0); 958bdd1243dSDimitry Andric if (N0.getOpcode() != ISD::AND || !isa<ConstantSDNode>(N0.getOperand(1))) 95981ad6265SDimitry Andric break; 96081ad6265SDimitry Andric unsigned ShAmt = N1C->getZExtValue(); 96181ad6265SDimitry Andric uint64_t Mask = N0.getConstantOperandVal(1); 96281ad6265SDimitry Andric 96381ad6265SDimitry Andric // Optimize (srl (and X, C2), C) -> (slli (srliw X, C3), C3-C) where C2 has 96481ad6265SDimitry Andric // 32 leading zeros and C3 trailing zeros. 965bdd1243dSDimitry Andric if (isShiftedMask_64(Mask) && N0.hasOneUse()) { 96681ad6265SDimitry Andric unsigned XLen = Subtarget->getXLen(); 967bdd1243dSDimitry Andric unsigned LeadingZeros = XLen - llvm::bit_width(Mask); 96806c3fb27SDimitry Andric unsigned TrailingZeros = llvm::countr_zero(Mask); 96981ad6265SDimitry Andric if (LeadingZeros == 32 && TrailingZeros > ShAmt) { 97081ad6265SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 97181ad6265SDimitry Andric RISCV::SRLIW, DL, VT, N0->getOperand(0), 97281ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros, DL, VT)); 97381ad6265SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 97481ad6265SDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 97581ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros - ShAmt, DL, VT)); 97681ad6265SDimitry Andric ReplaceNode(Node, SLLI); 97781ad6265SDimitry Andric return; 97881ad6265SDimitry Andric } 97981ad6265SDimitry Andric } 98081ad6265SDimitry Andric 98181ad6265SDimitry Andric // Optimize (srl (and X, C2), C) -> 98281ad6265SDimitry Andric // (srli (slli X, (XLen-C3), (XLen-C3) + C) 98381ad6265SDimitry Andric // Where C2 is a mask with C3 trailing ones. 98481ad6265SDimitry Andric // Taking into account that the C2 may have had lower bits unset by 98581ad6265SDimitry Andric // SimplifyDemandedBits. This avoids materializing the C2 immediate. 98681ad6265SDimitry Andric // This pattern occurs when type legalizing right shifts for types with 98781ad6265SDimitry Andric // less than XLen bits. 988fe6060f1SDimitry Andric Mask |= maskTrailingOnes<uint64_t>(ShAmt); 98904eeddc0SDimitry Andric if (!isMask_64(Mask)) 99004eeddc0SDimitry Andric break; 99106c3fb27SDimitry Andric unsigned TrailingOnes = llvm::countr_one(Mask); 992bdd1243dSDimitry Andric if (ShAmt >= TrailingOnes) 99304eeddc0SDimitry Andric break; 994*5c16e71dSDimitry Andric // If the mask has 32 trailing ones, use SRLI on RV32 or SRLIW on RV64. 995bdd1243dSDimitry Andric if (TrailingOnes == 32) { 996*5c16e71dSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 997*5c16e71dSDimitry Andric Subtarget->is64Bit() ? RISCV::SRLIW : RISCV::SRLI, DL, VT, 998*5c16e71dSDimitry Andric N0->getOperand(0), CurDAG->getTargetConstant(ShAmt, DL, VT)); 999*5c16e71dSDimitry Andric ReplaceNode(Node, SRLI); 1000bdd1243dSDimitry Andric return; 1001bdd1243dSDimitry Andric } 1002bdd1243dSDimitry Andric 100306c3fb27SDimitry Andric // Only do the remaining transforms if the AND has one use. 1004bdd1243dSDimitry Andric if (!N0.hasOneUse()) 1005bdd1243dSDimitry Andric break; 1006bdd1243dSDimitry Andric 100706c3fb27SDimitry Andric // If C2 is (1 << ShAmt) use bexti or th.tst if possible. 100806c3fb27SDimitry Andric if (HasBitTest && ShAmt + 1 == TrailingOnes) { 100906c3fb27SDimitry Andric SDNode *BEXTI = CurDAG->getMachineNode( 101006c3fb27SDimitry Andric Subtarget->hasStdExtZbs() ? RISCV::BEXTI : RISCV::TH_TST, DL, VT, 101106c3fb27SDimitry Andric N0->getOperand(0), CurDAG->getTargetConstant(ShAmt, DL, VT)); 1012fcaf7f86SDimitry Andric ReplaceNode(Node, BEXTI); 1013fcaf7f86SDimitry Andric return; 1014fcaf7f86SDimitry Andric } 101506c3fb27SDimitry Andric 101604eeddc0SDimitry Andric unsigned LShAmt = Subtarget->getXLen() - TrailingOnes; 1017fe6060f1SDimitry Andric SDNode *SLLI = 1018fe6060f1SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0->getOperand(0), 1019fe6060f1SDimitry Andric CurDAG->getTargetConstant(LShAmt, DL, VT)); 1020fe6060f1SDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1021fe6060f1SDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 1022fe6060f1SDimitry Andric CurDAG->getTargetConstant(LShAmt + ShAmt, DL, VT)); 1023fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 1024fe6060f1SDimitry Andric return; 1025fe6060f1SDimitry Andric } 102604eeddc0SDimitry Andric case ISD::SRA: { 102706c3fb27SDimitry Andric if (trySignedBitfieldExtract(Node)) 102806c3fb27SDimitry Andric return; 102906c3fb27SDimitry Andric 103004eeddc0SDimitry Andric // Optimize (sra (sext_inreg X, i16), C) -> 103104eeddc0SDimitry Andric // (srai (slli X, (XLen-16), (XLen-16) + C) 103204eeddc0SDimitry Andric // And (sra (sext_inreg X, i8), C) -> 103304eeddc0SDimitry Andric // (srai (slli X, (XLen-8), (XLen-8) + C) 103404eeddc0SDimitry Andric // This can occur when Zbb is enabled, which makes sext_inreg i16/i8 legal. 103504eeddc0SDimitry Andric // This transform matches the code we get without Zbb. The shifts are more 103604eeddc0SDimitry Andric // compressible, and this can help expose CSE opportunities in the sdiv by 103704eeddc0SDimitry Andric // constant optimization. 103804eeddc0SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 103904eeddc0SDimitry Andric if (!N1C) 1040fe6060f1SDimitry Andric break; 104104eeddc0SDimitry Andric SDValue N0 = Node->getOperand(0); 104204eeddc0SDimitry Andric if (N0.getOpcode() != ISD::SIGN_EXTEND_INREG || !N0.hasOneUse()) 104304eeddc0SDimitry Andric break; 104404eeddc0SDimitry Andric unsigned ShAmt = N1C->getZExtValue(); 104504eeddc0SDimitry Andric unsigned ExtSize = 104604eeddc0SDimitry Andric cast<VTSDNode>(N0.getOperand(1))->getVT().getSizeInBits(); 104704eeddc0SDimitry Andric // ExtSize of 32 should use sraiw via tablegen pattern. 104804eeddc0SDimitry Andric if (ExtSize >= 32 || ShAmt >= ExtSize) 104904eeddc0SDimitry Andric break; 105004eeddc0SDimitry Andric unsigned LShAmt = Subtarget->getXLen() - ExtSize; 105104eeddc0SDimitry Andric SDNode *SLLI = 105204eeddc0SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0->getOperand(0), 105304eeddc0SDimitry Andric CurDAG->getTargetConstant(LShAmt, DL, VT)); 105404eeddc0SDimitry Andric SDNode *SRAI = CurDAG->getMachineNode( 105504eeddc0SDimitry Andric RISCV::SRAI, DL, VT, SDValue(SLLI, 0), 105604eeddc0SDimitry Andric CurDAG->getTargetConstant(LShAmt + ShAmt, DL, VT)); 105704eeddc0SDimitry Andric ReplaceNode(Node, SRAI); 105804eeddc0SDimitry Andric return; 1059fe6060f1SDimitry Andric } 1060bdd1243dSDimitry Andric case ISD::OR: 1061bdd1243dSDimitry Andric case ISD::XOR: 1062bdd1243dSDimitry Andric if (tryShrinkShlLogicImm(Node)) 1063bdd1243dSDimitry Andric return; 1064bdd1243dSDimitry Andric 1065bdd1243dSDimitry Andric break; 1066fe6060f1SDimitry Andric case ISD::AND: { 1067fe6060f1SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 1068fe6060f1SDimitry Andric if (!N1C) 1069fe6060f1SDimitry Andric break; 107006c3fb27SDimitry Andric uint64_t C1 = N1C->getZExtValue(); 107106c3fb27SDimitry Andric const bool isC1Mask = isMask_64(C1); 107206c3fb27SDimitry Andric const bool isC1ANDI = isInt<12>(C1); 1073fe6060f1SDimitry Andric 1074fe6060f1SDimitry Andric SDValue N0 = Node->getOperand(0); 1075fe6060f1SDimitry Andric 107606c3fb27SDimitry Andric auto tryUnsignedBitfieldExtract = [&](SDNode *Node, SDLoc DL, MVT VT, 107706c3fb27SDimitry Andric SDValue X, unsigned Msb, 107806c3fb27SDimitry Andric unsigned Lsb) { 107906c3fb27SDimitry Andric if (!Subtarget->hasVendorXTHeadBb()) 108006c3fb27SDimitry Andric return false; 108106c3fb27SDimitry Andric 108206c3fb27SDimitry Andric SDNode *TH_EXTU = CurDAG->getMachineNode( 108306c3fb27SDimitry Andric RISCV::TH_EXTU, DL, VT, X, CurDAG->getTargetConstant(Msb, DL, VT), 108406c3fb27SDimitry Andric CurDAG->getTargetConstant(Lsb, DL, VT)); 108506c3fb27SDimitry Andric ReplaceNode(Node, TH_EXTU); 108606c3fb27SDimitry Andric return true; 108706c3fb27SDimitry Andric }; 108806c3fb27SDimitry Andric 1089fe6060f1SDimitry Andric bool LeftShift = N0.getOpcode() == ISD::SHL; 1090bdd1243dSDimitry Andric if (LeftShift || N0.getOpcode() == ISD::SRL) { 1091fe6060f1SDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N0.getOperand(1)); 1092fe6060f1SDimitry Andric if (!C) 1093fe6060f1SDimitry Andric break; 1094753f127fSDimitry Andric unsigned C2 = C->getZExtValue(); 1095fe6060f1SDimitry Andric unsigned XLen = Subtarget->getXLen(); 1096753f127fSDimitry Andric assert((C2 > 0 && C2 < XLen) && "Unexpected shift amount!"); 1097fe6060f1SDimitry Andric 109881ad6265SDimitry Andric // Keep track of whether this is a c.andi. If we can't use c.andi, the 109981ad6265SDimitry Andric // shift pair might offer more compression opportunities. 110081ad6265SDimitry Andric // TODO: We could check for C extension here, but we don't have many lit 1101bdd1243dSDimitry Andric // tests with the C extension enabled so not checking gets better 1102bdd1243dSDimitry Andric // coverage. 110381ad6265SDimitry Andric // TODO: What if ANDI faster than shift? 110481ad6265SDimitry Andric bool IsCANDI = isInt<6>(N1C->getSExtValue()); 1105fe6060f1SDimitry Andric 1106fe6060f1SDimitry Andric // Clear irrelevant bits in the mask. 1107fe6060f1SDimitry Andric if (LeftShift) 1108fe6060f1SDimitry Andric C1 &= maskTrailingZeros<uint64_t>(C2); 1109fe6060f1SDimitry Andric else 1110fe6060f1SDimitry Andric C1 &= maskTrailingOnes<uint64_t>(XLen - C2); 1111fe6060f1SDimitry Andric 1112fe6060f1SDimitry Andric // Some transforms should only be done if the shift has a single use or 1113fe6060f1SDimitry Andric // the AND would become (srli (slli X, 32), 32) 1114fe6060f1SDimitry Andric bool OneUseOrZExtW = N0.hasOneUse() || C1 == UINT64_C(0xFFFFFFFF); 1115fe6060f1SDimitry Andric 1116fe6060f1SDimitry Andric SDValue X = N0.getOperand(0); 1117fe6060f1SDimitry Andric 1118fe6060f1SDimitry Andric // Turn (and (srl x, c2) c1) -> (srli (slli x, c3-c2), c3) if c1 is a mask 1119fe6060f1SDimitry Andric // with c3 leading zeros. 112006c3fb27SDimitry Andric if (!LeftShift && isC1Mask) { 1121bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(C1); 1122753f127fSDimitry Andric if (C2 < Leading) { 1123fe6060f1SDimitry Andric // If the number of leading zeros is C2+32 this can be SRLIW. 1124753f127fSDimitry Andric if (C2 + 32 == Leading) { 112581ad6265SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 112681ad6265SDimitry Andric RISCV::SRLIW, DL, VT, X, CurDAG->getTargetConstant(C2, DL, VT)); 1127fe6060f1SDimitry Andric ReplaceNode(Node, SRLIW); 1128fe6060f1SDimitry Andric return; 1129fe6060f1SDimitry Andric } 1130fe6060f1SDimitry Andric 1131bdd1243dSDimitry Andric // (and (srl (sexti32 Y), c2), c1) -> (srliw (sraiw Y, 31), c3 - 32) 1132bdd1243dSDimitry Andric // if c1 is a mask with c3 leading zeros and c2 >= 32 and c3-c2==1. 1133fe6060f1SDimitry Andric // 1134fe6060f1SDimitry Andric // This pattern occurs when (i32 (srl (sra 31), c3 - 32)) is type 1135fe6060f1SDimitry Andric // legalized and goes through DAG combine. 1136753f127fSDimitry Andric if (C2 >= 32 && (Leading - C2) == 1 && N0.hasOneUse() && 113781ad6265SDimitry Andric X.getOpcode() == ISD::SIGN_EXTEND_INREG && 113881ad6265SDimitry Andric cast<VTSDNode>(X.getOperand(1))->getVT() == MVT::i32) { 1139fe6060f1SDimitry Andric SDNode *SRAIW = 114081ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::SRAIW, DL, VT, X.getOperand(0), 114181ad6265SDimitry Andric CurDAG->getTargetConstant(31, DL, VT)); 1142fe6060f1SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 114381ad6265SDimitry Andric RISCV::SRLIW, DL, VT, SDValue(SRAIW, 0), 1144753f127fSDimitry Andric CurDAG->getTargetConstant(Leading - 32, DL, VT)); 1145fe6060f1SDimitry Andric ReplaceNode(Node, SRLIW); 1146fe6060f1SDimitry Andric return; 1147fe6060f1SDimitry Andric } 1148fe6060f1SDimitry Andric 114906c3fb27SDimitry Andric // Try to use an unsigned bitfield extract (e.g., th.extu) if 115006c3fb27SDimitry Andric // available. 115106c3fb27SDimitry Andric // Transform (and (srl x, C2), C1) 115206c3fb27SDimitry Andric // -> (<bfextract> x, msb, lsb) 115306c3fb27SDimitry Andric // 115406c3fb27SDimitry Andric // Make sure to keep this below the SRLIW cases, as we always want to 115506c3fb27SDimitry Andric // prefer the more common instruction. 115606c3fb27SDimitry Andric const unsigned Msb = llvm::bit_width(C1) + C2 - 1; 115706c3fb27SDimitry Andric const unsigned Lsb = C2; 115806c3fb27SDimitry Andric if (tryUnsignedBitfieldExtract(Node, DL, VT, X, Msb, Lsb)) 115906c3fb27SDimitry Andric return; 116006c3fb27SDimitry Andric 1161fe6060f1SDimitry Andric // (srli (slli x, c3-c2), c3). 116281ad6265SDimitry Andric // Skip if we could use (zext.w (sraiw X, C2)). 1163753f127fSDimitry Andric bool Skip = Subtarget->hasStdExtZba() && Leading == 32 && 116481ad6265SDimitry Andric X.getOpcode() == ISD::SIGN_EXTEND_INREG && 116581ad6265SDimitry Andric cast<VTSDNode>(X.getOperand(1))->getVT() == MVT::i32; 116606c3fb27SDimitry Andric // Also Skip if we can use bexti or th.tst. 116706c3fb27SDimitry Andric Skip |= HasBitTest && Leading == XLen - 1; 116881ad6265SDimitry Andric if (OneUseOrZExtW && !Skip) { 1169fe6060f1SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 117081ad6265SDimitry Andric RISCV::SLLI, DL, VT, X, 1171753f127fSDimitry Andric CurDAG->getTargetConstant(Leading - C2, DL, VT)); 1172753f127fSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1173753f127fSDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 1174753f127fSDimitry Andric CurDAG->getTargetConstant(Leading, DL, VT)); 1175fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 1176fe6060f1SDimitry Andric return; 1177fe6060f1SDimitry Andric } 1178fe6060f1SDimitry Andric } 1179fe6060f1SDimitry Andric } 1180fe6060f1SDimitry Andric 1181349cc55cSDimitry Andric // Turn (and (shl x, c2), c1) -> (srli (slli c2+c3), c3) if c1 is a mask 1182fe6060f1SDimitry Andric // shifted by c2 bits with c3 leading zeros. 1183fe6060f1SDimitry Andric if (LeftShift && isShiftedMask_64(C1)) { 1184bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(C1); 1185fe6060f1SDimitry Andric 1186753f127fSDimitry Andric if (C2 + Leading < XLen && 1187753f127fSDimitry Andric C1 == (maskTrailingOnes<uint64_t>(XLen - (C2 + Leading)) << C2)) { 1188fe6060f1SDimitry Andric // Use slli.uw when possible. 1189753f127fSDimitry Andric if ((XLen - (C2 + Leading)) == 32 && Subtarget->hasStdExtZba()) { 1190bdd1243dSDimitry Andric SDNode *SLLI_UW = 1191bdd1243dSDimitry Andric CurDAG->getMachineNode(RISCV::SLLI_UW, DL, VT, X, 1192bdd1243dSDimitry Andric CurDAG->getTargetConstant(C2, DL, VT)); 11931fd87a68SDimitry Andric ReplaceNode(Node, SLLI_UW); 1194fe6060f1SDimitry Andric return; 1195fe6060f1SDimitry Andric } 1196fe6060f1SDimitry Andric 1197fe6060f1SDimitry Andric // (srli (slli c2+c3), c3) 119881ad6265SDimitry Andric if (OneUseOrZExtW && !IsCANDI) { 1199fe6060f1SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 120081ad6265SDimitry Andric RISCV::SLLI, DL, VT, X, 1201753f127fSDimitry Andric CurDAG->getTargetConstant(C2 + Leading, DL, VT)); 1202753f127fSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1203753f127fSDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 1204753f127fSDimitry Andric CurDAG->getTargetConstant(Leading, DL, VT)); 1205fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 1206fe6060f1SDimitry Andric return; 1207fe6060f1SDimitry Andric } 1208fe6060f1SDimitry Andric } 1209fe6060f1SDimitry Andric } 1210fe6060f1SDimitry Andric 1211349cc55cSDimitry Andric // Turn (and (shr x, c2), c1) -> (slli (srli x, c2+c3), c3) if c1 is a 1212349cc55cSDimitry Andric // shifted mask with c2 leading zeros and c3 trailing zeros. 1213349cc55cSDimitry Andric if (!LeftShift && isShiftedMask_64(C1)) { 1214bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(C1); 121506c3fb27SDimitry Andric unsigned Trailing = llvm::countr_zero(C1); 1216bdd1243dSDimitry Andric if (Leading == C2 && C2 + Trailing < XLen && OneUseOrZExtW && 1217bdd1243dSDimitry Andric !IsCANDI) { 121881ad6265SDimitry Andric unsigned SrliOpc = RISCV::SRLI; 121981ad6265SDimitry Andric // If the input is zexti32 we should use SRLIW. 1220bdd1243dSDimitry Andric if (X.getOpcode() == ISD::AND && 1221bdd1243dSDimitry Andric isa<ConstantSDNode>(X.getOperand(1)) && 122281ad6265SDimitry Andric X.getConstantOperandVal(1) == UINT64_C(0xFFFFFFFF)) { 122381ad6265SDimitry Andric SrliOpc = RISCV::SRLIW; 122481ad6265SDimitry Andric X = X.getOperand(0); 122581ad6265SDimitry Andric } 1226349cc55cSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1227753f127fSDimitry Andric SrliOpc, DL, VT, X, 1228753f127fSDimitry Andric CurDAG->getTargetConstant(C2 + Trailing, DL, VT)); 1229bdd1243dSDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 1230bdd1243dSDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLI, 0), 1231753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 1232349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 1233349cc55cSDimitry Andric return; 1234349cc55cSDimitry Andric } 1235349cc55cSDimitry Andric // If the leading zero count is C2+32, we can use SRLIW instead of SRLI. 1236753f127fSDimitry Andric if (Leading > 32 && (Leading - 32) == C2 && C2 + Trailing < 32 && 123781ad6265SDimitry Andric OneUseOrZExtW && !IsCANDI) { 1238753f127fSDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 1239753f127fSDimitry Andric RISCV::SRLIW, DL, VT, X, 1240753f127fSDimitry Andric CurDAG->getTargetConstant(C2 + Trailing, DL, VT)); 1241bdd1243dSDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 1242bdd1243dSDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 1243753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 1244349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 1245349cc55cSDimitry Andric return; 1246349cc55cSDimitry Andric } 1247349cc55cSDimitry Andric } 1248349cc55cSDimitry Andric 1249349cc55cSDimitry Andric // Turn (and (shl x, c2), c1) -> (slli (srli x, c3-c2), c3) if c1 is a 1250349cc55cSDimitry Andric // shifted mask with no leading zeros and c3 trailing zeros. 1251349cc55cSDimitry Andric if (LeftShift && isShiftedMask_64(C1)) { 1252bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(C1); 125306c3fb27SDimitry Andric unsigned Trailing = llvm::countr_zero(C1); 1254753f127fSDimitry Andric if (Leading == 0 && C2 < Trailing && OneUseOrZExtW && !IsCANDI) { 1255349cc55cSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1256753f127fSDimitry Andric RISCV::SRLI, DL, VT, X, 1257753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)); 1258bdd1243dSDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 1259bdd1243dSDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLI, 0), 1260753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 1261349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 1262349cc55cSDimitry Andric return; 1263349cc55cSDimitry Andric } 1264349cc55cSDimitry Andric // If we have (32-C2) leading zeros, we can use SRLIW instead of SRLI. 1265753f127fSDimitry Andric if (C2 < Trailing && Leading + C2 == 32 && OneUseOrZExtW && !IsCANDI) { 1266753f127fSDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 1267753f127fSDimitry Andric RISCV::SRLIW, DL, VT, X, 1268753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)); 1269bdd1243dSDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 1270bdd1243dSDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 1271753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 1272349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 1273349cc55cSDimitry Andric return; 1274349cc55cSDimitry Andric } 1275349cc55cSDimitry Andric } 1276bdd1243dSDimitry Andric } 1277bdd1243dSDimitry Andric 127806c3fb27SDimitry Andric // If C1 masks off the upper bits only (but can't be formed as an 127906c3fb27SDimitry Andric // ANDI), use an unsigned bitfield extract (e.g., th.extu), if 128006c3fb27SDimitry Andric // available. 128106c3fb27SDimitry Andric // Transform (and x, C1) 128206c3fb27SDimitry Andric // -> (<bfextract> x, msb, lsb) 128306c3fb27SDimitry Andric if (isC1Mask && !isC1ANDI) { 128406c3fb27SDimitry Andric const unsigned Msb = llvm::bit_width(C1) - 1; 128506c3fb27SDimitry Andric if (tryUnsignedBitfieldExtract(Node, DL, VT, N0, Msb, 0)) 128606c3fb27SDimitry Andric return; 128706c3fb27SDimitry Andric } 128806c3fb27SDimitry Andric 1289bdd1243dSDimitry Andric if (tryShrinkShlLogicImm(Node)) 1290bdd1243dSDimitry Andric return; 1291349cc55cSDimitry Andric 1292fe6060f1SDimitry Andric break; 1293fe6060f1SDimitry Andric } 12940eae32dcSDimitry Andric case ISD::MUL: { 12950eae32dcSDimitry Andric // Special case for calculating (mul (and X, C2), C1) where the full product 12960eae32dcSDimitry Andric // fits in XLen bits. We can shift X left by the number of leading zeros in 12970eae32dcSDimitry Andric // C2 and shift C1 left by XLen-lzcnt(C2). This will ensure the final 12980eae32dcSDimitry Andric // product has XLen trailing zeros, putting it in the output of MULHU. This 12990eae32dcSDimitry Andric // can avoid materializing a constant in a register for C2. 13000eae32dcSDimitry Andric 13010eae32dcSDimitry Andric // RHS should be a constant. 13020eae32dcSDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 13030eae32dcSDimitry Andric if (!N1C || !N1C->hasOneUse()) 13040eae32dcSDimitry Andric break; 13050eae32dcSDimitry Andric 13060eae32dcSDimitry Andric // LHS should be an AND with constant. 13070eae32dcSDimitry Andric SDValue N0 = Node->getOperand(0); 13080eae32dcSDimitry Andric if (N0.getOpcode() != ISD::AND || !isa<ConstantSDNode>(N0.getOperand(1))) 13090eae32dcSDimitry Andric break; 13100eae32dcSDimitry Andric 13110eae32dcSDimitry Andric uint64_t C2 = cast<ConstantSDNode>(N0.getOperand(1))->getZExtValue(); 13120eae32dcSDimitry Andric 13130eae32dcSDimitry Andric // Constant should be a mask. 13140eae32dcSDimitry Andric if (!isMask_64(C2)) 13150eae32dcSDimitry Andric break; 13160eae32dcSDimitry Andric 131706c3fb27SDimitry Andric // If this can be an ANDI or ZEXT.H, don't do this if the ANDI/ZEXT has 131806c3fb27SDimitry Andric // multiple users or the constant is a simm12. This prevents inserting a 131906c3fb27SDimitry Andric // shift and still have uses of the AND/ZEXT. Shifting a simm12 will likely 132006c3fb27SDimitry Andric // make it more costly to materialize. Otherwise, using a SLLI might allow 132106c3fb27SDimitry Andric // it to be compressed. 1322fcaf7f86SDimitry Andric bool IsANDIOrZExt = 1323fcaf7f86SDimitry Andric isInt<12>(C2) || 132406c3fb27SDimitry Andric (C2 == UINT64_C(0xFFFF) && Subtarget->hasStdExtZbb()); 132506c3fb27SDimitry Andric // With XTHeadBb, we can use TH.EXTU. 132606c3fb27SDimitry Andric IsANDIOrZExt |= C2 == UINT64_C(0xFFFF) && Subtarget->hasVendorXTHeadBb(); 1327fcaf7f86SDimitry Andric if (IsANDIOrZExt && (isInt<12>(N1C->getSExtValue()) || !N0.hasOneUse())) 13280eae32dcSDimitry Andric break; 132906c3fb27SDimitry Andric // If this can be a ZEXT.w, don't do this if the ZEXT has multiple users or 133006c3fb27SDimitry Andric // the constant is a simm32. 133106c3fb27SDimitry Andric bool IsZExtW = C2 == UINT64_C(0xFFFFFFFF) && Subtarget->hasStdExtZba(); 133206c3fb27SDimitry Andric // With XTHeadBb, we can use TH.EXTU. 133306c3fb27SDimitry Andric IsZExtW |= C2 == UINT64_C(0xFFFFFFFF) && Subtarget->hasVendorXTHeadBb(); 133406c3fb27SDimitry Andric if (IsZExtW && (isInt<32>(N1C->getSExtValue()) || !N0.hasOneUse())) 133506c3fb27SDimitry Andric break; 13360eae32dcSDimitry Andric 13370eae32dcSDimitry Andric // We need to shift left the AND input and C1 by a total of XLen bits. 13380eae32dcSDimitry Andric 13390eae32dcSDimitry Andric // How far left do we need to shift the AND input? 13400eae32dcSDimitry Andric unsigned XLen = Subtarget->getXLen(); 1341bdd1243dSDimitry Andric unsigned LeadingZeros = XLen - llvm::bit_width(C2); 13420eae32dcSDimitry Andric 13430eae32dcSDimitry Andric // The constant gets shifted by the remaining amount unless that would 13440eae32dcSDimitry Andric // shift bits out. 13450eae32dcSDimitry Andric uint64_t C1 = N1C->getZExtValue(); 13460eae32dcSDimitry Andric unsigned ConstantShift = XLen - LeadingZeros; 1347bdd1243dSDimitry Andric if (ConstantShift > (XLen - llvm::bit_width(C1))) 13480eae32dcSDimitry Andric break; 13490eae32dcSDimitry Andric 13500eae32dcSDimitry Andric uint64_t ShiftedC1 = C1 << ConstantShift; 13510eae32dcSDimitry Andric // If this RV32, we need to sign extend the constant. 13520eae32dcSDimitry Andric if (XLen == 32) 135381ad6265SDimitry Andric ShiftedC1 = SignExtend64<32>(ShiftedC1); 13540eae32dcSDimitry Andric 13550eae32dcSDimitry Andric // Create (mulhu (slli X, lzcnt(C2)), C1 << (XLen - lzcnt(C2))). 135606c3fb27SDimitry Andric SDNode *Imm = selectImm(CurDAG, DL, VT, ShiftedC1, *Subtarget).getNode(); 13570eae32dcSDimitry Andric SDNode *SLLI = 13580eae32dcSDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0.getOperand(0), 13590eae32dcSDimitry Andric CurDAG->getTargetConstant(LeadingZeros, DL, VT)); 13600eae32dcSDimitry Andric SDNode *MULHU = CurDAG->getMachineNode(RISCV::MULHU, DL, VT, 13610eae32dcSDimitry Andric SDValue(SLLI, 0), SDValue(Imm, 0)); 13620eae32dcSDimitry Andric ReplaceNode(Node, MULHU); 13630eae32dcSDimitry Andric return; 13640eae32dcSDimitry Andric } 136506c3fb27SDimitry Andric case ISD::LOAD: { 136606c3fb27SDimitry Andric if (tryIndexedLoad(Node)) 136706c3fb27SDimitry Andric return; 136806c3fb27SDimitry Andric break; 136906c3fb27SDimitry Andric } 1370fe6060f1SDimitry Andric case ISD::INTRINSIC_WO_CHAIN: { 1371fe6060f1SDimitry Andric unsigned IntNo = Node->getConstantOperandVal(0); 1372fe6060f1SDimitry Andric switch (IntNo) { 1373fe6060f1SDimitry Andric // By default we do not custom select any intrinsic. 1374fe6060f1SDimitry Andric default: 1375fe6060f1SDimitry Andric break; 1376fe6060f1SDimitry Andric case Intrinsic::riscv_vmsgeu: 1377fe6060f1SDimitry Andric case Intrinsic::riscv_vmsge: { 1378fe6060f1SDimitry Andric SDValue Src1 = Node->getOperand(1); 1379fe6060f1SDimitry Andric SDValue Src2 = Node->getOperand(2); 138004eeddc0SDimitry Andric bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu; 138104eeddc0SDimitry Andric bool IsCmpUnsignedZero = false; 1382fe6060f1SDimitry Andric // Only custom select scalar second operand. 1383fe6060f1SDimitry Andric if (Src2.getValueType() != XLenVT) 1384fe6060f1SDimitry Andric break; 1385fe6060f1SDimitry Andric // Small constants are handled with patterns. 1386fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Src2)) { 1387fe6060f1SDimitry Andric int64_t CVal = C->getSExtValue(); 138804eeddc0SDimitry Andric if (CVal >= -15 && CVal <= 16) { 138904eeddc0SDimitry Andric if (!IsUnsigned || CVal != 0) 1390fe6060f1SDimitry Andric break; 139104eeddc0SDimitry Andric IsCmpUnsignedZero = true; 1392fe6060f1SDimitry Andric } 139304eeddc0SDimitry Andric } 1394fe6060f1SDimitry Andric MVT Src1VT = Src1.getSimpleValueType(); 139504eeddc0SDimitry Andric unsigned VMSLTOpcode, VMNANDOpcode, VMSetOpcode; 1396fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(Src1VT)) { 1397fe6060f1SDimitry Andric default: 1398fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 139904eeddc0SDimitry Andric #define CASE_VMSLT_VMNAND_VMSET_OPCODES(lmulenum, suffix, suffix_b) \ 140004eeddc0SDimitry Andric case RISCVII::VLMUL::lmulenum: \ 140104eeddc0SDimitry Andric VMSLTOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix \ 140204eeddc0SDimitry Andric : RISCV::PseudoVMSLT_VX_##suffix; \ 140304eeddc0SDimitry Andric VMNANDOpcode = RISCV::PseudoVMNAND_MM_##suffix; \ 140404eeddc0SDimitry Andric VMSetOpcode = RISCV::PseudoVMSET_M_##suffix_b; \ 1405fe6060f1SDimitry Andric break; 140604eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F8, MF8, B1) 140704eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F4, MF4, B2) 140804eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F2, MF2, B4) 140904eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_1, M1, B8) 141004eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_2, M2, B16) 141104eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_4, M4, B32) 141204eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_8, M8, B64) 141304eeddc0SDimitry Andric #undef CASE_VMSLT_VMNAND_VMSET_OPCODES 1414fe6060f1SDimitry Andric } 1415fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant( 1416fe6060f1SDimitry Andric Log2_32(Src1VT.getScalarSizeInBits()), DL, XLenVT); 1417fe6060f1SDimitry Andric SDValue VL; 1418fe6060f1SDimitry Andric selectVLOp(Node->getOperand(3), VL); 1419fe6060f1SDimitry Andric 142004eeddc0SDimitry Andric // If vmsgeu with 0 immediate, expand it to vmset. 142104eeddc0SDimitry Andric if (IsCmpUnsignedZero) { 142204eeddc0SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMSetOpcode, DL, VT, VL, SEW)); 142304eeddc0SDimitry Andric return; 142404eeddc0SDimitry Andric } 142504eeddc0SDimitry Andric 1426fe6060f1SDimitry Andric // Expand to 1427fe6060f1SDimitry Andric // vmslt{u}.vx vd, va, x; vmnand.mm vd, vd, vd 1428fe6060f1SDimitry Andric SDValue Cmp = SDValue( 1429fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTOpcode, DL, VT, {Src1, Src2, VL, SEW}), 1430fe6060f1SDimitry Andric 0); 1431fe6060f1SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMNANDOpcode, DL, VT, 1432fe6060f1SDimitry Andric {Cmp, Cmp, VL, SEW})); 1433fe6060f1SDimitry Andric return; 1434fe6060f1SDimitry Andric } 1435fe6060f1SDimitry Andric case Intrinsic::riscv_vmsgeu_mask: 1436fe6060f1SDimitry Andric case Intrinsic::riscv_vmsge_mask: { 1437fe6060f1SDimitry Andric SDValue Src1 = Node->getOperand(2); 1438fe6060f1SDimitry Andric SDValue Src2 = Node->getOperand(3); 143904eeddc0SDimitry Andric bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu_mask; 144004eeddc0SDimitry Andric bool IsCmpUnsignedZero = false; 1441fe6060f1SDimitry Andric // Only custom select scalar second operand. 1442fe6060f1SDimitry Andric if (Src2.getValueType() != XLenVT) 1443fe6060f1SDimitry Andric break; 1444fe6060f1SDimitry Andric // Small constants are handled with patterns. 1445fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Src2)) { 1446fe6060f1SDimitry Andric int64_t CVal = C->getSExtValue(); 144704eeddc0SDimitry Andric if (CVal >= -15 && CVal <= 16) { 144804eeddc0SDimitry Andric if (!IsUnsigned || CVal != 0) 1449fe6060f1SDimitry Andric break; 145004eeddc0SDimitry Andric IsCmpUnsignedZero = true; 1451fe6060f1SDimitry Andric } 145204eeddc0SDimitry Andric } 1453fe6060f1SDimitry Andric MVT Src1VT = Src1.getSimpleValueType(); 145404eeddc0SDimitry Andric unsigned VMSLTOpcode, VMSLTMaskOpcode, VMXOROpcode, VMANDNOpcode, 145581ad6265SDimitry Andric VMOROpcode; 1456fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(Src1VT)) { 1457fe6060f1SDimitry Andric default: 1458fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 145981ad6265SDimitry Andric #define CASE_VMSLT_OPCODES(lmulenum, suffix, suffix_b) \ 146004eeddc0SDimitry Andric case RISCVII::VLMUL::lmulenum: \ 146104eeddc0SDimitry Andric VMSLTOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix \ 146204eeddc0SDimitry Andric : RISCV::PseudoVMSLT_VX_##suffix; \ 146304eeddc0SDimitry Andric VMSLTMaskOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix##_MASK \ 146404eeddc0SDimitry Andric : RISCV::PseudoVMSLT_VX_##suffix##_MASK; \ 1465fe6060f1SDimitry Andric break; 146681ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_F8, MF8, B1) 146781ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_F4, MF4, B2) 146881ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_F2, MF2, B4) 146981ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_1, M1, B8) 147081ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_2, M2, B16) 147181ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_4, M4, B32) 147281ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_8, M8, B64) 147381ad6265SDimitry Andric #undef CASE_VMSLT_OPCODES 1474fe6060f1SDimitry Andric } 1475fe6060f1SDimitry Andric // Mask operations use the LMUL from the mask type. 1476fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(VT)) { 1477fe6060f1SDimitry Andric default: 1478fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 147981ad6265SDimitry Andric #define CASE_VMXOR_VMANDN_VMOR_OPCODES(lmulenum, suffix) \ 148004eeddc0SDimitry Andric case RISCVII::VLMUL::lmulenum: \ 148104eeddc0SDimitry Andric VMXOROpcode = RISCV::PseudoVMXOR_MM_##suffix; \ 148204eeddc0SDimitry Andric VMANDNOpcode = RISCV::PseudoVMANDN_MM_##suffix; \ 148381ad6265SDimitry Andric VMOROpcode = RISCV::PseudoVMOR_MM_##suffix; \ 1484fe6060f1SDimitry Andric break; 148581ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_F8, MF8) 148681ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_F4, MF4) 148781ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_F2, MF2) 148881ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_1, M1) 148981ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_2, M2) 149081ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_4, M4) 149181ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_8, M8) 149281ad6265SDimitry Andric #undef CASE_VMXOR_VMANDN_VMOR_OPCODES 1493fe6060f1SDimitry Andric } 1494fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant( 1495fe6060f1SDimitry Andric Log2_32(Src1VT.getScalarSizeInBits()), DL, XLenVT); 1496fe6060f1SDimitry Andric SDValue MaskSEW = CurDAG->getTargetConstant(0, DL, XLenVT); 1497fe6060f1SDimitry Andric SDValue VL; 1498fe6060f1SDimitry Andric selectVLOp(Node->getOperand(5), VL); 1499fe6060f1SDimitry Andric SDValue MaskedOff = Node->getOperand(1); 1500fe6060f1SDimitry Andric SDValue Mask = Node->getOperand(4); 150104eeddc0SDimitry Andric 150281ad6265SDimitry Andric // If vmsgeu_mask with 0 immediate, expand it to vmor mask, maskedoff. 150304eeddc0SDimitry Andric if (IsCmpUnsignedZero) { 150481ad6265SDimitry Andric // We don't need vmor if the MaskedOff and the Mask are the same 150581ad6265SDimitry Andric // value. 150681ad6265SDimitry Andric if (Mask == MaskedOff) { 150781ad6265SDimitry Andric ReplaceUses(Node, Mask.getNode()); 150881ad6265SDimitry Andric return; 150981ad6265SDimitry Andric } 151081ad6265SDimitry Andric ReplaceNode(Node, 151181ad6265SDimitry Andric CurDAG->getMachineNode(VMOROpcode, DL, VT, 151281ad6265SDimitry Andric {Mask, MaskedOff, VL, MaskSEW})); 151304eeddc0SDimitry Andric return; 151404eeddc0SDimitry Andric } 151504eeddc0SDimitry Andric 1516fe6060f1SDimitry Andric // If the MaskedOff value and the Mask are the same value use 1517349cc55cSDimitry Andric // vmslt{u}.vx vt, va, x; vmandn.mm vd, vd, vt 1518fe6060f1SDimitry Andric // This avoids needing to copy v0 to vd before starting the next sequence. 1519fe6060f1SDimitry Andric if (Mask == MaskedOff) { 1520fe6060f1SDimitry Andric SDValue Cmp = SDValue( 1521fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTOpcode, DL, VT, {Src1, Src2, VL, SEW}), 1522fe6060f1SDimitry Andric 0); 1523349cc55cSDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMANDNOpcode, DL, VT, 1524fe6060f1SDimitry Andric {Mask, Cmp, VL, MaskSEW})); 1525fe6060f1SDimitry Andric return; 1526fe6060f1SDimitry Andric } 1527fe6060f1SDimitry Andric 1528fe6060f1SDimitry Andric // Mask needs to be copied to V0. 1529fe6060f1SDimitry Andric SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, 1530fe6060f1SDimitry Andric RISCV::V0, Mask, SDValue()); 1531fe6060f1SDimitry Andric SDValue Glue = Chain.getValue(1); 1532fe6060f1SDimitry Andric SDValue V0 = CurDAG->getRegister(RISCV::V0, VT); 1533fe6060f1SDimitry Andric 1534fe6060f1SDimitry Andric // Otherwise use 1535fe6060f1SDimitry Andric // vmslt{u}.vx vd, va, x, v0.t; vmxor.mm vd, vd, v0 153681ad6265SDimitry Andric // The result is mask undisturbed. 153781ad6265SDimitry Andric // We use the same instructions to emulate mask agnostic behavior, because 153881ad6265SDimitry Andric // the agnostic result can be either undisturbed or all 1. 1539fe6060f1SDimitry Andric SDValue Cmp = SDValue( 1540fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTMaskOpcode, DL, VT, 1541fe6060f1SDimitry Andric {MaskedOff, Src1, Src2, V0, VL, SEW, Glue}), 1542fe6060f1SDimitry Andric 0); 154381ad6265SDimitry Andric // vmxor.mm vd, vd, v0 is used to update active value. 1544fe6060f1SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMXOROpcode, DL, VT, 1545fe6060f1SDimitry Andric {Cmp, Mask, VL, MaskSEW})); 1546fe6060f1SDimitry Andric return; 1547fe6060f1SDimitry Andric } 154806c3fb27SDimitry Andric case Intrinsic::riscv_vsetvli: 154906c3fb27SDimitry Andric case Intrinsic::riscv_vsetvlimax: 155004eeddc0SDimitry Andric return selectVSETVLI(Node); 1551fe6060f1SDimitry Andric } 1552fe6060f1SDimitry Andric break; 1553fe6060f1SDimitry Andric } 1554e8d8bef9SDimitry Andric case ISD::INTRINSIC_W_CHAIN: { 1555e8d8bef9SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 1556e8d8bef9SDimitry Andric switch (IntNo) { 1557e8d8bef9SDimitry Andric // By default we do not custom select any intrinsic. 1558e8d8bef9SDimitry Andric default: 15590b57cec5SDimitry Andric break; 1560e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg2: 1561e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg3: 1562e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg4: 1563e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg5: 1564e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg6: 1565e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg7: 1566e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg8: { 1567fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ false, /*IsStrided*/ false); 1568e8d8bef9SDimitry Andric return; 1569e8d8bef9SDimitry Andric } 1570e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg2_mask: 1571e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg3_mask: 1572e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg4_mask: 1573e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg5_mask: 1574e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg6_mask: 1575e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg7_mask: 1576e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg8_mask: { 1577fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ true, /*IsStrided*/ false); 1578e8d8bef9SDimitry Andric return; 1579e8d8bef9SDimitry Andric } 1580e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg2: 1581e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg3: 1582e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg4: 1583e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg5: 1584e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg6: 1585e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg7: 1586e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg8: { 1587fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ false, /*IsStrided*/ true); 1588e8d8bef9SDimitry Andric return; 1589e8d8bef9SDimitry Andric } 1590e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg2_mask: 1591e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg3_mask: 1592e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg4_mask: 1593e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg5_mask: 1594e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg6_mask: 1595e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg7_mask: 1596e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg8_mask: { 1597fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ true, /*IsStrided*/ true); 1598e8d8bef9SDimitry Andric return; 1599e8d8bef9SDimitry Andric } 1600e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg2: 1601e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg3: 1602e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg4: 1603e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg5: 1604e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg6: 1605e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg7: 1606e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg8: 1607fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ true); 1608fe6060f1SDimitry Andric return; 1609e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg2: 1610e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg3: 1611e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg4: 1612e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg5: 1613e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg6: 1614e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg7: 1615fe6060f1SDimitry Andric case Intrinsic::riscv_vluxseg8: 1616fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ false); 1617e8d8bef9SDimitry Andric return; 1618e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg2_mask: 1619e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg3_mask: 1620e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg4_mask: 1621e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg5_mask: 1622e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg6_mask: 1623e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg7_mask: 1624e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg8_mask: 1625fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ true); 1626fe6060f1SDimitry Andric return; 1627e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg2_mask: 1628e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg3_mask: 1629e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg4_mask: 1630e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg5_mask: 1631e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg6_mask: 1632e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg7_mask: 1633fe6060f1SDimitry Andric case Intrinsic::riscv_vluxseg8_mask: 1634fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ false); 1635fe6060f1SDimitry Andric return; 1636fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg8ff: 1637fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg7ff: 1638fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg6ff: 1639fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg5ff: 1640fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg4ff: 1641fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg3ff: 1642fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg2ff: { 1643fe6060f1SDimitry Andric selectVLSEGFF(Node, /*IsMasked*/ false); 1644fe6060f1SDimitry Andric return; 1645fe6060f1SDimitry Andric } 1646fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg8ff_mask: 1647fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg7ff_mask: 1648fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg6ff_mask: 1649fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg5ff_mask: 1650fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg4ff_mask: 1651fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg3ff_mask: 1652fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg2ff_mask: { 1653fe6060f1SDimitry Andric selectVLSEGFF(Node, /*IsMasked*/ true); 1654fe6060f1SDimitry Andric return; 1655fe6060f1SDimitry Andric } 1656fe6060f1SDimitry Andric case Intrinsic::riscv_vloxei: 1657fe6060f1SDimitry Andric case Intrinsic::riscv_vloxei_mask: 1658fe6060f1SDimitry Andric case Intrinsic::riscv_vluxei: 1659fe6060f1SDimitry Andric case Intrinsic::riscv_vluxei_mask: { 1660fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vloxei_mask || 1661fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vluxei_mask; 1662fe6060f1SDimitry Andric bool IsOrdered = IntNo == Intrinsic::riscv_vloxei || 1663fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vloxei_mask; 1664fe6060f1SDimitry Andric 1665fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1666fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1667fe6060f1SDimitry Andric 1668fe6060f1SDimitry Andric unsigned CurOp = 2; 1669fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 1670fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 1671fe6060f1SDimitry Andric 1672fe6060f1SDimitry Andric MVT IndexVT; 1673fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1674fe6060f1SDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 1675349cc55cSDimitry Andric /*IsLoad=*/true, &IndexVT); 1676fe6060f1SDimitry Andric 1677fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 1678fe6060f1SDimitry Andric "Element count mismatch"); 1679fe6060f1SDimitry Andric 1680fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1681fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 1682fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 168304eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 168404eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 168504eeddc0SDimitry Andric "values when XLEN=32"); 168604eeddc0SDimitry Andric } 1687fe6060f1SDimitry Andric const RISCV::VLX_VSXPseudo *P = RISCV::getVLXPseudo( 168806c3fb27SDimitry Andric IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 1689fe6060f1SDimitry Andric static_cast<unsigned>(IndexLMUL)); 1690fe6060f1SDimitry Andric MachineSDNode *Load = 1691fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1692fe6060f1SDimitry Andric 1693fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1694fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1695fe6060f1SDimitry Andric 1696fe6060f1SDimitry Andric ReplaceNode(Node, Load); 1697fe6060f1SDimitry Andric return; 1698fe6060f1SDimitry Andric } 1699349cc55cSDimitry Andric case Intrinsic::riscv_vlm: 1700fe6060f1SDimitry Andric case Intrinsic::riscv_vle: 1701fe6060f1SDimitry Andric case Intrinsic::riscv_vle_mask: 1702fe6060f1SDimitry Andric case Intrinsic::riscv_vlse: 1703fe6060f1SDimitry Andric case Intrinsic::riscv_vlse_mask: { 1704fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vle_mask || 1705fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vlse_mask; 1706fe6060f1SDimitry Andric bool IsStrided = 1707fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vlse || IntNo == Intrinsic::riscv_vlse_mask; 1708fe6060f1SDimitry Andric 1709fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1710fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1711fe6060f1SDimitry Andric 171206c3fb27SDimitry Andric // The riscv_vlm intrinsic are always tail agnostic and no passthru 171306c3fb27SDimitry Andric // operand at the IR level. In pseudos, they have both policy and 171406c3fb27SDimitry Andric // passthru operand. The passthru operand is needed to track the 171506c3fb27SDimitry Andric // "tail undefined" state, and the policy is there just for 171606c3fb27SDimitry Andric // for consistency - it will always be "don't care" for the 171706c3fb27SDimitry Andric // unmasked form. 171804eeddc0SDimitry Andric bool HasPassthruOperand = IntNo != Intrinsic::riscv_vlm; 171906c3fb27SDimitry Andric unsigned CurOp = 2; 1720fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 172106c3fb27SDimitry Andric if (HasPassthruOperand) 1722fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 172306c3fb27SDimitry Andric else { 172406c3fb27SDimitry Andric // We eagerly lower to implicit_def (instead of undef), as we 172506c3fb27SDimitry Andric // otherwise fail to select nodes such as: nxv1i1 = undef 172606c3fb27SDimitry Andric SDNode *Passthru = 172706c3fb27SDimitry Andric CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, VT); 172806c3fb27SDimitry Andric Operands.push_back(SDValue(Passthru, 0)); 172906c3fb27SDimitry Andric } 1730fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 1731349cc55cSDimitry Andric Operands, /*IsLoad=*/true); 1732fe6060f1SDimitry Andric 1733fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1734fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = 173506c3fb27SDimitry Andric RISCV::getVLEPseudo(IsMasked, IsStrided, /*FF*/ false, Log2SEW, 1736fe6060f1SDimitry Andric static_cast<unsigned>(LMUL)); 1737fe6060f1SDimitry Andric MachineSDNode *Load = 1738fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1739fe6060f1SDimitry Andric 1740fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1741fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1742fe6060f1SDimitry Andric 1743fe6060f1SDimitry Andric ReplaceNode(Node, Load); 1744fe6060f1SDimitry Andric return; 1745fe6060f1SDimitry Andric } 1746fe6060f1SDimitry Andric case Intrinsic::riscv_vleff: 1747fe6060f1SDimitry Andric case Intrinsic::riscv_vleff_mask: { 1748fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vleff_mask; 1749fe6060f1SDimitry Andric 1750fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1751fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1752fe6060f1SDimitry Andric 1753fe6060f1SDimitry Andric unsigned CurOp = 2; 1754fe6060f1SDimitry Andric SmallVector<SDValue, 7> Operands; 1755fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 1756fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1757349cc55cSDimitry Andric /*IsStridedOrIndexed*/ false, Operands, 1758349cc55cSDimitry Andric /*IsLoad=*/true); 1759fe6060f1SDimitry Andric 1760fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1761fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = 176206c3fb27SDimitry Andric RISCV::getVLEPseudo(IsMasked, /*Strided*/ false, /*FF*/ true, 176304eeddc0SDimitry Andric Log2SEW, static_cast<unsigned>(LMUL)); 176481ad6265SDimitry Andric MachineSDNode *Load = CurDAG->getMachineNode( 176581ad6265SDimitry Andric P->Pseudo, DL, Node->getVTList(), Operands); 1766fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1767fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1768fe6060f1SDimitry Andric 176981ad6265SDimitry Andric ReplaceNode(Node, Load); 17700b57cec5SDimitry Andric return; 17710b57cec5SDimitry Andric } 17720b57cec5SDimitry Andric } 17730b57cec5SDimitry Andric break; 17740b57cec5SDimitry Andric } 1775e8d8bef9SDimitry Andric case ISD::INTRINSIC_VOID: { 1776e8d8bef9SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 1777e8d8bef9SDimitry Andric switch (IntNo) { 1778e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg2: 1779e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg3: 1780e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg4: 1781e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg5: 1782e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg6: 1783e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg7: 1784e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg8: { 1785fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ false, /*IsStrided*/ false); 17860b57cec5SDimitry Andric return; 17870b57cec5SDimitry Andric } 1788e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg2_mask: 1789e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg3_mask: 1790e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg4_mask: 1791e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg5_mask: 1792e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg6_mask: 1793e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg7_mask: 1794e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg8_mask: { 1795fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ true, /*IsStrided*/ false); 1796e8d8bef9SDimitry Andric return; 1797e8d8bef9SDimitry Andric } 1798e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg2: 1799e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg3: 1800e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg4: 1801e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg5: 1802e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg6: 1803e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg7: 1804e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg8: { 1805fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ false, /*IsStrided*/ true); 1806e8d8bef9SDimitry Andric return; 1807e8d8bef9SDimitry Andric } 1808e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg2_mask: 1809e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg3_mask: 1810e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg4_mask: 1811e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg5_mask: 1812e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg6_mask: 1813e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg7_mask: 1814e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg8_mask: { 1815fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ true, /*IsStrided*/ true); 1816e8d8bef9SDimitry Andric return; 1817e8d8bef9SDimitry Andric } 1818e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg2: 1819e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg3: 1820e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg4: 1821e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg5: 1822e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg6: 1823e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg7: 1824e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg8: 1825fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ true); 1826fe6060f1SDimitry Andric return; 1827e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg2: 1828e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg3: 1829e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg4: 1830e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg5: 1831e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg6: 1832e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg7: 1833fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxseg8: 1834fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ false); 1835e8d8bef9SDimitry Andric return; 1836e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg2_mask: 1837e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg3_mask: 1838e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg4_mask: 1839e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg5_mask: 1840e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg6_mask: 1841e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg7_mask: 1842e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg8_mask: 1843fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ true); 1844fe6060f1SDimitry Andric return; 1845e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg2_mask: 1846e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg3_mask: 1847e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg4_mask: 1848e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg5_mask: 1849e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg6_mask: 1850e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg7_mask: 1851fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxseg8_mask: 1852fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ false); 1853fe6060f1SDimitry Andric return; 1854fe6060f1SDimitry Andric case Intrinsic::riscv_vsoxei: 1855fe6060f1SDimitry Andric case Intrinsic::riscv_vsoxei_mask: 1856fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxei: 1857fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxei_mask: { 1858fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vsoxei_mask || 1859fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsuxei_mask; 1860fe6060f1SDimitry Andric bool IsOrdered = IntNo == Intrinsic::riscv_vsoxei || 1861fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsoxei_mask; 1862fe6060f1SDimitry Andric 1863fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 1864fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1865fe6060f1SDimitry Andric 1866fe6060f1SDimitry Andric unsigned CurOp = 2; 1867fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 1868fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Store value. 1869fe6060f1SDimitry Andric 1870fe6060f1SDimitry Andric MVT IndexVT; 1871fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1872fe6060f1SDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 1873349cc55cSDimitry Andric /*IsLoad=*/false, &IndexVT); 1874fe6060f1SDimitry Andric 1875fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 1876fe6060f1SDimitry Andric "Element count mismatch"); 1877fe6060f1SDimitry Andric 1878fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1879fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 1880fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 188104eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 188204eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 188304eeddc0SDimitry Andric "values when XLEN=32"); 188404eeddc0SDimitry Andric } 1885fe6060f1SDimitry Andric const RISCV::VLX_VSXPseudo *P = RISCV::getVSXPseudo( 188606c3fb27SDimitry Andric IsMasked, IsOrdered, IndexLog2EEW, 188704eeddc0SDimitry Andric static_cast<unsigned>(LMUL), static_cast<unsigned>(IndexLMUL)); 1888fe6060f1SDimitry Andric MachineSDNode *Store = 1889fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1890fe6060f1SDimitry Andric 1891fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1892fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 1893fe6060f1SDimitry Andric 1894fe6060f1SDimitry Andric ReplaceNode(Node, Store); 1895fe6060f1SDimitry Andric return; 1896fe6060f1SDimitry Andric } 1897349cc55cSDimitry Andric case Intrinsic::riscv_vsm: 1898fe6060f1SDimitry Andric case Intrinsic::riscv_vse: 1899fe6060f1SDimitry Andric case Intrinsic::riscv_vse_mask: 1900fe6060f1SDimitry Andric case Intrinsic::riscv_vsse: 1901fe6060f1SDimitry Andric case Intrinsic::riscv_vsse_mask: { 1902fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vse_mask || 1903fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsse_mask; 1904fe6060f1SDimitry Andric bool IsStrided = 1905fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsse || IntNo == Intrinsic::riscv_vsse_mask; 1906fe6060f1SDimitry Andric 1907fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 1908fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1909fe6060f1SDimitry Andric 1910fe6060f1SDimitry Andric unsigned CurOp = 2; 1911fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 1912fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Store value. 1913fe6060f1SDimitry Andric 1914fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 1915fe6060f1SDimitry Andric Operands); 1916fe6060f1SDimitry Andric 1917fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1918fe6060f1SDimitry Andric const RISCV::VSEPseudo *P = RISCV::getVSEPseudo( 1919fe6060f1SDimitry Andric IsMasked, IsStrided, Log2SEW, static_cast<unsigned>(LMUL)); 1920fe6060f1SDimitry Andric MachineSDNode *Store = 1921fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1922fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1923fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 1924fe6060f1SDimitry Andric 1925fe6060f1SDimitry Andric ReplaceNode(Node, Store); 1926e8d8bef9SDimitry Andric return; 1927e8d8bef9SDimitry Andric } 1928e8d8bef9SDimitry Andric } 1929e8d8bef9SDimitry Andric break; 1930e8d8bef9SDimitry Andric } 1931fe6060f1SDimitry Andric case ISD::BITCAST: { 1932fe6060f1SDimitry Andric MVT SrcVT = Node->getOperand(0).getSimpleValueType(); 1933fe6060f1SDimitry Andric // Just drop bitcasts between vectors if both are fixed or both are 1934fe6060f1SDimitry Andric // scalable. 1935fe6060f1SDimitry Andric if ((VT.isScalableVector() && SrcVT.isScalableVector()) || 1936fe6060f1SDimitry Andric (VT.isFixedLengthVector() && SrcVT.isFixedLengthVector())) { 1937fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, 0), Node->getOperand(0)); 1938fe6060f1SDimitry Andric CurDAG->RemoveDeadNode(Node); 1939e8d8bef9SDimitry Andric return; 1940e8d8bef9SDimitry Andric } 1941fe6060f1SDimitry Andric break; 1942fe6060f1SDimitry Andric } 1943fe6060f1SDimitry Andric case ISD::INSERT_SUBVECTOR: { 1944fe6060f1SDimitry Andric SDValue V = Node->getOperand(0); 1945fe6060f1SDimitry Andric SDValue SubV = Node->getOperand(1); 1946fe6060f1SDimitry Andric SDLoc DL(SubV); 1947fe6060f1SDimitry Andric auto Idx = Node->getConstantOperandVal(2); 1948fe6060f1SDimitry Andric MVT SubVecVT = SubV.getSimpleValueType(); 1949fe6060f1SDimitry Andric 1950fe6060f1SDimitry Andric const RISCVTargetLowering &TLI = *Subtarget->getTargetLowering(); 1951fe6060f1SDimitry Andric MVT SubVecContainerVT = SubVecVT; 1952fe6060f1SDimitry Andric // Establish the correct scalable-vector types for any fixed-length type. 1953fe6060f1SDimitry Andric if (SubVecVT.isFixedLengthVector()) 1954fe6060f1SDimitry Andric SubVecContainerVT = TLI.getContainerForFixedLengthVector(SubVecVT); 1955fe6060f1SDimitry Andric if (VT.isFixedLengthVector()) 1956fe6060f1SDimitry Andric VT = TLI.getContainerForFixedLengthVector(VT); 1957fe6060f1SDimitry Andric 1958fe6060f1SDimitry Andric const auto *TRI = Subtarget->getRegisterInfo(); 1959fe6060f1SDimitry Andric unsigned SubRegIdx; 1960fe6060f1SDimitry Andric std::tie(SubRegIdx, Idx) = 1961fe6060f1SDimitry Andric RISCVTargetLowering::decomposeSubvectorInsertExtractToSubRegs( 1962fe6060f1SDimitry Andric VT, SubVecContainerVT, Idx, TRI); 1963fe6060f1SDimitry Andric 1964fe6060f1SDimitry Andric // If the Idx hasn't been completely eliminated then this is a subvector 1965fe6060f1SDimitry Andric // insert which doesn't naturally align to a vector register. These must 1966fe6060f1SDimitry Andric // be handled using instructions to manipulate the vector registers. 1967fe6060f1SDimitry Andric if (Idx != 0) 1968fe6060f1SDimitry Andric break; 1969fe6060f1SDimitry Andric 1970fe6060f1SDimitry Andric RISCVII::VLMUL SubVecLMUL = RISCVTargetLowering::getLMUL(SubVecContainerVT); 1971fe6060f1SDimitry Andric bool IsSubVecPartReg = SubVecLMUL == RISCVII::VLMUL::LMUL_F2 || 1972fe6060f1SDimitry Andric SubVecLMUL == RISCVII::VLMUL::LMUL_F4 || 1973fe6060f1SDimitry Andric SubVecLMUL == RISCVII::VLMUL::LMUL_F8; 1974fe6060f1SDimitry Andric (void)IsSubVecPartReg; // Silence unused variable warning without asserts. 1975fe6060f1SDimitry Andric assert((!IsSubVecPartReg || V.isUndef()) && 1976fe6060f1SDimitry Andric "Expecting lowering to have created legal INSERT_SUBVECTORs when " 1977fe6060f1SDimitry Andric "the subvector is smaller than a full-sized register"); 1978fe6060f1SDimitry Andric 1979fe6060f1SDimitry Andric // If we haven't set a SubRegIdx, then we must be going between 1980fe6060f1SDimitry Andric // equally-sized LMUL groups (e.g. VR -> VR). This can be done as a copy. 1981fe6060f1SDimitry Andric if (SubRegIdx == RISCV::NoSubRegister) { 1982fe6060f1SDimitry Andric unsigned InRegClassID = RISCVTargetLowering::getRegClassIDForVecVT(VT); 1983fe6060f1SDimitry Andric assert(RISCVTargetLowering::getRegClassIDForVecVT(SubVecContainerVT) == 1984fe6060f1SDimitry Andric InRegClassID && 1985fe6060f1SDimitry Andric "Unexpected subvector extraction"); 1986fe6060f1SDimitry Andric SDValue RC = CurDAG->getTargetConstant(InRegClassID, DL, XLenVT); 1987fe6060f1SDimitry Andric SDNode *NewNode = CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, 1988fe6060f1SDimitry Andric DL, VT, SubV, RC); 1989fe6060f1SDimitry Andric ReplaceNode(Node, NewNode); 1990fe6060f1SDimitry Andric return; 1991fe6060f1SDimitry Andric } 1992fe6060f1SDimitry Andric 1993fe6060f1SDimitry Andric SDValue Insert = CurDAG->getTargetInsertSubreg(SubRegIdx, DL, VT, V, SubV); 1994fe6060f1SDimitry Andric ReplaceNode(Node, Insert.getNode()); 1995fe6060f1SDimitry Andric return; 1996fe6060f1SDimitry Andric } 1997fe6060f1SDimitry Andric case ISD::EXTRACT_SUBVECTOR: { 1998fe6060f1SDimitry Andric SDValue V = Node->getOperand(0); 1999fe6060f1SDimitry Andric auto Idx = Node->getConstantOperandVal(1); 2000fe6060f1SDimitry Andric MVT InVT = V.getSimpleValueType(); 2001fe6060f1SDimitry Andric SDLoc DL(V); 2002fe6060f1SDimitry Andric 2003fe6060f1SDimitry Andric const RISCVTargetLowering &TLI = *Subtarget->getTargetLowering(); 2004fe6060f1SDimitry Andric MVT SubVecContainerVT = VT; 2005fe6060f1SDimitry Andric // Establish the correct scalable-vector types for any fixed-length type. 2006fe6060f1SDimitry Andric if (VT.isFixedLengthVector()) 2007fe6060f1SDimitry Andric SubVecContainerVT = TLI.getContainerForFixedLengthVector(VT); 2008fe6060f1SDimitry Andric if (InVT.isFixedLengthVector()) 2009fe6060f1SDimitry Andric InVT = TLI.getContainerForFixedLengthVector(InVT); 2010fe6060f1SDimitry Andric 2011fe6060f1SDimitry Andric const auto *TRI = Subtarget->getRegisterInfo(); 2012fe6060f1SDimitry Andric unsigned SubRegIdx; 2013fe6060f1SDimitry Andric std::tie(SubRegIdx, Idx) = 2014fe6060f1SDimitry Andric RISCVTargetLowering::decomposeSubvectorInsertExtractToSubRegs( 2015fe6060f1SDimitry Andric InVT, SubVecContainerVT, Idx, TRI); 2016fe6060f1SDimitry Andric 2017fe6060f1SDimitry Andric // If the Idx hasn't been completely eliminated then this is a subvector 2018fe6060f1SDimitry Andric // extract which doesn't naturally align to a vector register. These must 2019fe6060f1SDimitry Andric // be handled using instructions to manipulate the vector registers. 2020fe6060f1SDimitry Andric if (Idx != 0) 2021fe6060f1SDimitry Andric break; 2022fe6060f1SDimitry Andric 2023fe6060f1SDimitry Andric // If we haven't set a SubRegIdx, then we must be going between 2024fe6060f1SDimitry Andric // equally-sized LMUL types (e.g. VR -> VR). This can be done as a copy. 2025fe6060f1SDimitry Andric if (SubRegIdx == RISCV::NoSubRegister) { 2026fe6060f1SDimitry Andric unsigned InRegClassID = RISCVTargetLowering::getRegClassIDForVecVT(InVT); 2027fe6060f1SDimitry Andric assert(RISCVTargetLowering::getRegClassIDForVecVT(SubVecContainerVT) == 2028fe6060f1SDimitry Andric InRegClassID && 2029fe6060f1SDimitry Andric "Unexpected subvector extraction"); 2030fe6060f1SDimitry Andric SDValue RC = CurDAG->getTargetConstant(InRegClassID, DL, XLenVT); 2031fe6060f1SDimitry Andric SDNode *NewNode = 2032fe6060f1SDimitry Andric CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, VT, V, RC); 2033fe6060f1SDimitry Andric ReplaceNode(Node, NewNode); 2034fe6060f1SDimitry Andric return; 2035fe6060f1SDimitry Andric } 2036fe6060f1SDimitry Andric 2037fe6060f1SDimitry Andric SDValue Extract = CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, V); 2038fe6060f1SDimitry Andric ReplaceNode(Node, Extract.getNode()); 2039fe6060f1SDimitry Andric return; 2040fe6060f1SDimitry Andric } 204104eeddc0SDimitry Andric case RISCVISD::VMV_S_X_VL: 204204eeddc0SDimitry Andric case RISCVISD::VFMV_S_F_VL: 2043fe6060f1SDimitry Andric case RISCVISD::VMV_V_X_VL: 2044fe6060f1SDimitry Andric case RISCVISD::VFMV_V_F_VL: { 2045fe6060f1SDimitry Andric // Try to match splat of a scalar load to a strided load with stride of x0. 204604eeddc0SDimitry Andric bool IsScalarMove = Node->getOpcode() == RISCVISD::VMV_S_X_VL || 204704eeddc0SDimitry Andric Node->getOpcode() == RISCVISD::VFMV_S_F_VL; 2048bdd1243dSDimitry Andric if (!Node->getOperand(0).isUndef()) 204904eeddc0SDimitry Andric break; 2050bdd1243dSDimitry Andric SDValue Src = Node->getOperand(1); 2051fe6060f1SDimitry Andric auto *Ld = dyn_cast<LoadSDNode>(Src); 205206c3fb27SDimitry Andric // Can't fold load update node because the second 205306c3fb27SDimitry Andric // output is used so that load update node can't be removed. 205406c3fb27SDimitry Andric if (!Ld || Ld->isIndexed()) 2055fe6060f1SDimitry Andric break; 2056fe6060f1SDimitry Andric EVT MemVT = Ld->getMemoryVT(); 2057fe6060f1SDimitry Andric // The memory VT should be the same size as the element type. 2058fe6060f1SDimitry Andric if (MemVT.getStoreSize() != VT.getVectorElementType().getStoreSize()) 2059fe6060f1SDimitry Andric break; 2060fe6060f1SDimitry Andric if (!IsProfitableToFold(Src, Node, Node) || 2061fe6060f1SDimitry Andric !IsLegalToFold(Src, Node, Node, TM.getOptLevel())) 2062fe6060f1SDimitry Andric break; 2063fe6060f1SDimitry Andric 2064fe6060f1SDimitry Andric SDValue VL; 2065bdd1243dSDimitry Andric if (IsScalarMove) { 206604eeddc0SDimitry Andric // We could deal with more VL if we update the VSETVLI insert pass to 206704eeddc0SDimitry Andric // avoid introducing more VSETVLI. 206804eeddc0SDimitry Andric if (!isOneConstant(Node->getOperand(2))) 206904eeddc0SDimitry Andric break; 207004eeddc0SDimitry Andric selectVLOp(Node->getOperand(2), VL); 207104eeddc0SDimitry Andric } else 207281ad6265SDimitry Andric selectVLOp(Node->getOperand(2), VL); 2073fe6060f1SDimitry Andric 2074fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 2075fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(Log2SEW, DL, XLenVT); 2076fe6060f1SDimitry Andric 207706c3fb27SDimitry Andric // If VL=1, then we don't need to do a strided load and can just do a 207806c3fb27SDimitry Andric // regular load. 207906c3fb27SDimitry Andric bool IsStrided = !isOneConstant(VL); 208006c3fb27SDimitry Andric 208106c3fb27SDimitry Andric // Only do a strided load if we have optimized zero-stride vector load. 208206c3fb27SDimitry Andric if (IsStrided && !Subtarget->hasOptimizedZeroStrideLoad()) 208306c3fb27SDimitry Andric break; 208406c3fb27SDimitry Andric 208506c3fb27SDimitry Andric SmallVector<SDValue> Operands = 208606c3fb27SDimitry Andric {CurDAG->getUNDEF(VT), Ld->getBasePtr()}; 208706c3fb27SDimitry Andric if (IsStrided) 208806c3fb27SDimitry Andric Operands.push_back(CurDAG->getRegister(RISCV::X0, XLenVT)); 208906c3fb27SDimitry Andric uint64_t Policy = RISCVII::MASK_AGNOSTIC | RISCVII::TAIL_AGNOSTIC; 209006c3fb27SDimitry Andric SDValue PolicyOp = CurDAG->getTargetConstant(Policy, DL, XLenVT); 209106c3fb27SDimitry Andric Operands.append({VL, SEW, PolicyOp, Ld->getChain()}); 2092fe6060f1SDimitry Andric 2093fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 2094fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = RISCV::getVLEPseudo( 209506c3fb27SDimitry Andric /*IsMasked*/ false, IsStrided, /*FF*/ false, 209604eeddc0SDimitry Andric Log2SEW, static_cast<unsigned>(LMUL)); 2097fe6060f1SDimitry Andric MachineSDNode *Load = 2098bdd1243dSDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, {VT, MVT::Other}, Operands); 2099bdd1243dSDimitry Andric // Update the chain. 2100bdd1243dSDimitry Andric ReplaceUses(Src.getValue(1), SDValue(Load, 1)); 2101bdd1243dSDimitry Andric // Record the mem-refs 210281ad6265SDimitry Andric CurDAG->setNodeMemRefs(Load, {Ld->getMemOperand()}); 2103bdd1243dSDimitry Andric // Replace the splat with the vlse. 2104fe6060f1SDimitry Andric ReplaceNode(Node, Load); 2105e8d8bef9SDimitry Andric return; 2106e8d8bef9SDimitry Andric } 210706c3fb27SDimitry Andric case ISD::PREFETCH: 210806c3fb27SDimitry Andric unsigned Locality = Node->getConstantOperandVal(3); 210906c3fb27SDimitry Andric if (Locality > 2) 211006c3fb27SDimitry Andric break; 211106c3fb27SDimitry Andric 211206c3fb27SDimitry Andric if (auto *LoadStoreMem = dyn_cast<MemSDNode>(Node)) { 211306c3fb27SDimitry Andric MachineMemOperand *MMO = LoadStoreMem->getMemOperand(); 211406c3fb27SDimitry Andric MMO->setFlags(MachineMemOperand::MONonTemporal); 211506c3fb27SDimitry Andric 211606c3fb27SDimitry Andric int NontemporalLevel = 0; 211706c3fb27SDimitry Andric switch (Locality) { 211806c3fb27SDimitry Andric case 0: 211906c3fb27SDimitry Andric NontemporalLevel = 3; // NTL.ALL 212006c3fb27SDimitry Andric break; 212106c3fb27SDimitry Andric case 1: 212206c3fb27SDimitry Andric NontemporalLevel = 1; // NTL.PALL 212306c3fb27SDimitry Andric break; 212406c3fb27SDimitry Andric case 2: 212506c3fb27SDimitry Andric NontemporalLevel = 0; // NTL.P1 212606c3fb27SDimitry Andric break; 212706c3fb27SDimitry Andric default: 212806c3fb27SDimitry Andric llvm_unreachable("unexpected locality value."); 212906c3fb27SDimitry Andric } 213006c3fb27SDimitry Andric 213106c3fb27SDimitry Andric if (NontemporalLevel & 0b1) 213206c3fb27SDimitry Andric MMO->setFlags(MONontemporalBit0); 213306c3fb27SDimitry Andric if (NontemporalLevel & 0b10) 213406c3fb27SDimitry Andric MMO->setFlags(MONontemporalBit1); 213506c3fb27SDimitry Andric } 213606c3fb27SDimitry Andric break; 2137e8d8bef9SDimitry Andric } 21380b57cec5SDimitry Andric 21390b57cec5SDimitry Andric // Select the default instruction. 21400b57cec5SDimitry Andric SelectCode(Node); 21410b57cec5SDimitry Andric } 21420b57cec5SDimitry Andric 21430b57cec5SDimitry Andric bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand( 21440b57cec5SDimitry Andric const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { 214506c3fb27SDimitry Andric // Always produce a register and immediate operand, as expected by 214606c3fb27SDimitry Andric // RISCVAsmPrinter::PrintAsmMemoryOperand. 21470b57cec5SDimitry Andric switch (ConstraintID) { 214806c3fb27SDimitry Andric case InlineAsm::Constraint_o: 214906c3fb27SDimitry Andric case InlineAsm::Constraint_m: { 215006c3fb27SDimitry Andric SDValue Op0, Op1; 215106c3fb27SDimitry Andric bool Found = SelectAddrRegImm(Op, Op0, Op1); 215206c3fb27SDimitry Andric assert(Found && "SelectAddrRegImm should always succeed"); 215306c3fb27SDimitry Andric (void)Found; 215406c3fb27SDimitry Andric OutOps.push_back(Op0); 215506c3fb27SDimitry Andric OutOps.push_back(Op1); 21560b57cec5SDimitry Andric return false; 215706c3fb27SDimitry Andric } 21580b57cec5SDimitry Andric case InlineAsm::Constraint_A: 21590b57cec5SDimitry Andric OutOps.push_back(Op); 216006c3fb27SDimitry Andric OutOps.push_back( 216106c3fb27SDimitry Andric CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getXLenVT())); 21620b57cec5SDimitry Andric return false; 21630b57cec5SDimitry Andric default: 216406c3fb27SDimitry Andric report_fatal_error("Unexpected asm memory constraint " + 216506c3fb27SDimitry Andric InlineAsm::getMemConstraintName(ConstraintID)); 21660b57cec5SDimitry Andric } 21670b57cec5SDimitry Andric 21680b57cec5SDimitry Andric return true; 21690b57cec5SDimitry Andric } 21700b57cec5SDimitry Andric 217181ad6265SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrFrameIndex(SDValue Addr, SDValue &Base, 217281ad6265SDimitry Andric SDValue &Offset) { 2173fe6060f1SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 21740b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT()); 217581ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), Subtarget->getXLenVT()); 21760b57cec5SDimitry Andric return true; 21770b57cec5SDimitry Andric } 217881ad6265SDimitry Andric 217981ad6265SDimitry Andric return false; 218081ad6265SDimitry Andric } 218181ad6265SDimitry Andric 218281ad6265SDimitry Andric // Select a frame index and an optional immediate offset from an ADD or OR. 218381ad6265SDimitry Andric bool RISCVDAGToDAGISel::SelectFrameAddrRegImm(SDValue Addr, SDValue &Base, 218481ad6265SDimitry Andric SDValue &Offset) { 218581ad6265SDimitry Andric if (SelectAddrFrameIndex(Addr, Base, Offset)) 218681ad6265SDimitry Andric return true; 218781ad6265SDimitry Andric 218881ad6265SDimitry Andric if (!CurDAG->isBaseWithConstantOffset(Addr)) 218981ad6265SDimitry Andric return false; 219081ad6265SDimitry Andric 219181ad6265SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) { 219281ad6265SDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 219381ad6265SDimitry Andric if (isInt<12>(CVal)) { 219481ad6265SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), 219581ad6265SDimitry Andric Subtarget->getXLenVT()); 219681ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(CVal, SDLoc(Addr), 219781ad6265SDimitry Andric Subtarget->getXLenVT()); 219881ad6265SDimitry Andric return true; 219981ad6265SDimitry Andric } 220081ad6265SDimitry Andric } 220181ad6265SDimitry Andric 22020b57cec5SDimitry Andric return false; 22030b57cec5SDimitry Andric } 22040b57cec5SDimitry Andric 2205753f127fSDimitry Andric // Fold constant addresses. 2206753f127fSDimitry Andric static bool selectConstantAddr(SelectionDAG *CurDAG, const SDLoc &DL, 2207753f127fSDimitry Andric const MVT VT, const RISCVSubtarget *Subtarget, 2208753f127fSDimitry Andric SDValue Addr, SDValue &Base, SDValue &Offset) { 2209753f127fSDimitry Andric if (!isa<ConstantSDNode>(Addr)) 2210753f127fSDimitry Andric return false; 2211753f127fSDimitry Andric 2212753f127fSDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr)->getSExtValue(); 2213753f127fSDimitry Andric 2214753f127fSDimitry Andric // If the constant is a simm12, we can fold the whole constant and use X0 as 2215753f127fSDimitry Andric // the base. If the constant can be materialized with LUI+simm12, use LUI as 2216753f127fSDimitry Andric // the base. We can't use generateInstSeq because it favors LUI+ADDIW. 2217753f127fSDimitry Andric int64_t Lo12 = SignExtend64<12>(CVal); 2218753f127fSDimitry Andric int64_t Hi = (uint64_t)CVal - (uint64_t)Lo12; 2219753f127fSDimitry Andric if (!Subtarget->is64Bit() || isInt<32>(Hi)) { 2220753f127fSDimitry Andric if (Hi) { 2221753f127fSDimitry Andric int64_t Hi20 = (Hi >> 12) & 0xfffff; 2222753f127fSDimitry Andric Base = SDValue( 2223753f127fSDimitry Andric CurDAG->getMachineNode(RISCV::LUI, DL, VT, 2224753f127fSDimitry Andric CurDAG->getTargetConstant(Hi20, DL, VT)), 2225753f127fSDimitry Andric 0); 2226753f127fSDimitry Andric } else { 2227753f127fSDimitry Andric Base = CurDAG->getRegister(RISCV::X0, VT); 2228753f127fSDimitry Andric } 2229753f127fSDimitry Andric Offset = CurDAG->getTargetConstant(Lo12, DL, VT); 2230753f127fSDimitry Andric return true; 2231753f127fSDimitry Andric } 2232753f127fSDimitry Andric 2233753f127fSDimitry Andric // Ask how constant materialization would handle this constant. 2234753f127fSDimitry Andric RISCVMatInt::InstSeq Seq = 2235753f127fSDimitry Andric RISCVMatInt::generateInstSeq(CVal, Subtarget->getFeatureBits()); 2236753f127fSDimitry Andric 2237753f127fSDimitry Andric // If the last instruction would be an ADDI, we can fold its immediate and 2238753f127fSDimitry Andric // emit the rest of the sequence as the base. 2239bdd1243dSDimitry Andric if (Seq.back().getOpcode() != RISCV::ADDI) 2240753f127fSDimitry Andric return false; 2241bdd1243dSDimitry Andric Lo12 = Seq.back().getImm(); 2242753f127fSDimitry Andric 2243753f127fSDimitry Andric // Drop the last instruction. 2244753f127fSDimitry Andric Seq.pop_back(); 2245753f127fSDimitry Andric assert(!Seq.empty() && "Expected more instructions in sequence"); 2246753f127fSDimitry Andric 224706c3fb27SDimitry Andric Base = selectImmSeq(CurDAG, DL, VT, Seq); 2248753f127fSDimitry Andric Offset = CurDAG->getTargetConstant(Lo12, DL, VT); 2249753f127fSDimitry Andric return true; 2250753f127fSDimitry Andric } 2251753f127fSDimitry Andric 2252753f127fSDimitry Andric // Is this ADD instruction only used as the base pointer of scalar loads and 2253753f127fSDimitry Andric // stores? 2254753f127fSDimitry Andric static bool isWorthFoldingAdd(SDValue Add) { 2255bdd1243dSDimitry Andric for (auto *Use : Add->uses()) { 2256753f127fSDimitry Andric if (Use->getOpcode() != ISD::LOAD && Use->getOpcode() != ISD::STORE && 2257753f127fSDimitry Andric Use->getOpcode() != ISD::ATOMIC_LOAD && 2258753f127fSDimitry Andric Use->getOpcode() != ISD::ATOMIC_STORE) 2259753f127fSDimitry Andric return false; 2260753f127fSDimitry Andric EVT VT = cast<MemSDNode>(Use)->getMemoryVT(); 2261753f127fSDimitry Andric if (!VT.isScalarInteger() && VT != MVT::f16 && VT != MVT::f32 && 2262753f127fSDimitry Andric VT != MVT::f64) 2263753f127fSDimitry Andric return false; 2264753f127fSDimitry Andric // Don't allow stores of the value. It must be used as the address. 2265753f127fSDimitry Andric if (Use->getOpcode() == ISD::STORE && 2266753f127fSDimitry Andric cast<StoreSDNode>(Use)->getValue() == Add) 2267753f127fSDimitry Andric return false; 2268753f127fSDimitry Andric if (Use->getOpcode() == ISD::ATOMIC_STORE && 2269753f127fSDimitry Andric cast<AtomicSDNode>(Use)->getVal() == Add) 2270753f127fSDimitry Andric return false; 2271753f127fSDimitry Andric } 2272753f127fSDimitry Andric 2273fe6060f1SDimitry Andric return true; 2274e8d8bef9SDimitry Andric } 2275e8d8bef9SDimitry Andric 227606c3fb27SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrRegRegScale(SDValue Addr, 227706c3fb27SDimitry Andric unsigned MaxShiftAmount, 227806c3fb27SDimitry Andric SDValue &Base, SDValue &Index, 227906c3fb27SDimitry Andric SDValue &Scale) { 228006c3fb27SDimitry Andric EVT VT = Addr.getSimpleValueType(); 228106c3fb27SDimitry Andric auto UnwrapShl = [this, VT, MaxShiftAmount](SDValue N, SDValue &Index, 228206c3fb27SDimitry Andric SDValue &Shift) { 228306c3fb27SDimitry Andric uint64_t ShiftAmt = 0; 228406c3fb27SDimitry Andric Index = N; 228506c3fb27SDimitry Andric 228606c3fb27SDimitry Andric if (N.getOpcode() == ISD::SHL && isa<ConstantSDNode>(N.getOperand(1))) { 228706c3fb27SDimitry Andric // Only match shifts by a value in range [0, MaxShiftAmount]. 228806c3fb27SDimitry Andric if (N.getConstantOperandVal(1) <= MaxShiftAmount) { 228906c3fb27SDimitry Andric Index = N.getOperand(0); 229006c3fb27SDimitry Andric ShiftAmt = N.getConstantOperandVal(1); 229106c3fb27SDimitry Andric } 229206c3fb27SDimitry Andric } 229306c3fb27SDimitry Andric 229406c3fb27SDimitry Andric Shift = CurDAG->getTargetConstant(ShiftAmt, SDLoc(N), VT); 229506c3fb27SDimitry Andric return ShiftAmt != 0; 229606c3fb27SDimitry Andric }; 229706c3fb27SDimitry Andric 229806c3fb27SDimitry Andric if (Addr.getOpcode() == ISD::ADD) { 229906c3fb27SDimitry Andric if (auto *C1 = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { 230006c3fb27SDimitry Andric SDValue AddrB = Addr.getOperand(0); 230106c3fb27SDimitry Andric if (AddrB.getOpcode() == ISD::ADD && 230206c3fb27SDimitry Andric UnwrapShl(AddrB.getOperand(0), Index, Scale) && 230306c3fb27SDimitry Andric !isa<ConstantSDNode>(AddrB.getOperand(1)) && 230406c3fb27SDimitry Andric isInt<12>(C1->getSExtValue())) { 230506c3fb27SDimitry Andric // (add (add (shl A C2) B) C1) -> (add (add B C1) (shl A C2)) 230606c3fb27SDimitry Andric SDValue C1Val = 230706c3fb27SDimitry Andric CurDAG->getTargetConstant(C1->getZExtValue(), SDLoc(Addr), VT); 230806c3fb27SDimitry Andric Base = SDValue(CurDAG->getMachineNode(RISCV::ADDI, SDLoc(Addr), VT, 230906c3fb27SDimitry Andric AddrB.getOperand(1), C1Val), 231006c3fb27SDimitry Andric 0); 231106c3fb27SDimitry Andric return true; 231206c3fb27SDimitry Andric } 231306c3fb27SDimitry Andric } else if (UnwrapShl(Addr.getOperand(0), Index, Scale)) { 231406c3fb27SDimitry Andric Base = Addr.getOperand(1); 231506c3fb27SDimitry Andric return true; 231606c3fb27SDimitry Andric } else { 231706c3fb27SDimitry Andric UnwrapShl(Addr.getOperand(1), Index, Scale); 231806c3fb27SDimitry Andric Base = Addr.getOperand(0); 231906c3fb27SDimitry Andric return true; 232006c3fb27SDimitry Andric } 232106c3fb27SDimitry Andric } else if (UnwrapShl(Addr, Index, Scale)) { 232206c3fb27SDimitry Andric EVT VT = Addr.getValueType(); 232306c3fb27SDimitry Andric Base = CurDAG->getRegister(RISCV::X0, VT); 232406c3fb27SDimitry Andric return true; 232506c3fb27SDimitry Andric } 232606c3fb27SDimitry Andric 232706c3fb27SDimitry Andric return false; 232806c3fb27SDimitry Andric } 232906c3fb27SDimitry Andric 233081ad6265SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrRegImm(SDValue Addr, SDValue &Base, 233106c3fb27SDimitry Andric SDValue &Offset, bool IsINX) { 233281ad6265SDimitry Andric if (SelectAddrFrameIndex(Addr, Base, Offset)) 233381ad6265SDimitry Andric return true; 233481ad6265SDimitry Andric 233581ad6265SDimitry Andric SDLoc DL(Addr); 233681ad6265SDimitry Andric MVT VT = Addr.getSimpleValueType(); 233781ad6265SDimitry Andric 233881ad6265SDimitry Andric if (Addr.getOpcode() == RISCVISD::ADD_LO) { 233981ad6265SDimitry Andric Base = Addr.getOperand(0); 234081ad6265SDimitry Andric Offset = Addr.getOperand(1); 234181ad6265SDimitry Andric return true; 234281ad6265SDimitry Andric } 234381ad6265SDimitry Andric 234406c3fb27SDimitry Andric int64_t RV32ZdinxRange = IsINX ? 4 : 0; 234581ad6265SDimitry Andric if (CurDAG->isBaseWithConstantOffset(Addr)) { 234681ad6265SDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 234706c3fb27SDimitry Andric if (isInt<12>(CVal) && isInt<12>(CVal + RV32ZdinxRange)) { 234881ad6265SDimitry Andric Base = Addr.getOperand(0); 234981ad6265SDimitry Andric if (Base.getOpcode() == RISCVISD::ADD_LO) { 235081ad6265SDimitry Andric SDValue LoOperand = Base.getOperand(1); 235181ad6265SDimitry Andric if (auto *GA = dyn_cast<GlobalAddressSDNode>(LoOperand)) { 235281ad6265SDimitry Andric // If the Lo in (ADD_LO hi, lo) is a global variable's address 235381ad6265SDimitry Andric // (its low part, really), then we can rely on the alignment of that 235481ad6265SDimitry Andric // variable to provide a margin of safety before low part can overflow 235581ad6265SDimitry Andric // the 12 bits of the load/store offset. Check if CVal falls within 235681ad6265SDimitry Andric // that margin; if so (low part + CVal) can't overflow. 235781ad6265SDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 235881ad6265SDimitry Andric Align Alignment = commonAlignment( 235981ad6265SDimitry Andric GA->getGlobal()->getPointerAlignment(DL), GA->getOffset()); 236081ad6265SDimitry Andric if (CVal == 0 || Alignment > CVal) { 236181ad6265SDimitry Andric int64_t CombinedOffset = CVal + GA->getOffset(); 236281ad6265SDimitry Andric Base = Base.getOperand(0); 236381ad6265SDimitry Andric Offset = CurDAG->getTargetGlobalAddress( 236481ad6265SDimitry Andric GA->getGlobal(), SDLoc(LoOperand), LoOperand.getValueType(), 236581ad6265SDimitry Andric CombinedOffset, GA->getTargetFlags()); 236681ad6265SDimitry Andric return true; 236781ad6265SDimitry Andric } 236881ad6265SDimitry Andric } 236981ad6265SDimitry Andric } 237081ad6265SDimitry Andric 237181ad6265SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Base)) 237281ad6265SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), VT); 237381ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(CVal, DL, VT); 237481ad6265SDimitry Andric return true; 237581ad6265SDimitry Andric } 237681ad6265SDimitry Andric } 237781ad6265SDimitry Andric 237881ad6265SDimitry Andric // Handle ADD with large immediates. 237981ad6265SDimitry Andric if (Addr.getOpcode() == ISD::ADD && isa<ConstantSDNode>(Addr.getOperand(1))) { 238081ad6265SDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 238106c3fb27SDimitry Andric assert(!(isInt<12>(CVal) && isInt<12>(CVal + RV32ZdinxRange)) && 238206c3fb27SDimitry Andric "simm12 not already handled?"); 238381ad6265SDimitry Andric 2384753f127fSDimitry Andric // Handle immediates in the range [-4096,-2049] or [2048, 4094]. We can use 2385753f127fSDimitry Andric // an ADDI for part of the offset and fold the rest into the load/store. 2386753f127fSDimitry Andric // This mirrors the AddiPair PatFrag in RISCVInstrInfo.td. 238781ad6265SDimitry Andric if (isInt<12>(CVal / 2) && isInt<12>(CVal - CVal / 2)) { 238881ad6265SDimitry Andric int64_t Adj = CVal < 0 ? -2048 : 2047; 238981ad6265SDimitry Andric Base = SDValue( 239081ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::ADDI, DL, VT, Addr.getOperand(0), 239181ad6265SDimitry Andric CurDAG->getTargetConstant(Adj, DL, VT)), 239281ad6265SDimitry Andric 0); 239381ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(CVal - Adj, DL, VT); 239481ad6265SDimitry Andric return true; 239581ad6265SDimitry Andric } 2396753f127fSDimitry Andric 2397753f127fSDimitry Andric // For larger immediates, we might be able to save one instruction from 2398753f127fSDimitry Andric // constant materialization by folding the Lo12 bits of the immediate into 2399753f127fSDimitry Andric // the address. We should only do this if the ADD is only used by loads and 2400753f127fSDimitry Andric // stores that can fold the lo12 bits. Otherwise, the ADD will get iseled 2401753f127fSDimitry Andric // separately with the full materialized immediate creating extra 2402753f127fSDimitry Andric // instructions. 2403753f127fSDimitry Andric if (isWorthFoldingAdd(Addr) && 2404753f127fSDimitry Andric selectConstantAddr(CurDAG, DL, VT, Subtarget, Addr.getOperand(1), Base, 2405753f127fSDimitry Andric Offset)) { 2406753f127fSDimitry Andric // Insert an ADD instruction with the materialized Hi52 bits. 2407753f127fSDimitry Andric Base = SDValue( 2408753f127fSDimitry Andric CurDAG->getMachineNode(RISCV::ADD, DL, VT, Addr.getOperand(0), Base), 2409753f127fSDimitry Andric 0); 2410753f127fSDimitry Andric return true; 241181ad6265SDimitry Andric } 2412753f127fSDimitry Andric } 2413753f127fSDimitry Andric 2414753f127fSDimitry Andric if (selectConstantAddr(CurDAG, DL, VT, Subtarget, Addr, Base, Offset)) 2415753f127fSDimitry Andric return true; 241681ad6265SDimitry Andric 241781ad6265SDimitry Andric Base = Addr; 241881ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(0, DL, VT); 241981ad6265SDimitry Andric return true; 242081ad6265SDimitry Andric } 242181ad6265SDimitry Andric 2422fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth, 2423fe6060f1SDimitry Andric SDValue &ShAmt) { 2424bdd1243dSDimitry Andric ShAmt = N; 2425bdd1243dSDimitry Andric 242606c3fb27SDimitry Andric // Shift instructions on RISC-V only read the lower 5 or 6 bits of the shift 2427fe6060f1SDimitry Andric // amount. If there is an AND on the shift amount, we can bypass it if it 2428fe6060f1SDimitry Andric // doesn't affect any of those bits. 2429bdd1243dSDimitry Andric if (ShAmt.getOpcode() == ISD::AND && isa<ConstantSDNode>(ShAmt.getOperand(1))) { 2430bdd1243dSDimitry Andric const APInt &AndMask = ShAmt.getConstantOperandAPInt(1); 2431979e22ffSDimitry Andric 2432fe6060f1SDimitry Andric // Since the max shift amount is a power of 2 we can subtract 1 to make a 2433fe6060f1SDimitry Andric // mask that covers the bits needed to represent all shift amounts. 2434fe6060f1SDimitry Andric assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!"); 2435fe6060f1SDimitry Andric APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1); 2436e8d8bef9SDimitry Andric 2437fe6060f1SDimitry Andric if (ShMask.isSubsetOf(AndMask)) { 2438bdd1243dSDimitry Andric ShAmt = ShAmt.getOperand(0); 2439bdd1243dSDimitry Andric } else { 2440fe6060f1SDimitry Andric // SimplifyDemandedBits may have optimized the mask so try restoring any 2441fe6060f1SDimitry Andric // bits that are known zero. 2442bdd1243dSDimitry Andric KnownBits Known = CurDAG->computeKnownBits(ShAmt.getOperand(0)); 2443bdd1243dSDimitry Andric if (!ShMask.isSubsetOf(AndMask | Known.Zero)) 2444bdd1243dSDimitry Andric return true; 2445bdd1243dSDimitry Andric ShAmt = ShAmt.getOperand(0); 2446bdd1243dSDimitry Andric } 2447bdd1243dSDimitry Andric } 2448bdd1243dSDimitry Andric 2449bdd1243dSDimitry Andric if (ShAmt.getOpcode() == ISD::ADD && 2450bdd1243dSDimitry Andric isa<ConstantSDNode>(ShAmt.getOperand(1))) { 2451bdd1243dSDimitry Andric uint64_t Imm = ShAmt.getConstantOperandVal(1); 2452bdd1243dSDimitry Andric // If we are shifting by X+N where N == 0 mod Size, then just shift by X 2453bdd1243dSDimitry Andric // to avoid the ADD. 2454bdd1243dSDimitry Andric if (Imm != 0 && Imm % ShiftWidth == 0) { 2455bdd1243dSDimitry Andric ShAmt = ShAmt.getOperand(0); 2456fe6060f1SDimitry Andric return true; 2457fe6060f1SDimitry Andric } 2458bdd1243dSDimitry Andric } else if (ShAmt.getOpcode() == ISD::SUB && 2459bdd1243dSDimitry Andric isa<ConstantSDNode>(ShAmt.getOperand(0))) { 2460bdd1243dSDimitry Andric uint64_t Imm = ShAmt.getConstantOperandVal(0); 246181ad6265SDimitry Andric // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to 246281ad6265SDimitry Andric // generate a NEG instead of a SUB of a constant. 246381ad6265SDimitry Andric if (Imm != 0 && Imm % ShiftWidth == 0) { 2464bdd1243dSDimitry Andric SDLoc DL(ShAmt); 2465bdd1243dSDimitry Andric EVT VT = ShAmt.getValueType(); 246681ad6265SDimitry Andric SDValue Zero = CurDAG->getRegister(RISCV::X0, VT); 246781ad6265SDimitry Andric unsigned NegOpc = VT == MVT::i64 ? RISCV::SUBW : RISCV::SUB; 246881ad6265SDimitry Andric MachineSDNode *Neg = CurDAG->getMachineNode(NegOpc, DL, VT, Zero, 2469bdd1243dSDimitry Andric ShAmt.getOperand(1)); 247081ad6265SDimitry Andric ShAmt = SDValue(Neg, 0); 247181ad6265SDimitry Andric return true; 247281ad6265SDimitry Andric } 2473bdd1243dSDimitry Andric // If we are shifting by N-X where N == -1 mod Size, then just shift by ~X 2474bdd1243dSDimitry Andric // to generate a NOT instead of a SUB of a constant. 2475bdd1243dSDimitry Andric if (Imm % ShiftWidth == ShiftWidth - 1) { 2476bdd1243dSDimitry Andric SDLoc DL(ShAmt); 2477bdd1243dSDimitry Andric EVT VT = ShAmt.getValueType(); 2478bdd1243dSDimitry Andric MachineSDNode *Not = 2479bdd1243dSDimitry Andric CurDAG->getMachineNode(RISCV::XORI, DL, VT, ShAmt.getOperand(1), 2480bdd1243dSDimitry Andric CurDAG->getTargetConstant(-1, DL, VT)); 2481bdd1243dSDimitry Andric ShAmt = SDValue(Not, 0); 2482bdd1243dSDimitry Andric return true; 2483bdd1243dSDimitry Andric } 2484fe6060f1SDimitry Andric } 2485fe6060f1SDimitry Andric 2486fe6060f1SDimitry Andric return true; 2487fe6060f1SDimitry Andric } 2488fe6060f1SDimitry Andric 248906c3fb27SDimitry Andric /// RISC-V doesn't have general instructions for integer setne/seteq, but we can 249006c3fb27SDimitry Andric /// check for equality with 0. This function emits instructions that convert the 249106c3fb27SDimitry Andric /// seteq/setne into something that can be compared with 0. 249206c3fb27SDimitry Andric /// \p ExpectedCCVal indicates the condition code to attempt to match (e.g. 249306c3fb27SDimitry Andric /// ISD::SETNE). 249406c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectSETCC(SDValue N, ISD::CondCode ExpectedCCVal, 249506c3fb27SDimitry Andric SDValue &Val) { 249606c3fb27SDimitry Andric assert(ISD::isIntEqualitySetCC(ExpectedCCVal) && 249706c3fb27SDimitry Andric "Unexpected condition code!"); 249806c3fb27SDimitry Andric 249906c3fb27SDimitry Andric // We're looking for a setcc. 250006c3fb27SDimitry Andric if (N->getOpcode() != ISD::SETCC) 250106c3fb27SDimitry Andric return false; 250206c3fb27SDimitry Andric 250306c3fb27SDimitry Andric // Must be an equality comparison. 250406c3fb27SDimitry Andric ISD::CondCode CCVal = cast<CondCodeSDNode>(N->getOperand(2))->get(); 250506c3fb27SDimitry Andric if (CCVal != ExpectedCCVal) 250606c3fb27SDimitry Andric return false; 250706c3fb27SDimitry Andric 250806c3fb27SDimitry Andric SDValue LHS = N->getOperand(0); 250906c3fb27SDimitry Andric SDValue RHS = N->getOperand(1); 251006c3fb27SDimitry Andric 251106c3fb27SDimitry Andric if (!LHS.getValueType().isScalarInteger()) 251206c3fb27SDimitry Andric return false; 251306c3fb27SDimitry Andric 251406c3fb27SDimitry Andric // If the RHS side is 0, we don't need any extra instructions, return the LHS. 251506c3fb27SDimitry Andric if (isNullConstant(RHS)) { 251606c3fb27SDimitry Andric Val = LHS; 251706c3fb27SDimitry Andric return true; 251806c3fb27SDimitry Andric } 251906c3fb27SDimitry Andric 252006c3fb27SDimitry Andric SDLoc DL(N); 252106c3fb27SDimitry Andric 252206c3fb27SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(RHS)) { 252306c3fb27SDimitry Andric int64_t CVal = C->getSExtValue(); 252406c3fb27SDimitry Andric // If the RHS is -2048, we can use xori to produce 0 if the LHS is -2048 and 252506c3fb27SDimitry Andric // non-zero otherwise. 252606c3fb27SDimitry Andric if (CVal == -2048) { 252706c3fb27SDimitry Andric Val = 252806c3fb27SDimitry Andric SDValue(CurDAG->getMachineNode( 252906c3fb27SDimitry Andric RISCV::XORI, DL, N->getValueType(0), LHS, 253006c3fb27SDimitry Andric CurDAG->getTargetConstant(CVal, DL, N->getValueType(0))), 253106c3fb27SDimitry Andric 0); 253206c3fb27SDimitry Andric return true; 253306c3fb27SDimitry Andric } 253406c3fb27SDimitry Andric // If the RHS is [-2047,2048], we can use addi with -RHS to produce 0 if the 253506c3fb27SDimitry Andric // LHS is equal to the RHS and non-zero otherwise. 253606c3fb27SDimitry Andric if (isInt<12>(CVal) || CVal == 2048) { 253706c3fb27SDimitry Andric Val = 253806c3fb27SDimitry Andric SDValue(CurDAG->getMachineNode( 253906c3fb27SDimitry Andric RISCV::ADDI, DL, N->getValueType(0), LHS, 254006c3fb27SDimitry Andric CurDAG->getTargetConstant(-CVal, DL, N->getValueType(0))), 254106c3fb27SDimitry Andric 0); 254206c3fb27SDimitry Andric return true; 254306c3fb27SDimitry Andric } 254406c3fb27SDimitry Andric } 254506c3fb27SDimitry Andric 254606c3fb27SDimitry Andric // If nothing else we can XOR the LHS and RHS to produce zero if they are 254706c3fb27SDimitry Andric // equal and a non-zero value if they aren't. 254806c3fb27SDimitry Andric Val = SDValue( 254906c3fb27SDimitry Andric CurDAG->getMachineNode(RISCV::XOR, DL, N->getValueType(0), LHS, RHS), 0); 255006c3fb27SDimitry Andric return true; 255106c3fb27SDimitry Andric } 255206c3fb27SDimitry Andric 255306c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectSExtBits(SDValue N, unsigned Bits, SDValue &Val) { 2554fe6060f1SDimitry Andric if (N.getOpcode() == ISD::SIGN_EXTEND_INREG && 255506c3fb27SDimitry Andric cast<VTSDNode>(N.getOperand(1))->getVT().getSizeInBits() == Bits) { 2556fe6060f1SDimitry Andric Val = N.getOperand(0); 2557fe6060f1SDimitry Andric return true; 2558fe6060f1SDimitry Andric } 255906c3fb27SDimitry Andric 256006c3fb27SDimitry Andric auto UnwrapShlSra = [](SDValue N, unsigned ShiftAmt) { 256106c3fb27SDimitry Andric if (N.getOpcode() != ISD::SRA || !isa<ConstantSDNode>(N.getOperand(1))) 256206c3fb27SDimitry Andric return N; 256306c3fb27SDimitry Andric 256406c3fb27SDimitry Andric SDValue N0 = N.getOperand(0); 256506c3fb27SDimitry Andric if (N0.getOpcode() == ISD::SHL && isa<ConstantSDNode>(N0.getOperand(1)) && 256606c3fb27SDimitry Andric N.getConstantOperandVal(1) == ShiftAmt && 256706c3fb27SDimitry Andric N0.getConstantOperandVal(1) == ShiftAmt) 256806c3fb27SDimitry Andric return N0.getOperand(0); 256906c3fb27SDimitry Andric 257006c3fb27SDimitry Andric return N; 257106c3fb27SDimitry Andric }; 257206c3fb27SDimitry Andric 2573fe6060f1SDimitry Andric MVT VT = N.getSimpleValueType(); 257406c3fb27SDimitry Andric if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - Bits)) { 257506c3fb27SDimitry Andric Val = UnwrapShlSra(N, VT.getSizeInBits() - Bits); 2576fe6060f1SDimitry Andric return true; 2577fe6060f1SDimitry Andric } 2578fe6060f1SDimitry Andric 2579fe6060f1SDimitry Andric return false; 2580fe6060f1SDimitry Andric } 2581fe6060f1SDimitry Andric 2582bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::selectZExtBits(SDValue N, unsigned Bits, SDValue &Val) { 2583fe6060f1SDimitry Andric if (N.getOpcode() == ISD::AND) { 2584fe6060f1SDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1)); 2585bdd1243dSDimitry Andric if (C && C->getZExtValue() == maskTrailingOnes<uint64_t>(Bits)) { 2586fe6060f1SDimitry Andric Val = N.getOperand(0); 2587fe6060f1SDimitry Andric return true; 2588fe6060f1SDimitry Andric } 2589fe6060f1SDimitry Andric } 2590fe6060f1SDimitry Andric MVT VT = N.getSimpleValueType(); 2591bdd1243dSDimitry Andric APInt Mask = APInt::getBitsSetFrom(VT.getSizeInBits(), Bits); 2592fe6060f1SDimitry Andric if (CurDAG->MaskedValueIsZero(N, Mask)) { 2593fe6060f1SDimitry Andric Val = N; 2594fe6060f1SDimitry Andric return true; 2595fe6060f1SDimitry Andric } 2596fe6060f1SDimitry Andric 2597fe6060f1SDimitry Andric return false; 2598fe6060f1SDimitry Andric } 2599fe6060f1SDimitry Andric 2600753f127fSDimitry Andric /// Look for various patterns that can be done with a SHL that can be folded 2601753f127fSDimitry Andric /// into a SHXADD. \p ShAmt contains 1, 2, or 3 and is set based on which 2602753f127fSDimitry Andric /// SHXADD we are trying to match. 2603753f127fSDimitry Andric bool RISCVDAGToDAGISel::selectSHXADDOp(SDValue N, unsigned ShAmt, 2604753f127fSDimitry Andric SDValue &Val) { 2605753f127fSDimitry Andric if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) { 2606753f127fSDimitry Andric SDValue N0 = N.getOperand(0); 2607753f127fSDimitry Andric 2608753f127fSDimitry Andric bool LeftShift = N0.getOpcode() == ISD::SHL; 2609753f127fSDimitry Andric if ((LeftShift || N0.getOpcode() == ISD::SRL) && 2610753f127fSDimitry Andric isa<ConstantSDNode>(N0.getOperand(1))) { 2611753f127fSDimitry Andric uint64_t Mask = N.getConstantOperandVal(1); 2612753f127fSDimitry Andric unsigned C2 = N0.getConstantOperandVal(1); 2613753f127fSDimitry Andric 2614753f127fSDimitry Andric unsigned XLen = Subtarget->getXLen(); 2615753f127fSDimitry Andric if (LeftShift) 2616753f127fSDimitry Andric Mask &= maskTrailingZeros<uint64_t>(C2); 2617753f127fSDimitry Andric else 2618753f127fSDimitry Andric Mask &= maskTrailingOnes<uint64_t>(XLen - C2); 2619753f127fSDimitry Andric 2620753f127fSDimitry Andric // Look for (and (shl y, c2), c1) where c1 is a shifted mask with no 2621753f127fSDimitry Andric // leading zeros and c3 trailing zeros. We can use an SRLI by c2+c3 2622753f127fSDimitry Andric // followed by a SHXADD with c3 for the X amount. 2623753f127fSDimitry Andric if (isShiftedMask_64(Mask)) { 2624bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(Mask); 262506c3fb27SDimitry Andric unsigned Trailing = llvm::countr_zero(Mask); 2626753f127fSDimitry Andric if (LeftShift && Leading == 0 && C2 < Trailing && Trailing == ShAmt) { 2627753f127fSDimitry Andric SDLoc DL(N); 2628753f127fSDimitry Andric EVT VT = N.getValueType(); 2629753f127fSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 2630753f127fSDimitry Andric RISCV::SRLI, DL, VT, N0.getOperand(0), 2631753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)), 2632753f127fSDimitry Andric 0); 2633753f127fSDimitry Andric return true; 2634753f127fSDimitry Andric } 2635753f127fSDimitry Andric // Look for (and (shr y, c2), c1) where c1 is a shifted mask with c2 2636753f127fSDimitry Andric // leading zeros and c3 trailing zeros. We can use an SRLI by C3 2637753f127fSDimitry Andric // followed by a SHXADD using c3 for the X amount. 2638753f127fSDimitry Andric if (!LeftShift && Leading == C2 && Trailing == ShAmt) { 2639753f127fSDimitry Andric SDLoc DL(N); 2640753f127fSDimitry Andric EVT VT = N.getValueType(); 2641753f127fSDimitry Andric Val = SDValue( 2642753f127fSDimitry Andric CurDAG->getMachineNode( 2643753f127fSDimitry Andric RISCV::SRLI, DL, VT, N0.getOperand(0), 2644753f127fSDimitry Andric CurDAG->getTargetConstant(Leading + Trailing, DL, VT)), 2645753f127fSDimitry Andric 0); 2646753f127fSDimitry Andric return true; 2647753f127fSDimitry Andric } 2648753f127fSDimitry Andric } 2649753f127fSDimitry Andric } 2650753f127fSDimitry Andric } 2651753f127fSDimitry Andric 2652753f127fSDimitry Andric bool LeftShift = N.getOpcode() == ISD::SHL; 2653753f127fSDimitry Andric if ((LeftShift || N.getOpcode() == ISD::SRL) && 2654753f127fSDimitry Andric isa<ConstantSDNode>(N.getOperand(1))) { 2655753f127fSDimitry Andric SDValue N0 = N.getOperand(0); 2656753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && N0.hasOneUse() && 2657753f127fSDimitry Andric isa<ConstantSDNode>(N0.getOperand(1))) { 2658753f127fSDimitry Andric uint64_t Mask = N0.getConstantOperandVal(1); 2659753f127fSDimitry Andric if (isShiftedMask_64(Mask)) { 2660753f127fSDimitry Andric unsigned C1 = N.getConstantOperandVal(1); 2661753f127fSDimitry Andric unsigned XLen = Subtarget->getXLen(); 2662bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(Mask); 266306c3fb27SDimitry Andric unsigned Trailing = llvm::countr_zero(Mask); 2664753f127fSDimitry Andric // Look for (shl (and X, Mask), C1) where Mask has 32 leading zeros and 2665753f127fSDimitry Andric // C3 trailing zeros. If C1+C3==ShAmt we can use SRLIW+SHXADD. 2666753f127fSDimitry Andric if (LeftShift && Leading == 32 && Trailing > 0 && 2667753f127fSDimitry Andric (Trailing + C1) == ShAmt) { 2668753f127fSDimitry Andric SDLoc DL(N); 2669753f127fSDimitry Andric EVT VT = N.getValueType(); 2670753f127fSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 2671753f127fSDimitry Andric RISCV::SRLIW, DL, VT, N0.getOperand(0), 2672753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)), 2673753f127fSDimitry Andric 0); 2674753f127fSDimitry Andric return true; 2675753f127fSDimitry Andric } 2676753f127fSDimitry Andric // Look for (srl (and X, Mask), C1) where Mask has 32 leading zeros and 2677753f127fSDimitry Andric // C3 trailing zeros. If C3-C1==ShAmt we can use SRLIW+SHXADD. 2678753f127fSDimitry Andric if (!LeftShift && Leading == 32 && Trailing > C1 && 2679753f127fSDimitry Andric (Trailing - C1) == ShAmt) { 2680753f127fSDimitry Andric SDLoc DL(N); 2681753f127fSDimitry Andric EVT VT = N.getValueType(); 2682753f127fSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 2683753f127fSDimitry Andric RISCV::SRLIW, DL, VT, N0.getOperand(0), 2684753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)), 2685753f127fSDimitry Andric 0); 2686753f127fSDimitry Andric return true; 2687753f127fSDimitry Andric } 2688753f127fSDimitry Andric } 2689753f127fSDimitry Andric } 2690753f127fSDimitry Andric } 2691753f127fSDimitry Andric 2692753f127fSDimitry Andric return false; 2693753f127fSDimitry Andric } 2694753f127fSDimitry Andric 2695bdd1243dSDimitry Andric /// Look for various patterns that can be done with a SHL that can be folded 2696bdd1243dSDimitry Andric /// into a SHXADD_UW. \p ShAmt contains 1, 2, or 3 and is set based on which 2697bdd1243dSDimitry Andric /// SHXADD_UW we are trying to match. 2698bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::selectSHXADD_UWOp(SDValue N, unsigned ShAmt, 2699bdd1243dSDimitry Andric SDValue &Val) { 2700bdd1243dSDimitry Andric if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1)) && 2701bdd1243dSDimitry Andric N.hasOneUse()) { 2702bdd1243dSDimitry Andric SDValue N0 = N.getOperand(0); 2703bdd1243dSDimitry Andric if (N0.getOpcode() == ISD::SHL && isa<ConstantSDNode>(N0.getOperand(1)) && 2704bdd1243dSDimitry Andric N0.hasOneUse()) { 2705bdd1243dSDimitry Andric uint64_t Mask = N.getConstantOperandVal(1); 2706bdd1243dSDimitry Andric unsigned C2 = N0.getConstantOperandVal(1); 2707bdd1243dSDimitry Andric 2708bdd1243dSDimitry Andric Mask &= maskTrailingZeros<uint64_t>(C2); 2709bdd1243dSDimitry Andric 2710bdd1243dSDimitry Andric // Look for (and (shl y, c2), c1) where c1 is a shifted mask with 2711bdd1243dSDimitry Andric // 32-ShAmt leading zeros and c2 trailing zeros. We can use SLLI by 2712bdd1243dSDimitry Andric // c2-ShAmt followed by SHXADD_UW with ShAmt for the X amount. 2713bdd1243dSDimitry Andric if (isShiftedMask_64(Mask)) { 271406c3fb27SDimitry Andric unsigned Leading = llvm::countl_zero(Mask); 271506c3fb27SDimitry Andric unsigned Trailing = llvm::countr_zero(Mask); 2716bdd1243dSDimitry Andric if (Leading == 32 - ShAmt && Trailing == C2 && Trailing > ShAmt) { 2717bdd1243dSDimitry Andric SDLoc DL(N); 2718bdd1243dSDimitry Andric EVT VT = N.getValueType(); 2719bdd1243dSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 2720bdd1243dSDimitry Andric RISCV::SLLI, DL, VT, N0.getOperand(0), 2721bdd1243dSDimitry Andric CurDAG->getTargetConstant(C2 - ShAmt, DL, VT)), 2722bdd1243dSDimitry Andric 0); 2723bdd1243dSDimitry Andric return true; 2724bdd1243dSDimitry Andric } 2725bdd1243dSDimitry Andric } 2726bdd1243dSDimitry Andric } 2727bdd1243dSDimitry Andric } 2728bdd1243dSDimitry Andric 2729bdd1243dSDimitry Andric return false; 2730bdd1243dSDimitry Andric } 2731bdd1243dSDimitry Andric 2732349cc55cSDimitry Andric // Return true if all users of this SDNode* only consume the lower \p Bits. 2733349cc55cSDimitry Andric // This can be used to form W instructions for add/sub/mul/shl even when the 2734349cc55cSDimitry Andric // root isn't a sext_inreg. This can allow the ADDW/SUBW/MULW/SLLIW to CSE if 2735349cc55cSDimitry Andric // SimplifyDemandedBits has made it so some users see a sext_inreg and some 2736349cc55cSDimitry Andric // don't. The sext_inreg+add/sub/mul/shl will get selected, but still leave 2737349cc55cSDimitry Andric // the add/sub/mul/shl to become non-W instructions. By checking the users we 2738349cc55cSDimitry Andric // may be able to use a W instruction and CSE with the other instruction if 2739349cc55cSDimitry Andric // this has happened. We could try to detect that the CSE opportunity exists 2740349cc55cSDimitry Andric // before doing this, but that would be more complicated. 2741bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::hasAllNBitUsers(SDNode *Node, unsigned Bits, 2742bdd1243dSDimitry Andric const unsigned Depth) const { 2743349cc55cSDimitry Andric assert((Node->getOpcode() == ISD::ADD || Node->getOpcode() == ISD::SUB || 2744349cc55cSDimitry Andric Node->getOpcode() == ISD::MUL || Node->getOpcode() == ISD::SHL || 2745bdd1243dSDimitry Andric Node->getOpcode() == ISD::SRL || Node->getOpcode() == ISD::AND || 2746bdd1243dSDimitry Andric Node->getOpcode() == ISD::OR || Node->getOpcode() == ISD::XOR || 2747349cc55cSDimitry Andric Node->getOpcode() == ISD::SIGN_EXTEND_INREG || 2748bdd1243dSDimitry Andric isa<ConstantSDNode>(Node) || Depth != 0) && 2749349cc55cSDimitry Andric "Unexpected opcode"); 2750349cc55cSDimitry Andric 2751bdd1243dSDimitry Andric if (Depth >= SelectionDAG::MaxRecursionDepth) 2752bdd1243dSDimitry Andric return false; 2753bdd1243dSDimitry Andric 2754349cc55cSDimitry Andric for (auto UI = Node->use_begin(), UE = Node->use_end(); UI != UE; ++UI) { 2755349cc55cSDimitry Andric SDNode *User = *UI; 2756349cc55cSDimitry Andric // Users of this node should have already been instruction selected 2757349cc55cSDimitry Andric if (!User->isMachineOpcode()) 2758349cc55cSDimitry Andric return false; 2759349cc55cSDimitry Andric 2760349cc55cSDimitry Andric // TODO: Add more opcodes? 2761349cc55cSDimitry Andric switch (User->getMachineOpcode()) { 2762349cc55cSDimitry Andric default: 2763349cc55cSDimitry Andric return false; 2764349cc55cSDimitry Andric case RISCV::ADDW: 2765349cc55cSDimitry Andric case RISCV::ADDIW: 2766349cc55cSDimitry Andric case RISCV::SUBW: 2767349cc55cSDimitry Andric case RISCV::MULW: 2768349cc55cSDimitry Andric case RISCV::SLLW: 2769349cc55cSDimitry Andric case RISCV::SLLIW: 2770349cc55cSDimitry Andric case RISCV::SRAW: 2771349cc55cSDimitry Andric case RISCV::SRAIW: 2772349cc55cSDimitry Andric case RISCV::SRLW: 2773349cc55cSDimitry Andric case RISCV::SRLIW: 2774349cc55cSDimitry Andric case RISCV::DIVW: 2775349cc55cSDimitry Andric case RISCV::DIVUW: 2776349cc55cSDimitry Andric case RISCV::REMW: 2777349cc55cSDimitry Andric case RISCV::REMUW: 2778349cc55cSDimitry Andric case RISCV::ROLW: 2779349cc55cSDimitry Andric case RISCV::RORW: 2780349cc55cSDimitry Andric case RISCV::RORIW: 2781349cc55cSDimitry Andric case RISCV::CLZW: 2782349cc55cSDimitry Andric case RISCV::CTZW: 2783349cc55cSDimitry Andric case RISCV::CPOPW: 27841fd87a68SDimitry Andric case RISCV::SLLI_UW: 278581ad6265SDimitry Andric case RISCV::FMV_W_X: 2786349cc55cSDimitry Andric case RISCV::FCVT_H_W: 2787349cc55cSDimitry Andric case RISCV::FCVT_H_WU: 2788349cc55cSDimitry Andric case RISCV::FCVT_S_W: 2789349cc55cSDimitry Andric case RISCV::FCVT_S_WU: 2790349cc55cSDimitry Andric case RISCV::FCVT_D_W: 2791349cc55cSDimitry Andric case RISCV::FCVT_D_WU: 279206c3fb27SDimitry Andric case RISCV::TH_REVW: 279306c3fb27SDimitry Andric case RISCV::TH_SRRIW: 2794349cc55cSDimitry Andric if (Bits < 32) 2795349cc55cSDimitry Andric return false; 2796349cc55cSDimitry Andric break; 2797bdd1243dSDimitry Andric case RISCV::SLL: 2798bdd1243dSDimitry Andric case RISCV::SRA: 2799bdd1243dSDimitry Andric case RISCV::SRL: 2800bdd1243dSDimitry Andric case RISCV::ROL: 2801bdd1243dSDimitry Andric case RISCV::ROR: 2802bdd1243dSDimitry Andric case RISCV::BSET: 2803bdd1243dSDimitry Andric case RISCV::BCLR: 2804bdd1243dSDimitry Andric case RISCV::BINV: 2805bdd1243dSDimitry Andric // Shift amount operands only use log2(Xlen) bits. 2806bdd1243dSDimitry Andric if (UI.getOperandNo() != 1 || Bits < Log2_32(Subtarget->getXLen())) 2807bdd1243dSDimitry Andric return false; 2808bdd1243dSDimitry Andric break; 2809349cc55cSDimitry Andric case RISCV::SLLI: 2810349cc55cSDimitry Andric // SLLI only uses the lower (XLen - ShAmt) bits. 2811349cc55cSDimitry Andric if (Bits < Subtarget->getXLen() - User->getConstantOperandVal(1)) 2812349cc55cSDimitry Andric return false; 2813349cc55cSDimitry Andric break; 281404eeddc0SDimitry Andric case RISCV::ANDI: 2815bdd1243dSDimitry Andric if (Bits >= (unsigned)llvm::bit_width(User->getConstantOperandVal(1))) 281604eeddc0SDimitry Andric break; 2817bdd1243dSDimitry Andric goto RecCheck; 2818bdd1243dSDimitry Andric case RISCV::ORI: { 2819bdd1243dSDimitry Andric uint64_t Imm = cast<ConstantSDNode>(User->getOperand(1))->getSExtValue(); 2820bdd1243dSDimitry Andric if (Bits >= (unsigned)llvm::bit_width<uint64_t>(~Imm)) 2821bdd1243dSDimitry Andric break; 2822bdd1243dSDimitry Andric [[fallthrough]]; 2823bdd1243dSDimitry Andric } 2824bdd1243dSDimitry Andric case RISCV::AND: 2825bdd1243dSDimitry Andric case RISCV::OR: 2826bdd1243dSDimitry Andric case RISCV::XOR: 2827bdd1243dSDimitry Andric case RISCV::XORI: 2828bdd1243dSDimitry Andric case RISCV::ANDN: 2829bdd1243dSDimitry Andric case RISCV::ORN: 2830bdd1243dSDimitry Andric case RISCV::XNOR: 2831bdd1243dSDimitry Andric case RISCV::SH1ADD: 2832bdd1243dSDimitry Andric case RISCV::SH2ADD: 2833bdd1243dSDimitry Andric case RISCV::SH3ADD: 2834bdd1243dSDimitry Andric RecCheck: 2835bdd1243dSDimitry Andric if (hasAllNBitUsers(User, Bits, Depth + 1)) 2836bdd1243dSDimitry Andric break; 2837bdd1243dSDimitry Andric return false; 2838bdd1243dSDimitry Andric case RISCV::SRLI: { 2839bdd1243dSDimitry Andric unsigned ShAmt = User->getConstantOperandVal(1); 2840bdd1243dSDimitry Andric // If we are shifting right by less than Bits, and users don't demand any 2841bdd1243dSDimitry Andric // bits that were shifted into [Bits-1:0], then we can consider this as an 2842bdd1243dSDimitry Andric // N-Bit user. 2843bdd1243dSDimitry Andric if (Bits > ShAmt && hasAllNBitUsers(User, Bits - ShAmt, Depth + 1)) 2844bdd1243dSDimitry Andric break; 2845bdd1243dSDimitry Andric return false; 2846bdd1243dSDimitry Andric } 28471fd87a68SDimitry Andric case RISCV::SEXT_B: 2848bdd1243dSDimitry Andric case RISCV::PACKH: 284904eeddc0SDimitry Andric if (Bits < 8) 285004eeddc0SDimitry Andric return false; 285104eeddc0SDimitry Andric break; 28521fd87a68SDimitry Andric case RISCV::SEXT_H: 285381ad6265SDimitry Andric case RISCV::FMV_H_X: 28541fd87a68SDimitry Andric case RISCV::ZEXT_H_RV32: 28551fd87a68SDimitry Andric case RISCV::ZEXT_H_RV64: 2856bdd1243dSDimitry Andric case RISCV::PACKW: 285704eeddc0SDimitry Andric if (Bits < 16) 285804eeddc0SDimitry Andric return false; 285904eeddc0SDimitry Andric break; 2860bdd1243dSDimitry Andric case RISCV::PACK: 2861bdd1243dSDimitry Andric if (Bits < (Subtarget->getXLen() / 2)) 2862bdd1243dSDimitry Andric return false; 2863bdd1243dSDimitry Andric break; 28641fd87a68SDimitry Andric case RISCV::ADD_UW: 28651fd87a68SDimitry Andric case RISCV::SH1ADD_UW: 28661fd87a68SDimitry Andric case RISCV::SH2ADD_UW: 28671fd87a68SDimitry Andric case RISCV::SH3ADD_UW: 2868349cc55cSDimitry Andric // The first operand to add.uw/shXadd.uw is implicitly zero extended from 2869349cc55cSDimitry Andric // 32 bits. 2870349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 32) 2871349cc55cSDimitry Andric return false; 2872349cc55cSDimitry Andric break; 2873349cc55cSDimitry Andric case RISCV::SB: 2874349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 8) 2875349cc55cSDimitry Andric return false; 2876349cc55cSDimitry Andric break; 2877349cc55cSDimitry Andric case RISCV::SH: 2878349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 16) 2879349cc55cSDimitry Andric return false; 2880349cc55cSDimitry Andric break; 2881349cc55cSDimitry Andric case RISCV::SW: 2882349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 32) 2883349cc55cSDimitry Andric return false; 2884349cc55cSDimitry Andric break; 2885349cc55cSDimitry Andric } 2886349cc55cSDimitry Andric } 2887349cc55cSDimitry Andric 2888349cc55cSDimitry Andric return true; 2889349cc55cSDimitry Andric } 2890349cc55cSDimitry Andric 289106c3fb27SDimitry Andric // Select a constant that can be represented as (sign_extend(imm5) << imm2). 289206c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectSimm5Shl2(SDValue N, SDValue &Simm5, 289306c3fb27SDimitry Andric SDValue &Shl2) { 289406c3fb27SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(N)) { 289506c3fb27SDimitry Andric int64_t Offset = C->getSExtValue(); 289606c3fb27SDimitry Andric int64_t Shift; 289706c3fb27SDimitry Andric for (Shift = 0; Shift < 4; Shift++) 289806c3fb27SDimitry Andric if (isInt<5>(Offset >> Shift) && ((Offset % (1LL << Shift)) == 0)) 289906c3fb27SDimitry Andric break; 290006c3fb27SDimitry Andric 290106c3fb27SDimitry Andric // Constant cannot be encoded. 290206c3fb27SDimitry Andric if (Shift == 4) 290306c3fb27SDimitry Andric return false; 290406c3fb27SDimitry Andric 290506c3fb27SDimitry Andric EVT Ty = N->getValueType(0); 290606c3fb27SDimitry Andric Simm5 = CurDAG->getTargetConstant(Offset >> Shift, SDLoc(N), Ty); 290706c3fb27SDimitry Andric Shl2 = CurDAG->getTargetConstant(Shift, SDLoc(N), Ty); 290806c3fb27SDimitry Andric return true; 290906c3fb27SDimitry Andric } 291006c3fb27SDimitry Andric 291106c3fb27SDimitry Andric return false; 291206c3fb27SDimitry Andric } 291306c3fb27SDimitry Andric 2914fe6060f1SDimitry Andric // Select VL as a 5 bit immediate or a value that will become a register. This 2915fe6060f1SDimitry Andric // allows us to choose betwen VSETIVLI or VSETVLI later. 2916d409305fSDimitry Andric bool RISCVDAGToDAGISel::selectVLOp(SDValue N, SDValue &VL) { 2917d409305fSDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N); 291881ad6265SDimitry Andric if (C && isUInt<5>(C->getZExtValue())) { 2919fe6060f1SDimitry Andric VL = CurDAG->getTargetConstant(C->getZExtValue(), SDLoc(N), 2920fe6060f1SDimitry Andric N->getValueType(0)); 292106c3fb27SDimitry Andric } else if (C && C->isAllOnes()) { 292281ad6265SDimitry Andric // Treat all ones as VLMax. 292381ad6265SDimitry Andric VL = CurDAG->getTargetConstant(RISCV::VLMaxSentinel, SDLoc(N), 292481ad6265SDimitry Andric N->getValueType(0)); 292581ad6265SDimitry Andric } else if (isa<RegisterSDNode>(N) && 292681ad6265SDimitry Andric cast<RegisterSDNode>(N)->getReg() == RISCV::X0) { 292781ad6265SDimitry Andric // All our VL operands use an operand that allows GPRNoX0 or an immediate 292881ad6265SDimitry Andric // as the register class. Convert X0 to a special immediate to pass the 292981ad6265SDimitry Andric // MachineVerifier. This is recognized specially by the vsetvli insertion 293081ad6265SDimitry Andric // pass. 293181ad6265SDimitry Andric VL = CurDAG->getTargetConstant(RISCV::VLMaxSentinel, SDLoc(N), 293281ad6265SDimitry Andric N->getValueType(0)); 293381ad6265SDimitry Andric } else { 2934d409305fSDimitry Andric VL = N; 293581ad6265SDimitry Andric } 2936d409305fSDimitry Andric 2937d409305fSDimitry Andric return true; 2938d409305fSDimitry Andric } 2939d409305fSDimitry Andric 2940e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::selectVSplat(SDValue N, SDValue &SplatVal) { 294181ad6265SDimitry Andric if (N.getOpcode() != RISCVISD::VMV_V_X_VL || !N.getOperand(0).isUndef()) 2942e8d8bef9SDimitry Andric return false; 2943bdd1243dSDimitry Andric assert(N.getNumOperands() == 3 && "Unexpected number of operands"); 294481ad6265SDimitry Andric SplatVal = N.getOperand(1); 2945979e22ffSDimitry Andric return true; 2946979e22ffSDimitry Andric } 2947e8d8bef9SDimitry Andric 2948fe6060f1SDimitry Andric using ValidateFn = bool (*)(int64_t); 2949fe6060f1SDimitry Andric 2950fe6060f1SDimitry Andric static bool selectVSplatSimmHelper(SDValue N, SDValue &SplatVal, 2951fe6060f1SDimitry Andric SelectionDAG &DAG, 2952fe6060f1SDimitry Andric const RISCVSubtarget &Subtarget, 2953fe6060f1SDimitry Andric ValidateFn ValidateImm) { 295481ad6265SDimitry Andric if (N.getOpcode() != RISCVISD::VMV_V_X_VL || !N.getOperand(0).isUndef() || 295581ad6265SDimitry Andric !isa<ConstantSDNode>(N.getOperand(1))) 2956979e22ffSDimitry Andric return false; 2957bdd1243dSDimitry Andric assert(N.getNumOperands() == 3 && "Unexpected number of operands"); 2958e8d8bef9SDimitry Andric 295981ad6265SDimitry Andric int64_t SplatImm = 296081ad6265SDimitry Andric cast<ConstantSDNode>(N.getOperand(1))->getSExtValue(); 2961e8d8bef9SDimitry Andric 296281ad6265SDimitry Andric // The semantics of RISCVISD::VMV_V_X_VL is that when the operand 296381ad6265SDimitry Andric // type is wider than the resulting vector element type: an implicit 296481ad6265SDimitry Andric // truncation first takes place. Therefore, perform a manual 296581ad6265SDimitry Andric // truncation/sign-extension in order to ignore any truncated bits and catch 296681ad6265SDimitry Andric // any zero-extended immediate. 2967e8d8bef9SDimitry Andric // For example, we wish to match (i8 -1) -> (XLenVT 255) as a simm5 by first 2968e8d8bef9SDimitry Andric // sign-extending to (XLenVT -1). 2969fe6060f1SDimitry Andric MVT XLenVT = Subtarget.getXLenVT(); 297081ad6265SDimitry Andric assert(XLenVT == N.getOperand(1).getSimpleValueType() && 2971e8d8bef9SDimitry Andric "Unexpected splat operand type"); 2972fe6060f1SDimitry Andric MVT EltVT = N.getSimpleValueType().getVectorElementType(); 2973fe6060f1SDimitry Andric if (EltVT.bitsLT(XLenVT)) 2974e8d8bef9SDimitry Andric SplatImm = SignExtend64(SplatImm, EltVT.getSizeInBits()); 2975979e22ffSDimitry Andric 2976fe6060f1SDimitry Andric if (!ValidateImm(SplatImm)) 2977e8d8bef9SDimitry Andric return false; 2978979e22ffSDimitry Andric 2979fe6060f1SDimitry Andric SplatVal = DAG.getTargetConstant(SplatImm, SDLoc(N), XLenVT); 2980979e22ffSDimitry Andric return true; 2981979e22ffSDimitry Andric } 2982e8d8bef9SDimitry Andric 2983fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5(SDValue N, SDValue &SplatVal) { 2984fe6060f1SDimitry Andric return selectVSplatSimmHelper(N, SplatVal, *CurDAG, *Subtarget, 2985fe6060f1SDimitry Andric [](int64_t Imm) { return isInt<5>(Imm); }); 2986fe6060f1SDimitry Andric } 2987fe6060f1SDimitry Andric 2988fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5Plus1(SDValue N, SDValue &SplatVal) { 2989fe6060f1SDimitry Andric return selectVSplatSimmHelper( 2990fe6060f1SDimitry Andric N, SplatVal, *CurDAG, *Subtarget, 2991fe6060f1SDimitry Andric [](int64_t Imm) { return (isInt<5>(Imm) && Imm != -16) || Imm == 16; }); 2992fe6060f1SDimitry Andric } 2993fe6060f1SDimitry Andric 2994fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5Plus1NonZero(SDValue N, 2995fe6060f1SDimitry Andric SDValue &SplatVal) { 2996fe6060f1SDimitry Andric return selectVSplatSimmHelper( 2997fe6060f1SDimitry Andric N, SplatVal, *CurDAG, *Subtarget, [](int64_t Imm) { 2998fe6060f1SDimitry Andric return Imm != 0 && ((isInt<5>(Imm) && Imm != -16) || Imm == 16); 2999fe6060f1SDimitry Andric }); 3000fe6060f1SDimitry Andric } 3001fe6060f1SDimitry Andric 300206c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatUimm(SDValue N, unsigned Bits, 300306c3fb27SDimitry Andric SDValue &SplatVal) { 300481ad6265SDimitry Andric if (N.getOpcode() != RISCVISD::VMV_V_X_VL || !N.getOperand(0).isUndef() || 300581ad6265SDimitry Andric !isa<ConstantSDNode>(N.getOperand(1))) 3006979e22ffSDimitry Andric return false; 3007979e22ffSDimitry Andric 300881ad6265SDimitry Andric int64_t SplatImm = 300981ad6265SDimitry Andric cast<ConstantSDNode>(N.getOperand(1))->getSExtValue(); 3010979e22ffSDimitry Andric 301106c3fb27SDimitry Andric if (!isUIntN(Bits, SplatImm)) 3012e8d8bef9SDimitry Andric return false; 3013e8d8bef9SDimitry Andric 3014e8d8bef9SDimitry Andric SplatVal = 3015e8d8bef9SDimitry Andric CurDAG->getTargetConstant(SplatImm, SDLoc(N), Subtarget->getXLenVT()); 3016e8d8bef9SDimitry Andric 3017979e22ffSDimitry Andric return true; 3018979e22ffSDimitry Andric } 3019979e22ffSDimitry Andric 302006c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectExtOneUseVSplat(SDValue N, SDValue &SplatVal) { 302106c3fb27SDimitry Andric if (N->getOpcode() == ISD::SIGN_EXTEND || 302206c3fb27SDimitry Andric N->getOpcode() == ISD::ZERO_EXTEND) { 302306c3fb27SDimitry Andric if (!N.hasOneUse()) 302406c3fb27SDimitry Andric return false; 302506c3fb27SDimitry Andric N = N->getOperand(0); 302606c3fb27SDimitry Andric } 302706c3fb27SDimitry Andric return selectVSplat(N, SplatVal); 302806c3fb27SDimitry Andric } 302906c3fb27SDimitry Andric 303006c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectFPImm(SDValue N, SDValue &Imm) { 303106c3fb27SDimitry Andric ConstantFPSDNode *CFP = dyn_cast<ConstantFPSDNode>(N.getNode()); 303206c3fb27SDimitry Andric if (!CFP) 303306c3fb27SDimitry Andric return false; 303406c3fb27SDimitry Andric const APFloat &APF = CFP->getValueAPF(); 303506c3fb27SDimitry Andric // td can handle +0.0 already. 303606c3fb27SDimitry Andric if (APF.isPosZero()) 303706c3fb27SDimitry Andric return false; 303806c3fb27SDimitry Andric 303906c3fb27SDimitry Andric MVT VT = CFP->getSimpleValueType(0); 304006c3fb27SDimitry Andric 304106c3fb27SDimitry Andric if (static_cast<const RISCVTargetLowering *>(TLI)->getLegalZfaFPImm(APF, 304206c3fb27SDimitry Andric VT) >= 0) 304306c3fb27SDimitry Andric return false; 304406c3fb27SDimitry Andric 304506c3fb27SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 304606c3fb27SDimitry Andric if (VT == MVT::f64 && !Subtarget->is64Bit()) { 304706c3fb27SDimitry Andric assert(APF.isNegZero() && "Unexpected constant."); 304806c3fb27SDimitry Andric return false; 304906c3fb27SDimitry Andric } 305006c3fb27SDimitry Andric SDLoc DL(N); 305106c3fb27SDimitry Andric Imm = selectImm(CurDAG, DL, XLenVT, APF.bitcastToAPInt().getSExtValue(), 305206c3fb27SDimitry Andric *Subtarget); 305306c3fb27SDimitry Andric return true; 305406c3fb27SDimitry Andric } 305506c3fb27SDimitry Andric 3056fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectRVVSimm5(SDValue N, unsigned Width, 3057fe6060f1SDimitry Andric SDValue &Imm) { 3058fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(N)) { 3059fe6060f1SDimitry Andric int64_t ImmVal = SignExtend64(C->getSExtValue(), Width); 3060fe6060f1SDimitry Andric 3061fe6060f1SDimitry Andric if (!isInt<5>(ImmVal)) 3062fe6060f1SDimitry Andric return false; 3063fe6060f1SDimitry Andric 3064fe6060f1SDimitry Andric Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), Subtarget->getXLenVT()); 3065fe6060f1SDimitry Andric return true; 3066fe6060f1SDimitry Andric } 3067fe6060f1SDimitry Andric 3068fe6060f1SDimitry Andric return false; 3069fe6060f1SDimitry Andric } 3070fe6060f1SDimitry Andric 3071349cc55cSDimitry Andric // Try to remove sext.w if the input is a W instruction or can be made into 3072349cc55cSDimitry Andric // a W instruction cheaply. 3073349cc55cSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeSExtW(SDNode *N) { 3074349cc55cSDimitry Andric // Look for the sext.w pattern, addiw rd, rs1, 0. 3075349cc55cSDimitry Andric if (N->getMachineOpcode() != RISCV::ADDIW || 3076349cc55cSDimitry Andric !isNullConstant(N->getOperand(1))) 3077349cc55cSDimitry Andric return false; 3078349cc55cSDimitry Andric 3079349cc55cSDimitry Andric SDValue N0 = N->getOperand(0); 3080349cc55cSDimitry Andric if (!N0.isMachineOpcode()) 3081349cc55cSDimitry Andric return false; 3082349cc55cSDimitry Andric 3083349cc55cSDimitry Andric switch (N0.getMachineOpcode()) { 3084349cc55cSDimitry Andric default: 3085349cc55cSDimitry Andric break; 3086349cc55cSDimitry Andric case RISCV::ADD: 3087349cc55cSDimitry Andric case RISCV::ADDI: 3088349cc55cSDimitry Andric case RISCV::SUB: 3089349cc55cSDimitry Andric case RISCV::MUL: 3090349cc55cSDimitry Andric case RISCV::SLLI: { 3091349cc55cSDimitry Andric // Convert sext.w+add/sub/mul to their W instructions. This will create 3092349cc55cSDimitry Andric // a new independent instruction. This improves latency. 3093349cc55cSDimitry Andric unsigned Opc; 3094349cc55cSDimitry Andric switch (N0.getMachineOpcode()) { 3095349cc55cSDimitry Andric default: 3096349cc55cSDimitry Andric llvm_unreachable("Unexpected opcode!"); 3097349cc55cSDimitry Andric case RISCV::ADD: Opc = RISCV::ADDW; break; 3098349cc55cSDimitry Andric case RISCV::ADDI: Opc = RISCV::ADDIW; break; 3099349cc55cSDimitry Andric case RISCV::SUB: Opc = RISCV::SUBW; break; 3100349cc55cSDimitry Andric case RISCV::MUL: Opc = RISCV::MULW; break; 3101349cc55cSDimitry Andric case RISCV::SLLI: Opc = RISCV::SLLIW; break; 3102349cc55cSDimitry Andric } 3103349cc55cSDimitry Andric 3104349cc55cSDimitry Andric SDValue N00 = N0.getOperand(0); 3105349cc55cSDimitry Andric SDValue N01 = N0.getOperand(1); 3106349cc55cSDimitry Andric 3107349cc55cSDimitry Andric // Shift amount needs to be uimm5. 3108349cc55cSDimitry Andric if (N0.getMachineOpcode() == RISCV::SLLI && 3109349cc55cSDimitry Andric !isUInt<5>(cast<ConstantSDNode>(N01)->getSExtValue())) 3110349cc55cSDimitry Andric break; 3111349cc55cSDimitry Andric 3112349cc55cSDimitry Andric SDNode *Result = 3113349cc55cSDimitry Andric CurDAG->getMachineNode(Opc, SDLoc(N), N->getValueType(0), 3114349cc55cSDimitry Andric N00, N01); 3115349cc55cSDimitry Andric ReplaceUses(N, Result); 3116349cc55cSDimitry Andric return true; 3117349cc55cSDimitry Andric } 3118349cc55cSDimitry Andric case RISCV::ADDW: 3119349cc55cSDimitry Andric case RISCV::ADDIW: 3120349cc55cSDimitry Andric case RISCV::SUBW: 3121349cc55cSDimitry Andric case RISCV::MULW: 3122349cc55cSDimitry Andric case RISCV::SLLIW: 3123bdd1243dSDimitry Andric case RISCV::PACKW: 312406c3fb27SDimitry Andric case RISCV::TH_MULAW: 312506c3fb27SDimitry Andric case RISCV::TH_MULAH: 312606c3fb27SDimitry Andric case RISCV::TH_MULSW: 312706c3fb27SDimitry Andric case RISCV::TH_MULSH: 3128349cc55cSDimitry Andric // Result is already sign extended just remove the sext.w. 3129349cc55cSDimitry Andric // NOTE: We only handle the nodes that are selected with hasAllWUsers. 3130349cc55cSDimitry Andric ReplaceUses(N, N0.getNode()); 3131349cc55cSDimitry Andric return true; 3132349cc55cSDimitry Andric } 3133349cc55cSDimitry Andric 3134349cc55cSDimitry Andric return false; 31350b57cec5SDimitry Andric } 31360b57cec5SDimitry Andric 313706c3fb27SDimitry Andric static bool usesAllOnesMask(SDValue MaskOp, SDValue GlueOp) { 313881ad6265SDimitry Andric // Check that we're using V0 as a mask register. 313906c3fb27SDimitry Andric if (!isa<RegisterSDNode>(MaskOp) || 314006c3fb27SDimitry Andric cast<RegisterSDNode>(MaskOp)->getReg() != RISCV::V0) 314181ad6265SDimitry Andric return false; 314281ad6265SDimitry Andric 314381ad6265SDimitry Andric // The glued user defines V0. 314406c3fb27SDimitry Andric const auto *Glued = GlueOp.getNode(); 314581ad6265SDimitry Andric 314681ad6265SDimitry Andric if (!Glued || Glued->getOpcode() != ISD::CopyToReg) 314781ad6265SDimitry Andric return false; 314881ad6265SDimitry Andric 314981ad6265SDimitry Andric // Check that we're defining V0 as a mask register. 315081ad6265SDimitry Andric if (!isa<RegisterSDNode>(Glued->getOperand(1)) || 315181ad6265SDimitry Andric cast<RegisterSDNode>(Glued->getOperand(1))->getReg() != RISCV::V0) 315281ad6265SDimitry Andric return false; 315381ad6265SDimitry Andric 315481ad6265SDimitry Andric // Check the instruction defining V0; it needs to be a VMSET pseudo. 315581ad6265SDimitry Andric SDValue MaskSetter = Glued->getOperand(2); 315681ad6265SDimitry Andric 315781ad6265SDimitry Andric const auto IsVMSet = [](unsigned Opc) { 315881ad6265SDimitry Andric return Opc == RISCV::PseudoVMSET_M_B1 || Opc == RISCV::PseudoVMSET_M_B16 || 315981ad6265SDimitry Andric Opc == RISCV::PseudoVMSET_M_B2 || Opc == RISCV::PseudoVMSET_M_B32 || 316081ad6265SDimitry Andric Opc == RISCV::PseudoVMSET_M_B4 || Opc == RISCV::PseudoVMSET_M_B64 || 316181ad6265SDimitry Andric Opc == RISCV::PseudoVMSET_M_B8; 316281ad6265SDimitry Andric }; 316381ad6265SDimitry Andric 316481ad6265SDimitry Andric // TODO: Check that the VMSET is the expected bitwidth? The pseudo has 316581ad6265SDimitry Andric // undefined behaviour if it's the wrong bitwidth, so we could choose to 316681ad6265SDimitry Andric // assume that it's all-ones? Same applies to its VL. 3167bdd1243dSDimitry Andric return MaskSetter->isMachineOpcode() && 3168bdd1243dSDimitry Andric IsVMSet(MaskSetter.getMachineOpcode()); 3169bdd1243dSDimitry Andric } 3170bdd1243dSDimitry Andric 317106c3fb27SDimitry Andric // Return true if we can make sure mask of N is all-ones mask. 317206c3fb27SDimitry Andric static bool usesAllOnesMask(SDNode *N, unsigned MaskOpIdx) { 317306c3fb27SDimitry Andric return usesAllOnesMask(N->getOperand(MaskOpIdx), 317406c3fb27SDimitry Andric N->getOperand(N->getNumOperands() - 1)); 317506c3fb27SDimitry Andric } 317606c3fb27SDimitry Andric 317706c3fb27SDimitry Andric static bool isImplicitDef(SDValue V) { 317806c3fb27SDimitry Andric return V.isMachineOpcode() && 317906c3fb27SDimitry Andric V.getMachineOpcode() == TargetOpcode::IMPLICIT_DEF; 318006c3fb27SDimitry Andric } 318106c3fb27SDimitry Andric 3182bdd1243dSDimitry Andric // Optimize masked RVV pseudo instructions with a known all-ones mask to their 3183bdd1243dSDimitry Andric // corresponding "unmasked" pseudo versions. The mask we're interested in will 3184bdd1243dSDimitry Andric // take the form of a V0 physical register operand, with a glued 3185bdd1243dSDimitry Andric // register-setting instruction. 3186bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeMaskedRVV(SDNode *N) { 3187bdd1243dSDimitry Andric const RISCV::RISCVMaskedPseudoInfo *I = 3188bdd1243dSDimitry Andric RISCV::getMaskedPseudoInfo(N->getMachineOpcode()); 3189bdd1243dSDimitry Andric if (!I) 3190bdd1243dSDimitry Andric return false; 3191bdd1243dSDimitry Andric 3192bdd1243dSDimitry Andric unsigned MaskOpIdx = I->MaskOpIdx; 3193bdd1243dSDimitry Andric if (!usesAllOnesMask(N, MaskOpIdx)) 319481ad6265SDimitry Andric return false; 319581ad6265SDimitry Andric 319606c3fb27SDimitry Andric // There are two classes of pseudos in the table - compares and 319706c3fb27SDimitry Andric // everything else. See the comment on RISCVMaskedPseudo for details. 319806c3fb27SDimitry Andric const unsigned Opc = I->UnmaskedPseudo; 319906c3fb27SDimitry Andric const MCInstrDesc &MCID = TII->get(Opc); 320006c3fb27SDimitry Andric const bool UseTUPseudo = RISCVII::hasVecPolicyOp(MCID.TSFlags); 320106c3fb27SDimitry Andric #ifndef NDEBUG 320206c3fb27SDimitry Andric const MCInstrDesc &MaskedMCID = TII->get(N->getMachineOpcode()); 320306c3fb27SDimitry Andric assert(RISCVII::hasVecPolicyOp(MaskedMCID.TSFlags) == 320406c3fb27SDimitry Andric RISCVII::hasVecPolicyOp(MCID.TSFlags) && 320506c3fb27SDimitry Andric "Masked and unmasked pseudos are inconsistent"); 320606c3fb27SDimitry Andric const bool HasTiedDest = RISCVII::isFirstDefTiedToFirstUse(MCID); 320706c3fb27SDimitry Andric assert(UseTUPseudo == HasTiedDest && "Unexpected pseudo structure"); 320806c3fb27SDimitry Andric #endif 320981ad6265SDimitry Andric 321081ad6265SDimitry Andric SmallVector<SDValue, 8> Ops; 321106c3fb27SDimitry Andric // Skip the merge operand at index 0 if !UseTUPseudo. 321206c3fb27SDimitry Andric for (unsigned I = !UseTUPseudo, E = N->getNumOperands(); I != E; I++) { 321306c3fb27SDimitry Andric // Skip the mask, and the Glue. 321481ad6265SDimitry Andric SDValue Op = N->getOperand(I); 321506c3fb27SDimitry Andric if (I == MaskOpIdx || Op.getValueType() == MVT::Glue) 321681ad6265SDimitry Andric continue; 321781ad6265SDimitry Andric Ops.push_back(Op); 321881ad6265SDimitry Andric } 321981ad6265SDimitry Andric 322081ad6265SDimitry Andric // Transitively apply any node glued to our new node. 3221bdd1243dSDimitry Andric const auto *Glued = N->getGluedNode(); 322281ad6265SDimitry Andric if (auto *TGlued = Glued->getGluedNode()) 322381ad6265SDimitry Andric Ops.push_back(SDValue(TGlued, TGlued->getNumValues() - 1)); 322481ad6265SDimitry Andric 322581ad6265SDimitry Andric SDNode *Result = CurDAG->getMachineNode(Opc, SDLoc(N), N->getVTList(), Ops); 3226bdd1243dSDimitry Andric Result->setFlags(N->getFlags()); 322781ad6265SDimitry Andric ReplaceUses(N, Result); 322881ad6265SDimitry Andric 322981ad6265SDimitry Andric return true; 323081ad6265SDimitry Andric } 323181ad6265SDimitry Andric 323206c3fb27SDimitry Andric static bool IsVMerge(SDNode *N) { 323306c3fb27SDimitry Andric unsigned Opc = N->getMachineOpcode(); 323406c3fb27SDimitry Andric return Opc == RISCV::PseudoVMERGE_VVM_MF8 || 323506c3fb27SDimitry Andric Opc == RISCV::PseudoVMERGE_VVM_MF4 || 323606c3fb27SDimitry Andric Opc == RISCV::PseudoVMERGE_VVM_MF2 || 323706c3fb27SDimitry Andric Opc == RISCV::PseudoVMERGE_VVM_M1 || 323806c3fb27SDimitry Andric Opc == RISCV::PseudoVMERGE_VVM_M2 || 323906c3fb27SDimitry Andric Opc == RISCV::PseudoVMERGE_VVM_M4 || Opc == RISCV::PseudoVMERGE_VVM_M8; 324006c3fb27SDimitry Andric } 3241bdd1243dSDimitry Andric 324206c3fb27SDimitry Andric static bool IsVMv(SDNode *N) { 324306c3fb27SDimitry Andric unsigned Opc = N->getMachineOpcode(); 324406c3fb27SDimitry Andric return Opc == RISCV::PseudoVMV_V_V_MF8 || Opc == RISCV::PseudoVMV_V_V_MF4 || 324506c3fb27SDimitry Andric Opc == RISCV::PseudoVMV_V_V_MF2 || Opc == RISCV::PseudoVMV_V_V_M1 || 324606c3fb27SDimitry Andric Opc == RISCV::PseudoVMV_V_V_M2 || Opc == RISCV::PseudoVMV_V_V_M4 || 324706c3fb27SDimitry Andric Opc == RISCV::PseudoVMV_V_V_M8; 324806c3fb27SDimitry Andric } 324906c3fb27SDimitry Andric 325006c3fb27SDimitry Andric static unsigned GetVMSetForLMul(RISCVII::VLMUL LMUL) { 325106c3fb27SDimitry Andric switch (LMUL) { 325206c3fb27SDimitry Andric case RISCVII::LMUL_F8: 325306c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B1; 325406c3fb27SDimitry Andric case RISCVII::LMUL_F4: 325506c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B2; 325606c3fb27SDimitry Andric case RISCVII::LMUL_F2: 325706c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B4; 325806c3fb27SDimitry Andric case RISCVII::LMUL_1: 325906c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B8; 326006c3fb27SDimitry Andric case RISCVII::LMUL_2: 326106c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B16; 326206c3fb27SDimitry Andric case RISCVII::LMUL_4: 326306c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B32; 326406c3fb27SDimitry Andric case RISCVII::LMUL_8: 326506c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B64; 326606c3fb27SDimitry Andric case RISCVII::LMUL_RESERVED: 326706c3fb27SDimitry Andric llvm_unreachable("Unexpected LMUL"); 326806c3fb27SDimitry Andric } 326906c3fb27SDimitry Andric llvm_unreachable("Unknown VLMUL enum"); 327006c3fb27SDimitry Andric } 327106c3fb27SDimitry Andric 327206c3fb27SDimitry Andric // Try to fold away VMERGE_VVM instructions. We handle these cases: 327306c3fb27SDimitry Andric // -Masked TU VMERGE_VVM combined with an unmasked TA instruction instruction 327406c3fb27SDimitry Andric // folds to a masked TU instruction. VMERGE_VVM must have have merge operand 327506c3fb27SDimitry Andric // same as false operand. 327606c3fb27SDimitry Andric // -Masked TA VMERGE_VVM combined with an unmasked TA instruction fold to a 327706c3fb27SDimitry Andric // masked TA instruction. 327806c3fb27SDimitry Andric // -Unmasked TU VMERGE_VVM combined with a masked MU TA instruction folds to 327906c3fb27SDimitry Andric // masked TU instruction. Both instructions must have the same merge operand. 328006c3fb27SDimitry Andric // VMERGE_VVM must have have merge operand same as false operand. 328106c3fb27SDimitry Andric // Note: The VMERGE_VVM forms above (TA, and TU) refer to the policy implied, 328206c3fb27SDimitry Andric // not the pseudo name. That is, a TA VMERGE_VVM can be either the _TU pseudo 328306c3fb27SDimitry Andric // form with an IMPLICIT_DEF passthrough operand or the unsuffixed (TA) pseudo 328406c3fb27SDimitry Andric // form. 328506c3fb27SDimitry Andric bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) { 328606c3fb27SDimitry Andric SDValue Merge, False, True, VL, Mask, Glue; 328706c3fb27SDimitry Andric // A vmv.v.v is equivalent to a vmerge with an all-ones mask. 328806c3fb27SDimitry Andric if (IsVMv(N)) { 328906c3fb27SDimitry Andric Merge = N->getOperand(0); 329006c3fb27SDimitry Andric False = N->getOperand(0); 329106c3fb27SDimitry Andric True = N->getOperand(1); 329206c3fb27SDimitry Andric VL = N->getOperand(2); 329306c3fb27SDimitry Andric // A vmv.v.v won't have a Mask or Glue, instead we'll construct an all-ones 329406c3fb27SDimitry Andric // mask later below. 329506c3fb27SDimitry Andric } else { 329606c3fb27SDimitry Andric assert(IsVMerge(N)); 329706c3fb27SDimitry Andric Merge = N->getOperand(0); 329806c3fb27SDimitry Andric False = N->getOperand(1); 329906c3fb27SDimitry Andric True = N->getOperand(2); 330006c3fb27SDimitry Andric Mask = N->getOperand(3); 330106c3fb27SDimitry Andric VL = N->getOperand(4); 330206c3fb27SDimitry Andric // We always have a glue node for the mask at v0. 330306c3fb27SDimitry Andric Glue = N->getOperand(N->getNumOperands() - 1); 330406c3fb27SDimitry Andric } 330506c3fb27SDimitry Andric assert(!Mask || cast<RegisterSDNode>(Mask)->getReg() == RISCV::V0); 330606c3fb27SDimitry Andric assert(!Glue || Glue.getValueType() == MVT::Glue); 330706c3fb27SDimitry Andric 330806c3fb27SDimitry Andric // We require that either merge and false are the same, or that merge 330906c3fb27SDimitry Andric // is undefined. 331006c3fb27SDimitry Andric if (Merge != False && !isImplicitDef(Merge)) 331106c3fb27SDimitry Andric return false; 3312bdd1243dSDimitry Andric 3313bdd1243dSDimitry Andric assert(True.getResNo() == 0 && 3314bdd1243dSDimitry Andric "Expect True is the first output of an instruction."); 3315bdd1243dSDimitry Andric 3316bdd1243dSDimitry Andric // Need N is the exactly one using True. 3317bdd1243dSDimitry Andric if (!True.hasOneUse()) 3318bdd1243dSDimitry Andric return false; 3319bdd1243dSDimitry Andric 3320bdd1243dSDimitry Andric if (!True.isMachineOpcode()) 3321bdd1243dSDimitry Andric return false; 3322bdd1243dSDimitry Andric 3323bdd1243dSDimitry Andric unsigned TrueOpc = True.getMachineOpcode(); 332406c3fb27SDimitry Andric const MCInstrDesc &TrueMCID = TII->get(TrueOpc); 332506c3fb27SDimitry Andric uint64_t TrueTSFlags = TrueMCID.TSFlags; 332606c3fb27SDimitry Andric bool HasTiedDest = RISCVII::isFirstDefTiedToFirstUse(TrueMCID); 3327bdd1243dSDimitry Andric 332806c3fb27SDimitry Andric bool IsMasked = false; 3329bdd1243dSDimitry Andric const RISCV::RISCVMaskedPseudoInfo *Info = 333006c3fb27SDimitry Andric RISCV::lookupMaskedIntrinsicByUnmasked(TrueOpc); 333106c3fb27SDimitry Andric if (!Info && HasTiedDest) { 333206c3fb27SDimitry Andric Info = RISCV::getMaskedPseudoInfo(TrueOpc); 333306c3fb27SDimitry Andric IsMasked = true; 333406c3fb27SDimitry Andric } 3335bdd1243dSDimitry Andric 3336bdd1243dSDimitry Andric if (!Info) 3337bdd1243dSDimitry Andric return false; 3338bdd1243dSDimitry Andric 333906c3fb27SDimitry Andric if (HasTiedDest && !isImplicitDef(True->getOperand(0))) { 334006c3fb27SDimitry Andric // The vmerge instruction must be TU. 334106c3fb27SDimitry Andric // FIXME: This could be relaxed, but we need to handle the policy for the 334206c3fb27SDimitry Andric // resulting op correctly. 334306c3fb27SDimitry Andric if (isImplicitDef(Merge)) 334406c3fb27SDimitry Andric return false; 334506c3fb27SDimitry Andric SDValue MergeOpTrue = True->getOperand(0); 334606c3fb27SDimitry Andric // Both the vmerge instruction and the True instruction must have the same 334706c3fb27SDimitry Andric // merge operand. 334806c3fb27SDimitry Andric if (False != MergeOpTrue) 334906c3fb27SDimitry Andric return false; 335006c3fb27SDimitry Andric } 335106c3fb27SDimitry Andric 335206c3fb27SDimitry Andric if (IsMasked) { 335306c3fb27SDimitry Andric assert(HasTiedDest && "Expected tied dest"); 335406c3fb27SDimitry Andric // The vmerge instruction must be TU. 335506c3fb27SDimitry Andric if (isImplicitDef(Merge)) 335606c3fb27SDimitry Andric return false; 335706c3fb27SDimitry Andric // The vmerge instruction must have an all 1s mask since we're going to keep 335806c3fb27SDimitry Andric // the mask from the True instruction. 335906c3fb27SDimitry Andric // FIXME: Support mask agnostic True instruction which would have an 336006c3fb27SDimitry Andric // undef merge operand. 336106c3fb27SDimitry Andric if (Mask && !usesAllOnesMask(Mask, Glue)) 336206c3fb27SDimitry Andric return false; 336306c3fb27SDimitry Andric } 336406c3fb27SDimitry Andric 336506c3fb27SDimitry Andric // Skip if True has side effect. 336606c3fb27SDimitry Andric // TODO: Support vleff and vlsegff. 336706c3fb27SDimitry Andric if (TII->get(TrueOpc).hasUnmodeledSideEffects()) 336806c3fb27SDimitry Andric return false; 336906c3fb27SDimitry Andric 337006c3fb27SDimitry Andric // The last operand of a masked instruction may be glued. 337106c3fb27SDimitry Andric bool HasGlueOp = True->getGluedNode() != nullptr; 337206c3fb27SDimitry Andric 337306c3fb27SDimitry Andric // The chain operand may exist either before the glued operands or in the last 337406c3fb27SDimitry Andric // position. 337506c3fb27SDimitry Andric unsigned TrueChainOpIdx = True.getNumOperands() - HasGlueOp - 1; 3376bdd1243dSDimitry Andric bool HasChainOp = 337706c3fb27SDimitry Andric True.getOperand(TrueChainOpIdx).getValueType() == MVT::Other; 3378bdd1243dSDimitry Andric 3379bdd1243dSDimitry Andric if (HasChainOp) { 3380bdd1243dSDimitry Andric // Avoid creating cycles in the DAG. We must ensure that none of the other 3381bdd1243dSDimitry Andric // operands depend on True through it's Chain. 3382bdd1243dSDimitry Andric SmallVector<const SDNode *, 4> LoopWorklist; 3383bdd1243dSDimitry Andric SmallPtrSet<const SDNode *, 16> Visited; 3384bdd1243dSDimitry Andric LoopWorklist.push_back(False.getNode()); 338506c3fb27SDimitry Andric if (Mask) 3386bdd1243dSDimitry Andric LoopWorklist.push_back(Mask.getNode()); 3387bdd1243dSDimitry Andric LoopWorklist.push_back(VL.getNode()); 338806c3fb27SDimitry Andric if (Glue) 338906c3fb27SDimitry Andric LoopWorklist.push_back(Glue.getNode()); 3390bdd1243dSDimitry Andric if (SDNode::hasPredecessorHelper(True.getNode(), Visited, LoopWorklist)) 3391bdd1243dSDimitry Andric return false; 3392bdd1243dSDimitry Andric } 3393bdd1243dSDimitry Andric 339406c3fb27SDimitry Andric // The vector policy operand may be present for masked intrinsics 339506c3fb27SDimitry Andric bool HasVecPolicyOp = RISCVII::hasVecPolicyOp(TrueTSFlags); 339606c3fb27SDimitry Andric unsigned TrueVLIndex = 339706c3fb27SDimitry Andric True.getNumOperands() - HasVecPolicyOp - HasChainOp - HasGlueOp - 2; 3398bdd1243dSDimitry Andric SDValue TrueVL = True.getOperand(TrueVLIndex); 339906c3fb27SDimitry Andric SDValue SEW = True.getOperand(TrueVLIndex + 1); 3400bdd1243dSDimitry Andric 340106c3fb27SDimitry Andric auto GetMinVL = [](SDValue LHS, SDValue RHS) { 340206c3fb27SDimitry Andric if (LHS == RHS) 340306c3fb27SDimitry Andric return LHS; 340406c3fb27SDimitry Andric if (isAllOnesConstant(LHS)) 340506c3fb27SDimitry Andric return RHS; 340606c3fb27SDimitry Andric if (isAllOnesConstant(RHS)) 340706c3fb27SDimitry Andric return LHS; 340806c3fb27SDimitry Andric auto *CLHS = dyn_cast<ConstantSDNode>(LHS); 340906c3fb27SDimitry Andric auto *CRHS = dyn_cast<ConstantSDNode>(RHS); 341006c3fb27SDimitry Andric if (!CLHS || !CRHS) 341106c3fb27SDimitry Andric return SDValue(); 341206c3fb27SDimitry Andric return CLHS->getZExtValue() <= CRHS->getZExtValue() ? LHS : RHS; 3413bdd1243dSDimitry Andric }; 3414bdd1243dSDimitry Andric 341506c3fb27SDimitry Andric // Because N and True must have the same merge operand (or True's operand is 341606c3fb27SDimitry Andric // implicit_def), the "effective" body is the minimum of their VLs. 34178a4dda33SDimitry Andric SDValue OrigVL = VL; 341806c3fb27SDimitry Andric VL = GetMinVL(TrueVL, VL); 341906c3fb27SDimitry Andric if (!VL) 342006c3fb27SDimitry Andric return false; 342106c3fb27SDimitry Andric 342206c3fb27SDimitry Andric // If we end up changing the VL or mask of True, then we need to make sure it 342306c3fb27SDimitry Andric // doesn't raise any observable fp exceptions, since changing the active 342406c3fb27SDimitry Andric // elements will affect how fflags is set. 342506c3fb27SDimitry Andric if (TrueVL != VL || !IsMasked) 342606c3fb27SDimitry Andric if (mayRaiseFPException(True.getNode()) && 342706c3fb27SDimitry Andric !True->getFlags().hasNoFPExcept()) 3428bdd1243dSDimitry Andric return false; 3429bdd1243dSDimitry Andric 3430bdd1243dSDimitry Andric SDLoc DL(N); 343106c3fb27SDimitry Andric 343206c3fb27SDimitry Andric // From the preconditions we checked above, we know the mask and thus glue 343306c3fb27SDimitry Andric // for the result node will be taken from True. 343406c3fb27SDimitry Andric if (IsMasked) { 343506c3fb27SDimitry Andric Mask = True->getOperand(Info->MaskOpIdx); 343606c3fb27SDimitry Andric Glue = True->getOperand(True->getNumOperands() - 1); 343706c3fb27SDimitry Andric assert(Glue.getValueType() == MVT::Glue); 343806c3fb27SDimitry Andric } 343906c3fb27SDimitry Andric // If we end up using the vmerge mask the vmerge is actually a vmv.v.v, create 344006c3fb27SDimitry Andric // an all-ones mask to use. 344106c3fb27SDimitry Andric else if (IsVMv(N)) { 344206c3fb27SDimitry Andric unsigned TSFlags = TII->get(N->getMachineOpcode()).TSFlags; 344306c3fb27SDimitry Andric unsigned VMSetOpc = GetVMSetForLMul(RISCVII::getLMul(TSFlags)); 344406c3fb27SDimitry Andric ElementCount EC = N->getValueType(0).getVectorElementCount(); 344506c3fb27SDimitry Andric MVT MaskVT = MVT::getVectorVT(MVT::i1, EC); 344606c3fb27SDimitry Andric 344706c3fb27SDimitry Andric SDValue AllOnesMask = 344806c3fb27SDimitry Andric SDValue(CurDAG->getMachineNode(VMSetOpc, DL, MaskVT, VL, SEW), 0); 344906c3fb27SDimitry Andric SDValue MaskCopy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, 345006c3fb27SDimitry Andric RISCV::V0, AllOnesMask, SDValue()); 345106c3fb27SDimitry Andric Mask = CurDAG->getRegister(RISCV::V0, MaskVT); 345206c3fb27SDimitry Andric Glue = MaskCopy.getValue(1); 345306c3fb27SDimitry Andric } 345406c3fb27SDimitry Andric 3455bdd1243dSDimitry Andric unsigned MaskedOpc = Info->MaskedPseudo; 345606c3fb27SDimitry Andric #ifndef NDEBUG 345706c3fb27SDimitry Andric const MCInstrDesc &MaskedMCID = TII->get(MaskedOpc); 345806c3fb27SDimitry Andric assert(RISCVII::hasVecPolicyOp(MaskedMCID.TSFlags) && 3459bdd1243dSDimitry Andric "Expected instructions with mask have policy operand."); 346006c3fb27SDimitry Andric assert(MaskedMCID.getOperandConstraint(MaskedMCID.getNumDefs(), 346106c3fb27SDimitry Andric MCOI::TIED_TO) == 0 && 346206c3fb27SDimitry Andric "Expected instructions with mask have a tied dest."); 346306c3fb27SDimitry Andric #endif 346406c3fb27SDimitry Andric 34658a4dda33SDimitry Andric // Use a tumu policy, relaxing it to tail agnostic provided that the merge 34668a4dda33SDimitry Andric // operand is undefined. 34678a4dda33SDimitry Andric // 34688a4dda33SDimitry Andric // However, if the VL became smaller than what the vmerge had originally, then 34698a4dda33SDimitry Andric // elements past VL that were previously in the vmerge's body will have moved 34708a4dda33SDimitry Andric // to the tail. In that case we always need to use tail undisturbed to 34718a4dda33SDimitry Andric // preserve them. 34728a4dda33SDimitry Andric bool MergeVLShrunk = VL != OrigVL; 34738a4dda33SDimitry Andric uint64_t Policy = (isImplicitDef(Merge) && !MergeVLShrunk) 34748a4dda33SDimitry Andric ? RISCVII::TAIL_AGNOSTIC 34758a4dda33SDimitry Andric : /*TUMU*/ 0; 347606c3fb27SDimitry Andric SDValue PolicyOp = 347706c3fb27SDimitry Andric CurDAG->getTargetConstant(Policy, DL, Subtarget->getXLenVT()); 347806c3fb27SDimitry Andric 3479bdd1243dSDimitry Andric 3480bdd1243dSDimitry Andric SmallVector<SDValue, 8> Ops; 3481bdd1243dSDimitry Andric Ops.push_back(False); 348206c3fb27SDimitry Andric 348306c3fb27SDimitry Andric const bool HasRoundingMode = RISCVII::hasRoundModeOp(TrueTSFlags); 348406c3fb27SDimitry Andric const unsigned NormalOpsEnd = TrueVLIndex - IsMasked - HasRoundingMode; 348506c3fb27SDimitry Andric assert(!IsMasked || NormalOpsEnd == Info->MaskOpIdx); 348606c3fb27SDimitry Andric Ops.append(True->op_begin() + HasTiedDest, True->op_begin() + NormalOpsEnd); 348706c3fb27SDimitry Andric 348806c3fb27SDimitry Andric Ops.push_back(Mask); 348906c3fb27SDimitry Andric 349006c3fb27SDimitry Andric // For unmasked "VOp" with rounding mode operand, that is interfaces like 349106c3fb27SDimitry Andric // (..., rm, vl) or (..., rm, vl, policy). 349206c3fb27SDimitry Andric // Its masked version is (..., vm, rm, vl, policy). 349306c3fb27SDimitry Andric // Check the rounding mode pseudo nodes under RISCVInstrInfoVPseudos.td 349406c3fb27SDimitry Andric if (HasRoundingMode) 349506c3fb27SDimitry Andric Ops.push_back(True->getOperand(TrueVLIndex - 1)); 349606c3fb27SDimitry Andric 349706c3fb27SDimitry Andric Ops.append({VL, SEW, PolicyOp}); 3498bdd1243dSDimitry Andric 3499bdd1243dSDimitry Andric // Result node should have chain operand of True. 3500bdd1243dSDimitry Andric if (HasChainOp) 350106c3fb27SDimitry Andric Ops.push_back(True.getOperand(TrueChainOpIdx)); 3502bdd1243dSDimitry Andric 350306c3fb27SDimitry Andric // Add the glue for the CopyToReg of mask->v0. 350406c3fb27SDimitry Andric Ops.push_back(Glue); 3505bdd1243dSDimitry Andric 3506bdd1243dSDimitry Andric SDNode *Result = 3507bdd1243dSDimitry Andric CurDAG->getMachineNode(MaskedOpc, DL, True->getVTList(), Ops); 3508bdd1243dSDimitry Andric Result->setFlags(True->getFlags()); 3509bdd1243dSDimitry Andric 3510bdd1243dSDimitry Andric // Replace vmerge.vvm node by Result. 3511bdd1243dSDimitry Andric ReplaceUses(SDValue(N, 0), SDValue(Result, 0)); 3512bdd1243dSDimitry Andric 3513bdd1243dSDimitry Andric // Replace another value of True. E.g. chain and VL. 3514bdd1243dSDimitry Andric for (unsigned Idx = 1; Idx < True->getNumValues(); ++Idx) 3515bdd1243dSDimitry Andric ReplaceUses(True.getValue(Idx), SDValue(Result, Idx)); 3516bdd1243dSDimitry Andric 3517bdd1243dSDimitry Andric // Try to transform Result to unmasked intrinsic. 3518bdd1243dSDimitry Andric doPeepholeMaskedRVV(Result); 3519bdd1243dSDimitry Andric return true; 3520bdd1243dSDimitry Andric } 3521bdd1243dSDimitry Andric 352206c3fb27SDimitry Andric // Transform (VMERGE_VVM_<LMUL> false, false, true, allones, vl, sew) to 352306c3fb27SDimitry Andric // (VMV_V_V_<LMUL> false, true, vl, sew). It may decrease uses of VMSET. 352406c3fb27SDimitry Andric bool RISCVDAGToDAGISel::performVMergeToVMv(SDNode *N) { 352506c3fb27SDimitry Andric #define CASE_VMERGE_TO_VMV(lmul) \ 352606c3fb27SDimitry Andric case RISCV::PseudoVMERGE_VVM_##lmul: \ 352706c3fb27SDimitry Andric NewOpc = RISCV::PseudoVMV_V_V_##lmul; \ 352806c3fb27SDimitry Andric break; 3529bdd1243dSDimitry Andric unsigned NewOpc; 3530bdd1243dSDimitry Andric switch (N->getMachineOpcode()) { 3531bdd1243dSDimitry Andric default: 353206c3fb27SDimitry Andric llvm_unreachable("Expected VMERGE_VVM_<LMUL> instruction."); 353306c3fb27SDimitry Andric CASE_VMERGE_TO_VMV(MF8) 353406c3fb27SDimitry Andric CASE_VMERGE_TO_VMV(MF4) 353506c3fb27SDimitry Andric CASE_VMERGE_TO_VMV(MF2) 353606c3fb27SDimitry Andric CASE_VMERGE_TO_VMV(M1) 353706c3fb27SDimitry Andric CASE_VMERGE_TO_VMV(M2) 353806c3fb27SDimitry Andric CASE_VMERGE_TO_VMV(M4) 353906c3fb27SDimitry Andric CASE_VMERGE_TO_VMV(M8) 3540bdd1243dSDimitry Andric } 3541bdd1243dSDimitry Andric 3542bdd1243dSDimitry Andric if (!usesAllOnesMask(N, /* MaskOpIdx */ 3)) 3543bdd1243dSDimitry Andric return false; 3544bdd1243dSDimitry Andric 3545bdd1243dSDimitry Andric SDLoc DL(N); 354606c3fb27SDimitry Andric SDValue PolicyOp = 354706c3fb27SDimitry Andric CurDAG->getTargetConstant(/*TUMU*/ 0, DL, Subtarget->getXLenVT()); 354806c3fb27SDimitry Andric SDNode *Result = CurDAG->getMachineNode( 354906c3fb27SDimitry Andric NewOpc, DL, N->getValueType(0), 355006c3fb27SDimitry Andric {N->getOperand(1), N->getOperand(2), N->getOperand(4), N->getOperand(5), 355106c3fb27SDimitry Andric PolicyOp}); 3552bdd1243dSDimitry Andric ReplaceUses(N, Result); 3553bdd1243dSDimitry Andric return true; 3554bdd1243dSDimitry Andric } 3555bdd1243dSDimitry Andric 3556bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeMergeVVMFold() { 3557bdd1243dSDimitry Andric bool MadeChange = false; 3558bdd1243dSDimitry Andric SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); 3559bdd1243dSDimitry Andric 3560bdd1243dSDimitry Andric while (Position != CurDAG->allnodes_begin()) { 3561bdd1243dSDimitry Andric SDNode *N = &*--Position; 3562bdd1243dSDimitry Andric if (N->use_empty() || !N->isMachineOpcode()) 3563bdd1243dSDimitry Andric continue; 3564bdd1243dSDimitry Andric 356506c3fb27SDimitry Andric if (IsVMerge(N) || IsVMv(N)) 356606c3fb27SDimitry Andric MadeChange |= performCombineVMergeAndVOps(N); 356706c3fb27SDimitry Andric if (IsVMerge(N) && N->getOperand(0) == N->getOperand(1)) 356806c3fb27SDimitry Andric MadeChange |= performVMergeToVMv(N); 3569bdd1243dSDimitry Andric } 3570bdd1243dSDimitry Andric return MadeChange; 3571bdd1243dSDimitry Andric } 3572bdd1243dSDimitry Andric 35730b57cec5SDimitry Andric // This pass converts a legalized DAG into a RISCV-specific DAG, ready 35740b57cec5SDimitry Andric // for instruction scheduling. 357581ad6265SDimitry Andric FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM, 357681ad6265SDimitry Andric CodeGenOpt::Level OptLevel) { 357781ad6265SDimitry Andric return new RISCVDAGToDAGISel(TM, OptLevel); 35780b57cec5SDimitry Andric } 3579bdd1243dSDimitry Andric 3580bdd1243dSDimitry Andric char RISCVDAGToDAGISel::ID = 0; 3581bdd1243dSDimitry Andric 3582bdd1243dSDimitry Andric INITIALIZE_PASS(RISCVDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false) 3583