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" 255ffd83dbSDimitry Andric 260b57cec5SDimitry Andric using namespace llvm; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric #define DEBUG_TYPE "riscv-isel" 2906c3fb27SDimitry Andric #define PASS_NAME "RISC-V DAG->DAG Pattern Instruction Selection" 300b57cec5SDimitry Andric 315f757f3fSDimitry Andric static cl::opt<bool> UsePseudoMovImm( 325f757f3fSDimitry Andric "riscv-use-rematerializable-movimm", cl::Hidden, 335f757f3fSDimitry Andric cl::desc("Use a rematerializable pseudoinstruction for 2 instruction " 345f757f3fSDimitry Andric "constant materialization"), 355f757f3fSDimitry Andric cl::init(false)); 365f757f3fSDimitry Andric 37bdd1243dSDimitry Andric namespace llvm::RISCV { 38fe6060f1SDimitry Andric #define GET_RISCVVSSEGTable_IMPL 39fe6060f1SDimitry Andric #define GET_RISCVVLSEGTable_IMPL 40fe6060f1SDimitry Andric #define GET_RISCVVLXSEGTable_IMPL 41fe6060f1SDimitry Andric #define GET_RISCVVSXSEGTable_IMPL 42fe6060f1SDimitry Andric #define GET_RISCVVLETable_IMPL 43fe6060f1SDimitry Andric #define GET_RISCVVSETable_IMPL 44fe6060f1SDimitry Andric #define GET_RISCVVLXTable_IMPL 45fe6060f1SDimitry Andric #define GET_RISCVVSXTable_IMPL 4681ad6265SDimitry Andric #define GET_RISCVMaskedPseudosTable_IMPL 47fe6060f1SDimitry Andric #include "RISCVGenSearchableTables.inc" 48bdd1243dSDimitry Andric } // namespace llvm::RISCV 49bdd1243dSDimitry Andric 50fe6060f1SDimitry Andric void RISCVDAGToDAGISel::PreprocessISelDAG() { 51753f127fSDimitry Andric SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); 52fe6060f1SDimitry Andric 53753f127fSDimitry Andric bool MadeChange = false; 54753f127fSDimitry Andric while (Position != CurDAG->allnodes_begin()) { 55753f127fSDimitry Andric SDNode *N = &*--Position; 56753f127fSDimitry Andric if (N->use_empty()) 57753f127fSDimitry Andric continue; 58753f127fSDimitry Andric 59753f127fSDimitry Andric SDValue Result; 60753f127fSDimitry Andric switch (N->getOpcode()) { 61753f127fSDimitry Andric case ISD::SPLAT_VECTOR: { 6281ad6265SDimitry Andric // Convert integer SPLAT_VECTOR to VMV_V_X_VL and floating-point 6381ad6265SDimitry Andric // SPLAT_VECTOR to VFMV_V_F_VL to reduce isel burden. 6481ad6265SDimitry Andric MVT VT = N->getSimpleValueType(0); 6581ad6265SDimitry Andric unsigned Opc = 6681ad6265SDimitry Andric VT.isInteger() ? RISCVISD::VMV_V_X_VL : RISCVISD::VFMV_V_F_VL; 6781ad6265SDimitry Andric SDLoc DL(N); 6881ad6265SDimitry Andric SDValue VL = CurDAG->getRegister(RISCV::X0, Subtarget->getXLenVT()); 695f757f3fSDimitry Andric SDValue Src = N->getOperand(0); 705f757f3fSDimitry Andric if (VT.isInteger()) 715f757f3fSDimitry Andric Src = CurDAG->getNode(ISD::ANY_EXTEND, DL, Subtarget->getXLenVT(), 725f757f3fSDimitry Andric N->getOperand(0)); 735f757f3fSDimitry Andric Result = CurDAG->getNode(Opc, DL, VT, CurDAG->getUNDEF(VT), Src, VL); 74753f127fSDimitry Andric break; 7581ad6265SDimitry Andric } 76753f127fSDimitry Andric case RISCVISD::SPLAT_VECTOR_SPLIT_I64_VL: { 77fe6060f1SDimitry Andric // Lower SPLAT_VECTOR_SPLIT_I64 to two scalar stores and a stride 0 vector 78fe6060f1SDimitry Andric // load. Done after lowering and combining so that we have a chance to 79fe6060f1SDimitry Andric // optimize this to VMV_V_X_VL when the upper bits aren't needed. 8081ad6265SDimitry Andric assert(N->getNumOperands() == 4 && "Unexpected number of operands"); 81fe6060f1SDimitry Andric MVT VT = N->getSimpleValueType(0); 8281ad6265SDimitry Andric SDValue Passthru = N->getOperand(0); 8381ad6265SDimitry Andric SDValue Lo = N->getOperand(1); 8481ad6265SDimitry Andric SDValue Hi = N->getOperand(2); 8581ad6265SDimitry Andric SDValue VL = N->getOperand(3); 86fe6060f1SDimitry Andric assert(VT.getVectorElementType() == MVT::i64 && VT.isScalableVector() && 87fe6060f1SDimitry Andric Lo.getValueType() == MVT::i32 && Hi.getValueType() == MVT::i32 && 88fe6060f1SDimitry Andric "Unexpected VTs!"); 89fe6060f1SDimitry Andric MachineFunction &MF = CurDAG->getMachineFunction(); 90fe6060f1SDimitry Andric SDLoc DL(N); 91fe6060f1SDimitry Andric 9206c3fb27SDimitry Andric // Create temporary stack for each expanding node. 93fe6060f1SDimitry Andric SDValue StackSlot = 945f757f3fSDimitry Andric CurDAG->CreateStackTemporary(TypeSize::getFixed(8), Align(8)); 9506c3fb27SDimitry Andric int FI = cast<FrameIndexSDNode>(StackSlot.getNode())->getIndex(); 9606c3fb27SDimitry Andric MachinePointerInfo MPI = MachinePointerInfo::getFixedStack(MF, FI); 97fe6060f1SDimitry Andric 98fe6060f1SDimitry Andric SDValue Chain = CurDAG->getEntryNode(); 99fe6060f1SDimitry Andric Lo = CurDAG->getStore(Chain, DL, Lo, StackSlot, MPI, Align(8)); 100fe6060f1SDimitry Andric 101fe6060f1SDimitry Andric SDValue OffsetSlot = 1025f757f3fSDimitry Andric CurDAG->getMemBasePlusOffset(StackSlot, TypeSize::getFixed(4), DL); 103fe6060f1SDimitry Andric Hi = CurDAG->getStore(Chain, DL, Hi, OffsetSlot, MPI.getWithOffset(4), 104fe6060f1SDimitry Andric Align(8)); 105fe6060f1SDimitry Andric 106fe6060f1SDimitry Andric Chain = CurDAG->getNode(ISD::TokenFactor, DL, MVT::Other, Lo, Hi); 107fe6060f1SDimitry Andric 108fe6060f1SDimitry Andric SDVTList VTs = CurDAG->getVTList({VT, MVT::Other}); 109fe6060f1SDimitry Andric SDValue IntID = 110fe6060f1SDimitry Andric CurDAG->getTargetConstant(Intrinsic::riscv_vlse, DL, MVT::i64); 11104eeddc0SDimitry Andric SDValue Ops[] = {Chain, 11204eeddc0SDimitry Andric IntID, 11381ad6265SDimitry Andric Passthru, 11404eeddc0SDimitry Andric StackSlot, 11504eeddc0SDimitry Andric CurDAG->getRegister(RISCV::X0, MVT::i64), 11604eeddc0SDimitry Andric VL}; 117fe6060f1SDimitry Andric 118753f127fSDimitry Andric Result = CurDAG->getMemIntrinsicNode(ISD::INTRINSIC_W_CHAIN, DL, VTs, Ops, 119753f127fSDimitry Andric MVT::i64, MPI, Align(8), 120fe6060f1SDimitry Andric MachineMemOperand::MOLoad); 121753f127fSDimitry Andric break; 122fe6060f1SDimitry Andric } 123fe6060f1SDimitry Andric } 124fe6060f1SDimitry Andric 125753f127fSDimitry Andric if (Result) { 12606c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "RISC-V DAG preprocessing replacing:\nOld: "); 127753f127fSDimitry Andric LLVM_DEBUG(N->dump(CurDAG)); 128753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "\nNew: "); 129753f127fSDimitry Andric LLVM_DEBUG(Result->dump(CurDAG)); 130753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "\n"); 131753f127fSDimitry Andric 132753f127fSDimitry Andric CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0), Result); 133753f127fSDimitry Andric MadeChange = true; 134753f127fSDimitry Andric } 135753f127fSDimitry Andric } 136753f127fSDimitry Andric 137753f127fSDimitry Andric if (MadeChange) 138753f127fSDimitry Andric CurDAG->RemoveDeadNodes(); 139753f127fSDimitry Andric } 140753f127fSDimitry Andric 1410b57cec5SDimitry Andric void RISCVDAGToDAGISel::PostprocessISelDAG() { 14281ad6265SDimitry Andric HandleSDNode Dummy(CurDAG->getRoot()); 143349cc55cSDimitry Andric SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); 144349cc55cSDimitry Andric 145349cc55cSDimitry Andric bool MadeChange = false; 146349cc55cSDimitry Andric while (Position != CurDAG->allnodes_begin()) { 147349cc55cSDimitry Andric SDNode *N = &*--Position; 148349cc55cSDimitry Andric // Skip dead nodes and any non-machine opcodes. 149349cc55cSDimitry Andric if (N->use_empty() || !N->isMachineOpcode()) 150349cc55cSDimitry Andric continue; 151349cc55cSDimitry Andric 152349cc55cSDimitry Andric MadeChange |= doPeepholeSExtW(N); 1535f757f3fSDimitry Andric 1545f757f3fSDimitry Andric // FIXME: This is here only because the VMerge transform doesn't 1555f757f3fSDimitry Andric // know how to handle masked true inputs. Once that has been moved 1565f757f3fSDimitry Andric // to post-ISEL, this can be deleted as well. 1575f757f3fSDimitry Andric MadeChange |= doPeepholeMaskedRVV(cast<MachineSDNode>(N)); 158349cc55cSDimitry Andric } 159349cc55cSDimitry Andric 16081ad6265SDimitry Andric CurDAG->setRoot(Dummy.getValue()); 16181ad6265SDimitry Andric 162bdd1243dSDimitry Andric MadeChange |= doPeepholeMergeVVMFold(); 163bdd1243dSDimitry Andric 1645f757f3fSDimitry Andric // After we're done with everything else, convert IMPLICIT_DEF 1655f757f3fSDimitry Andric // passthru operands to NoRegister. This is required to workaround 1665f757f3fSDimitry Andric // an optimization deficiency in MachineCSE. This really should 1675f757f3fSDimitry Andric // be merged back into each of the patterns (i.e. there's no good 1685f757f3fSDimitry Andric // reason not to go directly to NoReg), but is being done this way 1695f757f3fSDimitry Andric // to allow easy backporting. 1705f757f3fSDimitry Andric MadeChange |= doPeepholeNoRegPassThru(); 1715f757f3fSDimitry Andric 172349cc55cSDimitry Andric if (MadeChange) 173349cc55cSDimitry Andric CurDAG->RemoveDeadNodes(); 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 17606c3fb27SDimitry Andric static SDValue selectImmSeq(SelectionDAG *CurDAG, const SDLoc &DL, const MVT VT, 17781ad6265SDimitry Andric RISCVMatInt::InstSeq &Seq) { 17881ad6265SDimitry Andric SDValue SrcReg = CurDAG->getRegister(RISCV::X0, VT); 17906c3fb27SDimitry Andric for (const RISCVMatInt::Inst &Inst : Seq) { 180bdd1243dSDimitry Andric SDValue SDImm = CurDAG->getTargetConstant(Inst.getImm(), DL, VT); 18106c3fb27SDimitry Andric SDNode *Result = nullptr; 18281ad6265SDimitry Andric switch (Inst.getOpndKind()) { 18381ad6265SDimitry Andric case RISCVMatInt::Imm: 184bdd1243dSDimitry Andric Result = CurDAG->getMachineNode(Inst.getOpcode(), DL, VT, SDImm); 18581ad6265SDimitry Andric break; 18681ad6265SDimitry Andric case RISCVMatInt::RegX0: 187bdd1243dSDimitry Andric Result = CurDAG->getMachineNode(Inst.getOpcode(), DL, VT, SrcReg, 18881ad6265SDimitry Andric CurDAG->getRegister(RISCV::X0, VT)); 18981ad6265SDimitry Andric break; 19081ad6265SDimitry Andric case RISCVMatInt::RegReg: 191bdd1243dSDimitry Andric Result = CurDAG->getMachineNode(Inst.getOpcode(), DL, VT, SrcReg, SrcReg); 19281ad6265SDimitry Andric break; 19381ad6265SDimitry Andric case RISCVMatInt::RegImm: 194bdd1243dSDimitry Andric Result = CurDAG->getMachineNode(Inst.getOpcode(), DL, VT, SrcReg, SDImm); 19581ad6265SDimitry Andric break; 19681ad6265SDimitry Andric } 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric // Only the first instruction has X0 as its source. 1990b57cec5SDimitry Andric SrcReg = SDValue(Result, 0); 2000b57cec5SDimitry Andric } 2010b57cec5SDimitry Andric 20206c3fb27SDimitry Andric return SrcReg; 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric 20506c3fb27SDimitry Andric static SDValue selectImm(SelectionDAG *CurDAG, const SDLoc &DL, const MVT VT, 20681ad6265SDimitry Andric int64_t Imm, const RISCVSubtarget &Subtarget) { 2075f757f3fSDimitry Andric RISCVMatInt::InstSeq Seq = RISCVMatInt::generateInstSeq(Imm, Subtarget); 20881ad6265SDimitry Andric 2095f757f3fSDimitry Andric // Use a rematerializable pseudo instruction for short sequences if enabled. 2105f757f3fSDimitry Andric if (Seq.size() == 2 && UsePseudoMovImm) 2115f757f3fSDimitry Andric return SDValue( 2125f757f3fSDimitry Andric CurDAG->getMachineNode(RISCV::PseudoMovImm, DL, VT, 2135f757f3fSDimitry Andric CurDAG->getTargetConstant(Imm, DL, VT)), 2145f757f3fSDimitry Andric 0); 2155f757f3fSDimitry Andric 2165f757f3fSDimitry Andric // See if we can create this constant as (ADD (SLLI X, C), X) where X is at 21706c3fb27SDimitry Andric // worst an LUI+ADDIW. This will require an extra register, but avoids a 21806c3fb27SDimitry Andric // constant pool. 2195f757f3fSDimitry Andric // If we have Zba we can use (ADD_UW X, (SLLI X, 32)) to handle cases where 2205f757f3fSDimitry Andric // low and high 32 bits are the same and bit 31 and 63 are set. 22106c3fb27SDimitry Andric if (Seq.size() > 3) { 2225f757f3fSDimitry Andric unsigned ShiftAmt, AddOpc; 22306c3fb27SDimitry Andric RISCVMatInt::InstSeq SeqLo = 2245f757f3fSDimitry Andric RISCVMatInt::generateTwoRegInstSeq(Imm, Subtarget, ShiftAmt, AddOpc); 2255f757f3fSDimitry Andric if (!SeqLo.empty() && (SeqLo.size() + 2) < Seq.size()) { 22606c3fb27SDimitry Andric SDValue Lo = selectImmSeq(CurDAG, DL, VT, SeqLo); 22706c3fb27SDimitry Andric 22806c3fb27SDimitry Andric SDValue SLLI = SDValue( 22906c3fb27SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, Lo, 2305f757f3fSDimitry Andric CurDAG->getTargetConstant(ShiftAmt, DL, VT)), 23106c3fb27SDimitry Andric 0); 2325f757f3fSDimitry Andric return SDValue(CurDAG->getMachineNode(AddOpc, DL, VT, Lo, SLLI), 0); 23306c3fb27SDimitry Andric } 23406c3fb27SDimitry Andric } 23506c3fb27SDimitry Andric 23606c3fb27SDimitry Andric // Otherwise, use the original sequence. 23781ad6265SDimitry Andric return selectImmSeq(CurDAG, DL, VT, Seq); 23881ad6265SDimitry Andric } 23981ad6265SDimitry Andric 24081ad6265SDimitry Andric static SDValue createTuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs, 24181ad6265SDimitry Andric unsigned NF, RISCVII::VLMUL LMUL) { 24281ad6265SDimitry Andric static const unsigned M1TupleRegClassIDs[] = { 24381ad6265SDimitry Andric RISCV::VRN2M1RegClassID, RISCV::VRN3M1RegClassID, RISCV::VRN4M1RegClassID, 24481ad6265SDimitry Andric RISCV::VRN5M1RegClassID, RISCV::VRN6M1RegClassID, RISCV::VRN7M1RegClassID, 24581ad6265SDimitry Andric RISCV::VRN8M1RegClassID}; 24681ad6265SDimitry Andric static const unsigned M2TupleRegClassIDs[] = {RISCV::VRN2M2RegClassID, 24781ad6265SDimitry Andric RISCV::VRN3M2RegClassID, 24881ad6265SDimitry Andric RISCV::VRN4M2RegClassID}; 24981ad6265SDimitry Andric 250e8d8bef9SDimitry Andric assert(Regs.size() >= 2 && Regs.size() <= 8); 251e8d8bef9SDimitry Andric 25281ad6265SDimitry Andric unsigned RegClassID; 25381ad6265SDimitry Andric unsigned SubReg0; 25481ad6265SDimitry Andric switch (LMUL) { 25581ad6265SDimitry Andric default: 25681ad6265SDimitry Andric llvm_unreachable("Invalid LMUL."); 25781ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_F8: 25881ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_F4: 25981ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_F2: 26081ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_1: 26181ad6265SDimitry Andric static_assert(RISCV::sub_vrm1_7 == RISCV::sub_vrm1_0 + 7, 26281ad6265SDimitry Andric "Unexpected subreg numbering"); 26381ad6265SDimitry Andric SubReg0 = RISCV::sub_vrm1_0; 26481ad6265SDimitry Andric RegClassID = M1TupleRegClassIDs[NF - 2]; 26581ad6265SDimitry Andric break; 26681ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_2: 26781ad6265SDimitry Andric static_assert(RISCV::sub_vrm2_3 == RISCV::sub_vrm2_0 + 3, 26881ad6265SDimitry Andric "Unexpected subreg numbering"); 26981ad6265SDimitry Andric SubReg0 = RISCV::sub_vrm2_0; 27081ad6265SDimitry Andric RegClassID = M2TupleRegClassIDs[NF - 2]; 27181ad6265SDimitry Andric break; 27281ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_4: 27381ad6265SDimitry Andric static_assert(RISCV::sub_vrm4_1 == RISCV::sub_vrm4_0 + 1, 27481ad6265SDimitry Andric "Unexpected subreg numbering"); 27581ad6265SDimitry Andric SubReg0 = RISCV::sub_vrm4_0; 27681ad6265SDimitry Andric RegClassID = RISCV::VRN2M4RegClassID; 27781ad6265SDimitry Andric break; 27881ad6265SDimitry Andric } 27981ad6265SDimitry Andric 280e8d8bef9SDimitry Andric SDLoc DL(Regs[0]); 281e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Ops; 282e8d8bef9SDimitry Andric 283e8d8bef9SDimitry Andric Ops.push_back(CurDAG.getTargetConstant(RegClassID, DL, MVT::i32)); 284e8d8bef9SDimitry Andric 285e8d8bef9SDimitry Andric for (unsigned I = 0; I < Regs.size(); ++I) { 286e8d8bef9SDimitry Andric Ops.push_back(Regs[I]); 287e8d8bef9SDimitry Andric Ops.push_back(CurDAG.getTargetConstant(SubReg0 + I, DL, MVT::i32)); 288e8d8bef9SDimitry Andric } 289e8d8bef9SDimitry Andric SDNode *N = 290e8d8bef9SDimitry Andric CurDAG.getMachineNode(TargetOpcode::REG_SEQUENCE, DL, MVT::Untyped, Ops); 291e8d8bef9SDimitry Andric return SDValue(N, 0); 292e8d8bef9SDimitry Andric } 293e8d8bef9SDimitry Andric 294fe6060f1SDimitry Andric void RISCVDAGToDAGISel::addVectorLoadStoreOperands( 295fe6060f1SDimitry Andric SDNode *Node, unsigned Log2SEW, const SDLoc &DL, unsigned CurOp, 296fe6060f1SDimitry Andric bool IsMasked, bool IsStridedOrIndexed, SmallVectorImpl<SDValue> &Operands, 297349cc55cSDimitry Andric bool IsLoad, MVT *IndexVT) { 298fe6060f1SDimitry Andric SDValue Chain = Node->getOperand(0); 299fe6060f1SDimitry Andric SDValue Glue; 300fe6060f1SDimitry Andric 301753f127fSDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Base pointer. 302fe6060f1SDimitry Andric 303fe6060f1SDimitry Andric if (IsStridedOrIndexed) { 304fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Index. 305fe6060f1SDimitry Andric if (IndexVT) 306fe6060f1SDimitry Andric *IndexVT = Operands.back()->getSimpleValueType(0); 307fe6060f1SDimitry Andric } 308fe6060f1SDimitry Andric 309fe6060f1SDimitry Andric if (IsMasked) { 310fe6060f1SDimitry Andric // Mask needs to be copied to V0. 311fe6060f1SDimitry Andric SDValue Mask = Node->getOperand(CurOp++); 312fe6060f1SDimitry Andric Chain = CurDAG->getCopyToReg(Chain, DL, RISCV::V0, Mask, SDValue()); 313fe6060f1SDimitry Andric Glue = Chain.getValue(1); 314fe6060f1SDimitry Andric Operands.push_back(CurDAG->getRegister(RISCV::V0, Mask.getValueType())); 315fe6060f1SDimitry Andric } 316fe6060f1SDimitry Andric SDValue VL; 317fe6060f1SDimitry Andric selectVLOp(Node->getOperand(CurOp++), VL); 318fe6060f1SDimitry Andric Operands.push_back(VL); 319fe6060f1SDimitry Andric 320fe6060f1SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 321fe6060f1SDimitry Andric SDValue SEWOp = CurDAG->getTargetConstant(Log2SEW, DL, XLenVT); 322fe6060f1SDimitry Andric Operands.push_back(SEWOp); 323fe6060f1SDimitry Andric 32406c3fb27SDimitry Andric // At the IR layer, all the masked load intrinsics have policy operands, 32506c3fb27SDimitry Andric // none of the others do. All have passthru operands. For our pseudos, 32606c3fb27SDimitry Andric // all loads have policy operands. 32706c3fb27SDimitry Andric if (IsLoad) { 32806c3fb27SDimitry Andric uint64_t Policy = RISCVII::MASK_AGNOSTIC; 32906c3fb27SDimitry Andric if (IsMasked) 33006c3fb27SDimitry Andric Policy = Node->getConstantOperandVal(CurOp++); 331349cc55cSDimitry Andric SDValue PolicyOp = CurDAG->getTargetConstant(Policy, DL, XLenVT); 332349cc55cSDimitry Andric Operands.push_back(PolicyOp); 333349cc55cSDimitry Andric } 334349cc55cSDimitry Andric 335fe6060f1SDimitry Andric Operands.push_back(Chain); // Chain. 336fe6060f1SDimitry Andric if (Glue) 337fe6060f1SDimitry Andric Operands.push_back(Glue); 338fe6060f1SDimitry Andric } 339fe6060f1SDimitry Andric 340fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLSEG(SDNode *Node, bool IsMasked, 341e8d8bef9SDimitry Andric bool IsStrided) { 342e8d8bef9SDimitry Andric SDLoc DL(Node); 343e8d8bef9SDimitry Andric unsigned NF = Node->getNumValues() - 1; 344fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 345fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 346fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 347e8d8bef9SDimitry Andric 348fe6060f1SDimitry Andric unsigned CurOp = 2; 349fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 35081ad6265SDimitry Andric 351fe6060f1SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp, 352fe6060f1SDimitry Andric Node->op_begin() + CurOp + NF); 35381ad6265SDimitry Andric SDValue Merge = createTuple(*CurDAG, Regs, NF, LMUL); 35481ad6265SDimitry Andric Operands.push_back(Merge); 35581ad6265SDimitry Andric CurOp += NF; 356fe6060f1SDimitry Andric 357fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 358349cc55cSDimitry Andric Operands, /*IsLoad=*/true); 359fe6060f1SDimitry Andric 360fe6060f1SDimitry Andric const RISCV::VLSEGPseudo *P = 36106c3fb27SDimitry Andric RISCV::getVLSEGPseudo(NF, IsMasked, IsStrided, /*FF*/ false, Log2SEW, 362fe6060f1SDimitry Andric static_cast<unsigned>(LMUL)); 363fe6060f1SDimitry Andric MachineSDNode *Load = 364e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands); 365fe6060f1SDimitry Andric 366fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 367fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 368fe6060f1SDimitry Andric 369e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 370fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) { 371fe6060f1SDimitry Andric unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I); 372e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 373fe6060f1SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg)); 374fe6060f1SDimitry Andric } 375e8d8bef9SDimitry Andric 376e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); 377e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 378e8d8bef9SDimitry Andric } 379e8d8bef9SDimitry Andric 380fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLSEGFF(SDNode *Node, bool IsMasked) { 381e8d8bef9SDimitry Andric SDLoc DL(Node); 382fe6060f1SDimitry Andric unsigned NF = Node->getNumValues() - 2; // Do not count VL and Chain. 383fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 384e8d8bef9SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 385fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 386fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 387e8d8bef9SDimitry Andric 388fe6060f1SDimitry Andric unsigned CurOp = 2; 389e8d8bef9SDimitry Andric SmallVector<SDValue, 7> Operands; 39081ad6265SDimitry Andric 391fe6060f1SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp, 392fe6060f1SDimitry Andric Node->op_begin() + CurOp + NF); 393e8d8bef9SDimitry Andric SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL); 394fe6060f1SDimitry Andric Operands.push_back(MaskedOff); 39581ad6265SDimitry Andric CurOp += NF; 396e8d8bef9SDimitry Andric 397fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 398349cc55cSDimitry Andric /*IsStridedOrIndexed*/ false, Operands, 399349cc55cSDimitry Andric /*IsLoad=*/true); 400fe6060f1SDimitry Andric 401fe6060f1SDimitry Andric const RISCV::VLSEGPseudo *P = 40206c3fb27SDimitry Andric RISCV::getVLSEGPseudo(NF, IsMasked, /*Strided*/ false, /*FF*/ true, 403fe6060f1SDimitry Andric Log2SEW, static_cast<unsigned>(LMUL)); 404fe6060f1SDimitry Andric MachineSDNode *Load = CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, 40581ad6265SDimitry Andric XLenVT, MVT::Other, Operands); 406fe6060f1SDimitry Andric 407fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 408fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 409fe6060f1SDimitry Andric 410e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 411fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) { 412fe6060f1SDimitry Andric unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I); 413e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 414fe6060f1SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg)); 415fe6060f1SDimitry Andric } 416fe6060f1SDimitry Andric 41781ad6265SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); // VL 41881ad6265SDimitry Andric ReplaceUses(SDValue(Node, NF + 1), SDValue(Load, 2)); // Chain 419fe6060f1SDimitry Andric CurDAG->RemoveDeadNode(Node); 420fe6060f1SDimitry Andric } 421fe6060f1SDimitry Andric 422fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLXSEG(SDNode *Node, bool IsMasked, 423fe6060f1SDimitry Andric bool IsOrdered) { 424fe6060f1SDimitry Andric SDLoc DL(Node); 425fe6060f1SDimitry Andric unsigned NF = Node->getNumValues() - 1; 426fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 427fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 428fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 429fe6060f1SDimitry Andric 430fe6060f1SDimitry Andric unsigned CurOp = 2; 431fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 43281ad6265SDimitry Andric 433fe6060f1SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp, 434fe6060f1SDimitry Andric Node->op_begin() + CurOp + NF); 435fe6060f1SDimitry Andric SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL); 436fe6060f1SDimitry Andric Operands.push_back(MaskedOff); 43781ad6265SDimitry Andric CurOp += NF; 438fe6060f1SDimitry Andric 439fe6060f1SDimitry Andric MVT IndexVT; 440fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 441349cc55cSDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 442349cc55cSDimitry Andric /*IsLoad=*/true, &IndexVT); 443fe6060f1SDimitry Andric 444fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 445fe6060f1SDimitry Andric "Element count mismatch"); 446fe6060f1SDimitry Andric 447fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 448fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 44904eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 45004eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 45104eeddc0SDimitry Andric "values when XLEN=32"); 45204eeddc0SDimitry Andric } 453fe6060f1SDimitry Andric const RISCV::VLXSEGPseudo *P = RISCV::getVLXSEGPseudo( 45406c3fb27SDimitry Andric NF, IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 455fe6060f1SDimitry Andric static_cast<unsigned>(IndexLMUL)); 456fe6060f1SDimitry Andric MachineSDNode *Load = 457fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands); 458fe6060f1SDimitry Andric 459fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 460fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 461fe6060f1SDimitry Andric 462fe6060f1SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 463fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) { 464fe6060f1SDimitry Andric unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I); 465fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, I), 466fe6060f1SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg)); 467fe6060f1SDimitry Andric } 468e8d8bef9SDimitry Andric 469e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); 470e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 471e8d8bef9SDimitry Andric } 472e8d8bef9SDimitry Andric 473fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVSSEG(SDNode *Node, bool IsMasked, 474e8d8bef9SDimitry Andric bool IsStrided) { 475e8d8bef9SDimitry Andric SDLoc DL(Node); 476e8d8bef9SDimitry Andric unsigned NF = Node->getNumOperands() - 4; 477e8d8bef9SDimitry Andric if (IsStrided) 478e8d8bef9SDimitry Andric NF--; 479fe6060f1SDimitry Andric if (IsMasked) 480e8d8bef9SDimitry Andric NF--; 481fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 482fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 483fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 484e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 485e8d8bef9SDimitry Andric SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL); 486fe6060f1SDimitry Andric 487fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 488e8d8bef9SDimitry Andric Operands.push_back(StoreVal); 489fe6060f1SDimitry Andric unsigned CurOp = 2 + NF; 490fe6060f1SDimitry Andric 491fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 492fe6060f1SDimitry Andric Operands); 493fe6060f1SDimitry Andric 494fe6060f1SDimitry Andric const RISCV::VSSEGPseudo *P = RISCV::getVSSEGPseudo( 495fe6060f1SDimitry Andric NF, IsMasked, IsStrided, Log2SEW, static_cast<unsigned>(LMUL)); 496fe6060f1SDimitry Andric MachineSDNode *Store = 497e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands); 498fe6060f1SDimitry Andric 499fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 500fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 501fe6060f1SDimitry Andric 502e8d8bef9SDimitry Andric ReplaceNode(Node, Store); 503e8d8bef9SDimitry Andric } 504e8d8bef9SDimitry Andric 505fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVSXSEG(SDNode *Node, bool IsMasked, 506fe6060f1SDimitry Andric bool IsOrdered) { 507e8d8bef9SDimitry Andric SDLoc DL(Node); 508e8d8bef9SDimitry Andric unsigned NF = Node->getNumOperands() - 5; 509fe6060f1SDimitry Andric if (IsMasked) 510fe6060f1SDimitry Andric --NF; 511fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 512fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 513fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 514e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 515e8d8bef9SDimitry Andric SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL); 516e8d8bef9SDimitry Andric 517fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 518fe6060f1SDimitry Andric Operands.push_back(StoreVal); 519fe6060f1SDimitry Andric unsigned CurOp = 2 + NF; 520fe6060f1SDimitry Andric 521fe6060f1SDimitry Andric MVT IndexVT; 522fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 523349cc55cSDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 524349cc55cSDimitry Andric /*IsLoad=*/false, &IndexVT); 525fe6060f1SDimitry Andric 526fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 527fe6060f1SDimitry Andric "Element count mismatch"); 528fe6060f1SDimitry Andric 529fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 530fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 53104eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 53204eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 53304eeddc0SDimitry Andric "values when XLEN=32"); 53404eeddc0SDimitry Andric } 535fe6060f1SDimitry Andric const RISCV::VSXSEGPseudo *P = RISCV::getVSXSEGPseudo( 536fe6060f1SDimitry Andric NF, IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 537e8d8bef9SDimitry Andric static_cast<unsigned>(IndexLMUL)); 538fe6060f1SDimitry Andric MachineSDNode *Store = 539e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands); 540fe6060f1SDimitry Andric 541fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 542fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 543fe6060f1SDimitry Andric 544e8d8bef9SDimitry Andric ReplaceNode(Node, Store); 545e8d8bef9SDimitry Andric } 546e8d8bef9SDimitry Andric 54704eeddc0SDimitry Andric void RISCVDAGToDAGISel::selectVSETVLI(SDNode *Node) { 54804eeddc0SDimitry Andric if (!Subtarget->hasVInstructions()) 54904eeddc0SDimitry Andric return; 55004eeddc0SDimitry Andric 55106c3fb27SDimitry Andric assert(Node->getOpcode() == ISD::INTRINSIC_WO_CHAIN && "Unexpected opcode"); 55204eeddc0SDimitry Andric 55304eeddc0SDimitry Andric SDLoc DL(Node); 55404eeddc0SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 55504eeddc0SDimitry Andric 55606c3fb27SDimitry Andric unsigned IntNo = Node->getConstantOperandVal(0); 55704eeddc0SDimitry Andric 55804eeddc0SDimitry Andric assert((IntNo == Intrinsic::riscv_vsetvli || 55906c3fb27SDimitry Andric IntNo == Intrinsic::riscv_vsetvlimax) && 56004eeddc0SDimitry Andric "Unexpected vsetvli intrinsic"); 56104eeddc0SDimitry Andric 56206c3fb27SDimitry Andric bool VLMax = IntNo == Intrinsic::riscv_vsetvlimax; 56306c3fb27SDimitry Andric unsigned Offset = (VLMax ? 1 : 2); 56404eeddc0SDimitry Andric 56504eeddc0SDimitry Andric assert(Node->getNumOperands() == Offset + 2 && 56604eeddc0SDimitry Andric "Unexpected number of operands"); 56704eeddc0SDimitry Andric 56804eeddc0SDimitry Andric unsigned SEW = 56904eeddc0SDimitry Andric RISCVVType::decodeVSEW(Node->getConstantOperandVal(Offset) & 0x7); 57004eeddc0SDimitry Andric RISCVII::VLMUL VLMul = static_cast<RISCVII::VLMUL>( 57104eeddc0SDimitry Andric Node->getConstantOperandVal(Offset + 1) & 0x7); 57204eeddc0SDimitry Andric 57304eeddc0SDimitry Andric unsigned VTypeI = RISCVVType::encodeVTYPE(VLMul, SEW, /*TailAgnostic*/ true, 57406c3fb27SDimitry Andric /*MaskAgnostic*/ true); 57504eeddc0SDimitry Andric SDValue VTypeIOp = CurDAG->getTargetConstant(VTypeI, DL, XLenVT); 57604eeddc0SDimitry Andric 57704eeddc0SDimitry Andric SDValue VLOperand; 57804eeddc0SDimitry Andric unsigned Opcode = RISCV::PseudoVSETVLI; 5795f757f3fSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Node->getOperand(1))) { 5805f757f3fSDimitry Andric const unsigned VLEN = Subtarget->getRealMinVLen(); 5815f757f3fSDimitry Andric if (VLEN == Subtarget->getRealMaxVLen()) 5825f757f3fSDimitry Andric if (VLEN / RISCVVType::getSEWLMULRatio(SEW, VLMul) == C->getZExtValue()) 5835f757f3fSDimitry Andric VLMax = true; 5845f757f3fSDimitry Andric } 58506c3fb27SDimitry Andric if (VLMax || isAllOnesConstant(Node->getOperand(1))) { 58604eeddc0SDimitry Andric VLOperand = CurDAG->getRegister(RISCV::X0, XLenVT); 58704eeddc0SDimitry Andric Opcode = RISCV::PseudoVSETVLIX0; 58804eeddc0SDimitry Andric } else { 58906c3fb27SDimitry Andric VLOperand = Node->getOperand(1); 59004eeddc0SDimitry Andric 59104eeddc0SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(VLOperand)) { 59204eeddc0SDimitry Andric uint64_t AVL = C->getZExtValue(); 59304eeddc0SDimitry Andric if (isUInt<5>(AVL)) { 59404eeddc0SDimitry Andric SDValue VLImm = CurDAG->getTargetConstant(AVL, DL, XLenVT); 59506c3fb27SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(RISCV::PseudoVSETIVLI, DL, 59606c3fb27SDimitry Andric XLenVT, VLImm, VTypeIOp)); 59704eeddc0SDimitry Andric return; 59804eeddc0SDimitry Andric } 59904eeddc0SDimitry Andric } 60004eeddc0SDimitry Andric } 60104eeddc0SDimitry Andric 60206c3fb27SDimitry Andric ReplaceNode(Node, 60306c3fb27SDimitry Andric CurDAG->getMachineNode(Opcode, DL, XLenVT, VLOperand, VTypeIOp)); 60404eeddc0SDimitry Andric } 6050b57cec5SDimitry Andric 606bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::tryShrinkShlLogicImm(SDNode *Node) { 607bdd1243dSDimitry Andric MVT VT = Node->getSimpleValueType(0); 608bdd1243dSDimitry Andric unsigned Opcode = Node->getOpcode(); 609bdd1243dSDimitry Andric assert((Opcode == ISD::AND || Opcode == ISD::OR || Opcode == ISD::XOR) && 610bdd1243dSDimitry Andric "Unexpected opcode"); 611bdd1243dSDimitry Andric SDLoc DL(Node); 612bdd1243dSDimitry Andric 613bdd1243dSDimitry Andric // For operations of the form (x << C1) op C2, check if we can use 614bdd1243dSDimitry Andric // ANDI/ORI/XORI by transforming it into (x op (C2>>C1)) << C1. 615bdd1243dSDimitry Andric SDValue N0 = Node->getOperand(0); 616bdd1243dSDimitry Andric SDValue N1 = Node->getOperand(1); 617bdd1243dSDimitry Andric 618bdd1243dSDimitry Andric ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(N1); 619bdd1243dSDimitry Andric if (!Cst) 620bdd1243dSDimitry Andric return false; 621bdd1243dSDimitry Andric 622bdd1243dSDimitry Andric int64_t Val = Cst->getSExtValue(); 623bdd1243dSDimitry Andric 624bdd1243dSDimitry Andric // Check if immediate can already use ANDI/ORI/XORI. 625bdd1243dSDimitry Andric if (isInt<12>(Val)) 626bdd1243dSDimitry Andric return false; 627bdd1243dSDimitry Andric 628bdd1243dSDimitry Andric SDValue Shift = N0; 629bdd1243dSDimitry Andric 630bdd1243dSDimitry Andric // If Val is simm32 and we have a sext_inreg from i32, then the binop 631bdd1243dSDimitry Andric // produces at least 33 sign bits. We can peek through the sext_inreg and use 632bdd1243dSDimitry Andric // a SLLIW at the end. 633bdd1243dSDimitry Andric bool SignExt = false; 634bdd1243dSDimitry Andric if (isInt<32>(Val) && N0.getOpcode() == ISD::SIGN_EXTEND_INREG && 635bdd1243dSDimitry Andric N0.hasOneUse() && cast<VTSDNode>(N0.getOperand(1))->getVT() == MVT::i32) { 636bdd1243dSDimitry Andric SignExt = true; 637bdd1243dSDimitry Andric Shift = N0.getOperand(0); 638bdd1243dSDimitry Andric } 639bdd1243dSDimitry Andric 640bdd1243dSDimitry Andric if (Shift.getOpcode() != ISD::SHL || !Shift.hasOneUse()) 641bdd1243dSDimitry Andric return false; 642bdd1243dSDimitry Andric 643bdd1243dSDimitry Andric ConstantSDNode *ShlCst = dyn_cast<ConstantSDNode>(Shift.getOperand(1)); 644bdd1243dSDimitry Andric if (!ShlCst) 645bdd1243dSDimitry Andric return false; 646bdd1243dSDimitry Andric 647bdd1243dSDimitry Andric uint64_t ShAmt = ShlCst->getZExtValue(); 648bdd1243dSDimitry Andric 649bdd1243dSDimitry Andric // Make sure that we don't change the operation by removing bits. 650bdd1243dSDimitry Andric // This only matters for OR and XOR, AND is unaffected. 651bdd1243dSDimitry Andric uint64_t RemovedBitsMask = maskTrailingOnes<uint64_t>(ShAmt); 652bdd1243dSDimitry Andric if (Opcode != ISD::AND && (Val & RemovedBitsMask) != 0) 653bdd1243dSDimitry Andric return false; 654bdd1243dSDimitry Andric 655bdd1243dSDimitry Andric int64_t ShiftedVal = Val >> ShAmt; 656bdd1243dSDimitry Andric if (!isInt<12>(ShiftedVal)) 657bdd1243dSDimitry Andric return false; 658bdd1243dSDimitry Andric 659bdd1243dSDimitry Andric // If we peeked through a sext_inreg, make sure the shift is valid for SLLIW. 660bdd1243dSDimitry Andric if (SignExt && ShAmt >= 32) 661bdd1243dSDimitry Andric return false; 662bdd1243dSDimitry Andric 663bdd1243dSDimitry Andric // Ok, we can reorder to get a smaller immediate. 664bdd1243dSDimitry Andric unsigned BinOpc; 665bdd1243dSDimitry Andric switch (Opcode) { 666bdd1243dSDimitry Andric default: llvm_unreachable("Unexpected opcode"); 667bdd1243dSDimitry Andric case ISD::AND: BinOpc = RISCV::ANDI; break; 668bdd1243dSDimitry Andric case ISD::OR: BinOpc = RISCV::ORI; break; 669bdd1243dSDimitry Andric case ISD::XOR: BinOpc = RISCV::XORI; break; 670bdd1243dSDimitry Andric } 671bdd1243dSDimitry Andric 672bdd1243dSDimitry Andric unsigned ShOpc = SignExt ? RISCV::SLLIW : RISCV::SLLI; 673bdd1243dSDimitry Andric 674bdd1243dSDimitry Andric SDNode *BinOp = 675bdd1243dSDimitry Andric CurDAG->getMachineNode(BinOpc, DL, VT, Shift.getOperand(0), 676bdd1243dSDimitry Andric CurDAG->getTargetConstant(ShiftedVal, DL, VT)); 677bdd1243dSDimitry Andric SDNode *SLLI = 678bdd1243dSDimitry Andric CurDAG->getMachineNode(ShOpc, DL, VT, SDValue(BinOp, 0), 679bdd1243dSDimitry Andric CurDAG->getTargetConstant(ShAmt, DL, VT)); 680bdd1243dSDimitry Andric ReplaceNode(Node, SLLI); 681bdd1243dSDimitry Andric return true; 682bdd1243dSDimitry Andric } 683bdd1243dSDimitry Andric 68406c3fb27SDimitry Andric bool RISCVDAGToDAGISel::trySignedBitfieldExtract(SDNode *Node) { 68506c3fb27SDimitry Andric // Only supported with XTHeadBb at the moment. 68606c3fb27SDimitry Andric if (!Subtarget->hasVendorXTHeadBb()) 68706c3fb27SDimitry Andric return false; 68806c3fb27SDimitry Andric 68906c3fb27SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 69006c3fb27SDimitry Andric if (!N1C) 69106c3fb27SDimitry Andric return false; 69206c3fb27SDimitry Andric 69306c3fb27SDimitry Andric SDValue N0 = Node->getOperand(0); 69406c3fb27SDimitry Andric if (!N0.hasOneUse()) 69506c3fb27SDimitry Andric return false; 69606c3fb27SDimitry Andric 69706c3fb27SDimitry Andric auto BitfieldExtract = [&](SDValue N0, unsigned Msb, unsigned Lsb, SDLoc DL, 69806c3fb27SDimitry Andric MVT VT) { 69906c3fb27SDimitry Andric return CurDAG->getMachineNode(RISCV::TH_EXT, DL, VT, N0.getOperand(0), 70006c3fb27SDimitry Andric CurDAG->getTargetConstant(Msb, DL, VT), 70106c3fb27SDimitry Andric CurDAG->getTargetConstant(Lsb, DL, VT)); 70206c3fb27SDimitry Andric }; 70306c3fb27SDimitry Andric 70406c3fb27SDimitry Andric SDLoc DL(Node); 70506c3fb27SDimitry Andric MVT VT = Node->getSimpleValueType(0); 70606c3fb27SDimitry Andric const unsigned RightShAmt = N1C->getZExtValue(); 70706c3fb27SDimitry Andric 70806c3fb27SDimitry Andric // Transform (sra (shl X, C1) C2) with C1 < C2 70906c3fb27SDimitry Andric // -> (TH.EXT X, msb, lsb) 71006c3fb27SDimitry Andric if (N0.getOpcode() == ISD::SHL) { 71106c3fb27SDimitry Andric auto *N01C = dyn_cast<ConstantSDNode>(N0->getOperand(1)); 71206c3fb27SDimitry Andric if (!N01C) 71306c3fb27SDimitry Andric return false; 71406c3fb27SDimitry Andric 71506c3fb27SDimitry Andric const unsigned LeftShAmt = N01C->getZExtValue(); 71606c3fb27SDimitry Andric // Make sure that this is a bitfield extraction (i.e., the shift-right 71706c3fb27SDimitry Andric // amount can not be less than the left-shift). 71806c3fb27SDimitry Andric if (LeftShAmt > RightShAmt) 71906c3fb27SDimitry Andric return false; 72006c3fb27SDimitry Andric 72106c3fb27SDimitry Andric const unsigned MsbPlusOne = VT.getSizeInBits() - LeftShAmt; 72206c3fb27SDimitry Andric const unsigned Msb = MsbPlusOne - 1; 72306c3fb27SDimitry Andric const unsigned Lsb = RightShAmt - LeftShAmt; 72406c3fb27SDimitry Andric 72506c3fb27SDimitry Andric SDNode *TH_EXT = BitfieldExtract(N0, Msb, Lsb, DL, VT); 72606c3fb27SDimitry Andric ReplaceNode(Node, TH_EXT); 72706c3fb27SDimitry Andric return true; 72806c3fb27SDimitry Andric } 72906c3fb27SDimitry Andric 73006c3fb27SDimitry Andric // Transform (sra (sext_inreg X, _), C) -> 73106c3fb27SDimitry Andric // (TH.EXT X, msb, lsb) 73206c3fb27SDimitry Andric if (N0.getOpcode() == ISD::SIGN_EXTEND_INREG) { 73306c3fb27SDimitry Andric unsigned ExtSize = 73406c3fb27SDimitry Andric cast<VTSDNode>(N0.getOperand(1))->getVT().getSizeInBits(); 73506c3fb27SDimitry Andric 73606c3fb27SDimitry Andric // ExtSize of 32 should use sraiw via tablegen pattern. 73706c3fb27SDimitry Andric if (ExtSize == 32) 73806c3fb27SDimitry Andric return false; 73906c3fb27SDimitry Andric 74006c3fb27SDimitry Andric const unsigned Msb = ExtSize - 1; 74106c3fb27SDimitry Andric const unsigned Lsb = RightShAmt; 74206c3fb27SDimitry Andric 74306c3fb27SDimitry Andric SDNode *TH_EXT = BitfieldExtract(N0, Msb, Lsb, DL, VT); 74406c3fb27SDimitry Andric ReplaceNode(Node, TH_EXT); 74506c3fb27SDimitry Andric return true; 74606c3fb27SDimitry Andric } 74706c3fb27SDimitry Andric 74806c3fb27SDimitry Andric return false; 74906c3fb27SDimitry Andric } 75006c3fb27SDimitry Andric 75106c3fb27SDimitry Andric bool RISCVDAGToDAGISel::tryIndexedLoad(SDNode *Node) { 75206c3fb27SDimitry Andric // Target does not support indexed loads. 75306c3fb27SDimitry Andric if (!Subtarget->hasVendorXTHeadMemIdx()) 75406c3fb27SDimitry Andric return false; 75506c3fb27SDimitry Andric 75606c3fb27SDimitry Andric LoadSDNode *Ld = cast<LoadSDNode>(Node); 75706c3fb27SDimitry Andric ISD::MemIndexedMode AM = Ld->getAddressingMode(); 75806c3fb27SDimitry Andric if (AM == ISD::UNINDEXED) 75906c3fb27SDimitry Andric return false; 76006c3fb27SDimitry Andric 76106c3fb27SDimitry Andric const ConstantSDNode *C = dyn_cast<ConstantSDNode>(Ld->getOffset()); 76206c3fb27SDimitry Andric if (!C) 76306c3fb27SDimitry Andric return false; 76406c3fb27SDimitry Andric 76506c3fb27SDimitry Andric EVT LoadVT = Ld->getMemoryVT(); 76606c3fb27SDimitry Andric bool IsPre = (AM == ISD::PRE_INC || AM == ISD::PRE_DEC); 76706c3fb27SDimitry Andric bool IsPost = (AM == ISD::POST_INC || AM == ISD::POST_DEC); 76806c3fb27SDimitry Andric int64_t Offset = C->getSExtValue(); 76906c3fb27SDimitry Andric 77006c3fb27SDimitry Andric // Convert decrements to increments by a negative quantity. 77106c3fb27SDimitry Andric if (AM == ISD::PRE_DEC || AM == ISD::POST_DEC) 77206c3fb27SDimitry Andric Offset = -Offset; 77306c3fb27SDimitry Andric 77406c3fb27SDimitry Andric // The constants that can be encoded in the THeadMemIdx instructions 77506c3fb27SDimitry Andric // are of the form (sign_extend(imm5) << imm2). 77606c3fb27SDimitry Andric int64_t Shift; 77706c3fb27SDimitry Andric for (Shift = 0; Shift < 4; Shift++) 77806c3fb27SDimitry Andric if (isInt<5>(Offset >> Shift) && ((Offset % (1LL << Shift)) == 0)) 77906c3fb27SDimitry Andric break; 78006c3fb27SDimitry Andric 78106c3fb27SDimitry Andric // Constant cannot be encoded. 78206c3fb27SDimitry Andric if (Shift == 4) 78306c3fb27SDimitry Andric return false; 78406c3fb27SDimitry Andric 78506c3fb27SDimitry Andric bool IsZExt = (Ld->getExtensionType() == ISD::ZEXTLOAD); 78606c3fb27SDimitry Andric unsigned Opcode; 78706c3fb27SDimitry Andric if (LoadVT == MVT::i8 && IsPre) 78806c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LBUIB : RISCV::TH_LBIB; 78906c3fb27SDimitry Andric else if (LoadVT == MVT::i8 && IsPost) 79006c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LBUIA : RISCV::TH_LBIA; 79106c3fb27SDimitry Andric else if (LoadVT == MVT::i16 && IsPre) 79206c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LHUIB : RISCV::TH_LHIB; 79306c3fb27SDimitry Andric else if (LoadVT == MVT::i16 && IsPost) 79406c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LHUIA : RISCV::TH_LHIA; 79506c3fb27SDimitry Andric else if (LoadVT == MVT::i32 && IsPre) 79606c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LWUIB : RISCV::TH_LWIB; 79706c3fb27SDimitry Andric else if (LoadVT == MVT::i32 && IsPost) 79806c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LWUIA : RISCV::TH_LWIA; 79906c3fb27SDimitry Andric else if (LoadVT == MVT::i64 && IsPre) 80006c3fb27SDimitry Andric Opcode = RISCV::TH_LDIB; 80106c3fb27SDimitry Andric else if (LoadVT == MVT::i64 && IsPost) 80206c3fb27SDimitry Andric Opcode = RISCV::TH_LDIA; 80306c3fb27SDimitry Andric else 80406c3fb27SDimitry Andric return false; 80506c3fb27SDimitry Andric 80606c3fb27SDimitry Andric EVT Ty = Ld->getOffset().getValueType(); 80706c3fb27SDimitry Andric SDValue Ops[] = {Ld->getBasePtr(), 80806c3fb27SDimitry Andric CurDAG->getTargetConstant(Offset >> Shift, SDLoc(Node), Ty), 80906c3fb27SDimitry Andric CurDAG->getTargetConstant(Shift, SDLoc(Node), Ty), 81006c3fb27SDimitry Andric Ld->getChain()}; 81106c3fb27SDimitry Andric SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(Node), Ld->getValueType(0), 81206c3fb27SDimitry Andric Ld->getValueType(1), MVT::Other, Ops); 81306c3fb27SDimitry Andric 81406c3fb27SDimitry Andric MachineMemOperand *MemOp = cast<MemSDNode>(Node)->getMemOperand(); 81506c3fb27SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(New), {MemOp}); 81606c3fb27SDimitry Andric 81706c3fb27SDimitry Andric ReplaceNode(Node, New); 81806c3fb27SDimitry Andric 81906c3fb27SDimitry Andric return true; 82006c3fb27SDimitry Andric } 82106c3fb27SDimitry Andric 8220b57cec5SDimitry Andric void RISCVDAGToDAGISel::Select(SDNode *Node) { 8230b57cec5SDimitry Andric // If we have a custom node, we have already selected. 8240b57cec5SDimitry Andric if (Node->isMachineOpcode()) { 8250b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n"); 8260b57cec5SDimitry Andric Node->setNodeId(-1); 8270b57cec5SDimitry Andric return; 8280b57cec5SDimitry Andric } 8290b57cec5SDimitry Andric 8300b57cec5SDimitry Andric // Instruction Selection not handled by the auto-generated tablegen selection 8310b57cec5SDimitry Andric // should be handled here. 8320b57cec5SDimitry Andric unsigned Opcode = Node->getOpcode(); 8330b57cec5SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 8340b57cec5SDimitry Andric SDLoc DL(Node); 835fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 8360b57cec5SDimitry Andric 83706c3fb27SDimitry Andric bool HasBitTest = Subtarget->hasStdExtZbs() || Subtarget->hasVendorXTHeadBs(); 83806c3fb27SDimitry Andric 8390b57cec5SDimitry Andric switch (Opcode) { 8400b57cec5SDimitry Andric case ISD::Constant: { 8415f757f3fSDimitry Andric assert((VT == Subtarget->getXLenVT() || VT == MVT::i32) && "Unexpected VT"); 842fe6060f1SDimitry Andric auto *ConstNode = cast<ConstantSDNode>(Node); 84306c3fb27SDimitry Andric if (ConstNode->isZero()) { 844e8d8bef9SDimitry Andric SDValue New = 84506c3fb27SDimitry Andric CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, RISCV::X0, VT); 8460b57cec5SDimitry Andric ReplaceNode(Node, New.getNode()); 8470b57cec5SDimitry Andric return; 8480b57cec5SDimitry Andric } 849349cc55cSDimitry Andric int64_t Imm = ConstNode->getSExtValue(); 850349cc55cSDimitry Andric // If the upper XLen-16 bits are not used, try to convert this to a simm12 851349cc55cSDimitry Andric // by sign extending bit 15. 85281ad6265SDimitry Andric if (isUInt<16>(Imm) && isInt<12>(SignExtend64<16>(Imm)) && 853349cc55cSDimitry Andric hasAllHUsers(Node)) 85481ad6265SDimitry Andric Imm = SignExtend64<16>(Imm); 855349cc55cSDimitry Andric // If the upper 32-bits are not used try to convert this into a simm32 by 856349cc55cSDimitry Andric // sign extending bit 32. 857349cc55cSDimitry Andric if (!isInt<32>(Imm) && isUInt<32>(Imm) && hasAllWUsers(Node)) 85881ad6265SDimitry Andric Imm = SignExtend64<32>(Imm); 859349cc55cSDimitry Andric 86006c3fb27SDimitry Andric ReplaceNode(Node, selectImm(CurDAG, DL, VT, Imm, *Subtarget).getNode()); 86106c3fb27SDimitry Andric return; 86206c3fb27SDimitry Andric } 86306c3fb27SDimitry Andric case ISD::ConstantFP: { 86406c3fb27SDimitry Andric const APFloat &APF = cast<ConstantFPSDNode>(Node)->getValueAPF(); 8655f757f3fSDimitry Andric auto [FPImm, NeedsFNeg] = 8665f757f3fSDimitry Andric static_cast<const RISCVTargetLowering *>(TLI)->getLegalZfaFPImm(APF, 8675f757f3fSDimitry Andric VT); 86806c3fb27SDimitry Andric if (FPImm >= 0) { 86906c3fb27SDimitry Andric unsigned Opc; 8705f757f3fSDimitry Andric unsigned FNegOpc; 87106c3fb27SDimitry Andric switch (VT.SimpleTy) { 87206c3fb27SDimitry Andric default: 87306c3fb27SDimitry Andric llvm_unreachable("Unexpected size"); 87406c3fb27SDimitry Andric case MVT::f16: 87506c3fb27SDimitry Andric Opc = RISCV::FLI_H; 8765f757f3fSDimitry Andric FNegOpc = RISCV::FSGNJN_H; 87706c3fb27SDimitry Andric break; 87806c3fb27SDimitry Andric case MVT::f32: 87906c3fb27SDimitry Andric Opc = RISCV::FLI_S; 8805f757f3fSDimitry Andric FNegOpc = RISCV::FSGNJN_S; 88106c3fb27SDimitry Andric break; 88206c3fb27SDimitry Andric case MVT::f64: 88306c3fb27SDimitry Andric Opc = RISCV::FLI_D; 8845f757f3fSDimitry Andric FNegOpc = RISCV::FSGNJN_D; 88506c3fb27SDimitry Andric break; 88606c3fb27SDimitry Andric } 88706c3fb27SDimitry Andric SDNode *Res = CurDAG->getMachineNode( 88806c3fb27SDimitry Andric Opc, DL, VT, CurDAG->getTargetConstant(FPImm, DL, XLenVT)); 8895f757f3fSDimitry Andric if (NeedsFNeg) 8905f757f3fSDimitry Andric Res = CurDAG->getMachineNode(FNegOpc, DL, VT, SDValue(Res, 0), 8915f757f3fSDimitry Andric SDValue(Res, 0)); 8925f757f3fSDimitry Andric 89306c3fb27SDimitry Andric ReplaceNode(Node, Res); 89406c3fb27SDimitry Andric return; 89506c3fb27SDimitry Andric } 89606c3fb27SDimitry Andric 89706c3fb27SDimitry Andric bool NegZeroF64 = APF.isNegZero() && VT == MVT::f64; 89806c3fb27SDimitry Andric SDValue Imm; 89906c3fb27SDimitry Andric // For +0.0 or f64 -0.0 we need to start from X0. For all others, we will 90006c3fb27SDimitry Andric // create an integer immediate. 90106c3fb27SDimitry Andric if (APF.isPosZero() || NegZeroF64) 90206c3fb27SDimitry Andric Imm = CurDAG->getRegister(RISCV::X0, XLenVT); 90306c3fb27SDimitry Andric else 90406c3fb27SDimitry Andric Imm = selectImm(CurDAG, DL, XLenVT, APF.bitcastToAPInt().getSExtValue(), 90506c3fb27SDimitry Andric *Subtarget); 90606c3fb27SDimitry Andric 9075f757f3fSDimitry Andric bool HasZdinx = Subtarget->hasStdExtZdinx(); 9085f757f3fSDimitry Andric bool Is64Bit = Subtarget->is64Bit(); 90906c3fb27SDimitry Andric unsigned Opc; 91006c3fb27SDimitry Andric switch (VT.SimpleTy) { 91106c3fb27SDimitry Andric default: 91206c3fb27SDimitry Andric llvm_unreachable("Unexpected size"); 9135f757f3fSDimitry Andric case MVT::bf16: 9145f757f3fSDimitry Andric assert(Subtarget->hasStdExtZfbfmin()); 9155f757f3fSDimitry Andric Opc = RISCV::FMV_H_X; 9165f757f3fSDimitry Andric break; 91706c3fb27SDimitry Andric case MVT::f16: 918*cb14a3feSDimitry Andric Opc = Subtarget->hasStdExtZhinxmin() ? RISCV::COPY : RISCV::FMV_H_X; 91906c3fb27SDimitry Andric break; 92006c3fb27SDimitry Andric case MVT::f32: 92106c3fb27SDimitry Andric Opc = Subtarget->hasStdExtZfinx() ? RISCV::COPY : RISCV::FMV_W_X; 92206c3fb27SDimitry Andric break; 92306c3fb27SDimitry Andric case MVT::f64: 92406c3fb27SDimitry Andric // For RV32, we can't move from a GPR, we need to convert instead. This 92506c3fb27SDimitry Andric // should only happen for +0.0 and -0.0. 92606c3fb27SDimitry Andric assert((Subtarget->is64Bit() || APF.isZero()) && "Unexpected constant"); 9275f757f3fSDimitry Andric if (Is64Bit) 92806c3fb27SDimitry Andric Opc = HasZdinx ? RISCV::COPY : RISCV::FMV_D_X; 92906c3fb27SDimitry Andric else 93006c3fb27SDimitry Andric Opc = HasZdinx ? RISCV::FCVT_D_W_IN32X : RISCV::FCVT_D_W; 93106c3fb27SDimitry Andric break; 93206c3fb27SDimitry Andric } 93306c3fb27SDimitry Andric 9345f757f3fSDimitry Andric SDNode *Res; 9355f757f3fSDimitry Andric if (Opc == RISCV::FCVT_D_W_IN32X || Opc == RISCV::FCVT_D_W) 9365f757f3fSDimitry Andric Res = CurDAG->getMachineNode( 9375f757f3fSDimitry Andric Opc, DL, VT, Imm, 9385f757f3fSDimitry Andric CurDAG->getTargetConstant(RISCVFPRndMode::RNE, DL, XLenVT)); 9395f757f3fSDimitry Andric else 9405f757f3fSDimitry Andric Res = CurDAG->getMachineNode(Opc, DL, VT, Imm); 94106c3fb27SDimitry Andric 94206c3fb27SDimitry Andric // For f64 -0.0, we need to insert a fneg.d idiom. 9435f757f3fSDimitry Andric if (NegZeroF64) { 9445f757f3fSDimitry Andric Opc = RISCV::FSGNJN_D; 9455f757f3fSDimitry Andric if (HasZdinx) 9465f757f3fSDimitry Andric Opc = Is64Bit ? RISCV::FSGNJN_D_INX : RISCV::FSGNJN_D_IN32X; 9475f757f3fSDimitry Andric Res = 9485f757f3fSDimitry Andric CurDAG->getMachineNode(Opc, DL, VT, SDValue(Res, 0), SDValue(Res, 0)); 9495f757f3fSDimitry Andric } 95006c3fb27SDimitry Andric 95106c3fb27SDimitry Andric ReplaceNode(Node, Res); 95206c3fb27SDimitry Andric return; 95306c3fb27SDimitry Andric } 95406c3fb27SDimitry Andric case RISCVISD::SplitF64: { 95506c3fb27SDimitry Andric if (!Subtarget->hasStdExtZfa()) 95606c3fb27SDimitry Andric break; 95706c3fb27SDimitry Andric assert(Subtarget->hasStdExtD() && !Subtarget->is64Bit() && 95806c3fb27SDimitry Andric "Unexpected subtarget"); 95906c3fb27SDimitry Andric 96006c3fb27SDimitry Andric // With Zfa, lower to fmv.x.w and fmvh.x.d. 96106c3fb27SDimitry Andric if (!SDValue(Node, 0).use_empty()) { 96206c3fb27SDimitry Andric SDNode *Lo = CurDAG->getMachineNode(RISCV::FMV_X_W_FPR64, DL, VT, 96306c3fb27SDimitry Andric Node->getOperand(0)); 96406c3fb27SDimitry Andric ReplaceUses(SDValue(Node, 0), SDValue(Lo, 0)); 96506c3fb27SDimitry Andric } 96606c3fb27SDimitry Andric if (!SDValue(Node, 1).use_empty()) { 96706c3fb27SDimitry Andric SDNode *Hi = CurDAG->getMachineNode(RISCV::FMVH_X_D, DL, VT, 96806c3fb27SDimitry Andric Node->getOperand(0)); 96906c3fb27SDimitry Andric ReplaceUses(SDValue(Node, 1), SDValue(Hi, 0)); 97006c3fb27SDimitry Andric } 97106c3fb27SDimitry Andric 97206c3fb27SDimitry Andric CurDAG->RemoveDeadNode(Node); 9730b57cec5SDimitry Andric return; 9740b57cec5SDimitry Andric } 97581ad6265SDimitry Andric case ISD::SHL: { 976fe6060f1SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 97704eeddc0SDimitry Andric if (!N1C) 97804eeddc0SDimitry Andric break; 979fe6060f1SDimitry Andric SDValue N0 = Node->getOperand(0); 98004eeddc0SDimitry Andric if (N0.getOpcode() != ISD::AND || !N0.hasOneUse() || 98104eeddc0SDimitry Andric !isa<ConstantSDNode>(N0.getOperand(1))) 98204eeddc0SDimitry Andric break; 98304eeddc0SDimitry Andric unsigned ShAmt = N1C->getZExtValue(); 984fe6060f1SDimitry Andric uint64_t Mask = N0.getConstantOperandVal(1); 98581ad6265SDimitry Andric 98681ad6265SDimitry Andric // Optimize (shl (and X, C2), C) -> (slli (srliw X, C3), C3+C) where C2 has 98781ad6265SDimitry Andric // 32 leading zeros and C3 trailing zeros. 98881ad6265SDimitry Andric if (ShAmt <= 32 && isShiftedMask_64(Mask)) { 98981ad6265SDimitry Andric unsigned XLen = Subtarget->getXLen(); 990bdd1243dSDimitry Andric unsigned LeadingZeros = XLen - llvm::bit_width(Mask); 99106c3fb27SDimitry Andric unsigned TrailingZeros = llvm::countr_zero(Mask); 99281ad6265SDimitry Andric if (TrailingZeros > 0 && LeadingZeros == 32) { 99381ad6265SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 99481ad6265SDimitry Andric RISCV::SRLIW, DL, VT, N0->getOperand(0), 99581ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros, DL, VT)); 99681ad6265SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 99781ad6265SDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 99881ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros + ShAmt, DL, VT)); 99981ad6265SDimitry Andric ReplaceNode(Node, SLLI); 100081ad6265SDimitry Andric return; 100181ad6265SDimitry Andric } 100281ad6265SDimitry Andric } 100381ad6265SDimitry Andric break; 100481ad6265SDimitry Andric } 100581ad6265SDimitry Andric case ISD::SRL: { 100681ad6265SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 100781ad6265SDimitry Andric if (!N1C) 100881ad6265SDimitry Andric break; 100981ad6265SDimitry Andric SDValue N0 = Node->getOperand(0); 1010bdd1243dSDimitry Andric if (N0.getOpcode() != ISD::AND || !isa<ConstantSDNode>(N0.getOperand(1))) 101181ad6265SDimitry Andric break; 101281ad6265SDimitry Andric unsigned ShAmt = N1C->getZExtValue(); 101381ad6265SDimitry Andric uint64_t Mask = N0.getConstantOperandVal(1); 101481ad6265SDimitry Andric 101581ad6265SDimitry Andric // Optimize (srl (and X, C2), C) -> (slli (srliw X, C3), C3-C) where C2 has 101681ad6265SDimitry Andric // 32 leading zeros and C3 trailing zeros. 1017bdd1243dSDimitry Andric if (isShiftedMask_64(Mask) && N0.hasOneUse()) { 101881ad6265SDimitry Andric unsigned XLen = Subtarget->getXLen(); 1019bdd1243dSDimitry Andric unsigned LeadingZeros = XLen - llvm::bit_width(Mask); 102006c3fb27SDimitry Andric unsigned TrailingZeros = llvm::countr_zero(Mask); 102181ad6265SDimitry Andric if (LeadingZeros == 32 && TrailingZeros > ShAmt) { 102281ad6265SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 102381ad6265SDimitry Andric RISCV::SRLIW, DL, VT, N0->getOperand(0), 102481ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros, DL, VT)); 102581ad6265SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 102681ad6265SDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 102781ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros - ShAmt, DL, VT)); 102881ad6265SDimitry Andric ReplaceNode(Node, SLLI); 102981ad6265SDimitry Andric return; 103081ad6265SDimitry Andric } 103181ad6265SDimitry Andric } 103281ad6265SDimitry Andric 103381ad6265SDimitry Andric // Optimize (srl (and X, C2), C) -> 103481ad6265SDimitry Andric // (srli (slli X, (XLen-C3), (XLen-C3) + C) 103581ad6265SDimitry Andric // Where C2 is a mask with C3 trailing ones. 103681ad6265SDimitry Andric // Taking into account that the C2 may have had lower bits unset by 103781ad6265SDimitry Andric // SimplifyDemandedBits. This avoids materializing the C2 immediate. 103881ad6265SDimitry Andric // This pattern occurs when type legalizing right shifts for types with 103981ad6265SDimitry Andric // less than XLen bits. 1040fe6060f1SDimitry Andric Mask |= maskTrailingOnes<uint64_t>(ShAmt); 104104eeddc0SDimitry Andric if (!isMask_64(Mask)) 104204eeddc0SDimitry Andric break; 104306c3fb27SDimitry Andric unsigned TrailingOnes = llvm::countr_one(Mask); 1044bdd1243dSDimitry Andric if (ShAmt >= TrailingOnes) 104504eeddc0SDimitry Andric break; 10465c16e71dSDimitry Andric // If the mask has 32 trailing ones, use SRLI on RV32 or SRLIW on RV64. 1047bdd1243dSDimitry Andric if (TrailingOnes == 32) { 10485c16e71dSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 10495c16e71dSDimitry Andric Subtarget->is64Bit() ? RISCV::SRLIW : RISCV::SRLI, DL, VT, 10505c16e71dSDimitry Andric N0->getOperand(0), CurDAG->getTargetConstant(ShAmt, DL, VT)); 10515c16e71dSDimitry Andric ReplaceNode(Node, SRLI); 1052bdd1243dSDimitry Andric return; 1053bdd1243dSDimitry Andric } 1054bdd1243dSDimitry Andric 105506c3fb27SDimitry Andric // Only do the remaining transforms if the AND has one use. 1056bdd1243dSDimitry Andric if (!N0.hasOneUse()) 1057bdd1243dSDimitry Andric break; 1058bdd1243dSDimitry Andric 105906c3fb27SDimitry Andric // If C2 is (1 << ShAmt) use bexti or th.tst if possible. 106006c3fb27SDimitry Andric if (HasBitTest && ShAmt + 1 == TrailingOnes) { 106106c3fb27SDimitry Andric SDNode *BEXTI = CurDAG->getMachineNode( 106206c3fb27SDimitry Andric Subtarget->hasStdExtZbs() ? RISCV::BEXTI : RISCV::TH_TST, DL, VT, 106306c3fb27SDimitry Andric N0->getOperand(0), CurDAG->getTargetConstant(ShAmt, DL, VT)); 1064fcaf7f86SDimitry Andric ReplaceNode(Node, BEXTI); 1065fcaf7f86SDimitry Andric return; 1066fcaf7f86SDimitry Andric } 106706c3fb27SDimitry Andric 106804eeddc0SDimitry Andric unsigned LShAmt = Subtarget->getXLen() - TrailingOnes; 1069fe6060f1SDimitry Andric SDNode *SLLI = 1070fe6060f1SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0->getOperand(0), 1071fe6060f1SDimitry Andric CurDAG->getTargetConstant(LShAmt, DL, VT)); 1072fe6060f1SDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1073fe6060f1SDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 1074fe6060f1SDimitry Andric CurDAG->getTargetConstant(LShAmt + ShAmt, DL, VT)); 1075fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 1076fe6060f1SDimitry Andric return; 1077fe6060f1SDimitry Andric } 107804eeddc0SDimitry Andric case ISD::SRA: { 107906c3fb27SDimitry Andric if (trySignedBitfieldExtract(Node)) 108006c3fb27SDimitry Andric return; 108106c3fb27SDimitry Andric 108204eeddc0SDimitry Andric // Optimize (sra (sext_inreg X, i16), C) -> 108304eeddc0SDimitry Andric // (srai (slli X, (XLen-16), (XLen-16) + C) 108404eeddc0SDimitry Andric // And (sra (sext_inreg X, i8), C) -> 108504eeddc0SDimitry Andric // (srai (slli X, (XLen-8), (XLen-8) + C) 108604eeddc0SDimitry Andric // This can occur when Zbb is enabled, which makes sext_inreg i16/i8 legal. 108704eeddc0SDimitry Andric // This transform matches the code we get without Zbb. The shifts are more 108804eeddc0SDimitry Andric // compressible, and this can help expose CSE opportunities in the sdiv by 108904eeddc0SDimitry Andric // constant optimization. 109004eeddc0SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 109104eeddc0SDimitry Andric if (!N1C) 1092fe6060f1SDimitry Andric break; 109304eeddc0SDimitry Andric SDValue N0 = Node->getOperand(0); 109404eeddc0SDimitry Andric if (N0.getOpcode() != ISD::SIGN_EXTEND_INREG || !N0.hasOneUse()) 109504eeddc0SDimitry Andric break; 109604eeddc0SDimitry Andric unsigned ShAmt = N1C->getZExtValue(); 109704eeddc0SDimitry Andric unsigned ExtSize = 109804eeddc0SDimitry Andric cast<VTSDNode>(N0.getOperand(1))->getVT().getSizeInBits(); 109904eeddc0SDimitry Andric // ExtSize of 32 should use sraiw via tablegen pattern. 110004eeddc0SDimitry Andric if (ExtSize >= 32 || ShAmt >= ExtSize) 110104eeddc0SDimitry Andric break; 110204eeddc0SDimitry Andric unsigned LShAmt = Subtarget->getXLen() - ExtSize; 110304eeddc0SDimitry Andric SDNode *SLLI = 110404eeddc0SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0->getOperand(0), 110504eeddc0SDimitry Andric CurDAG->getTargetConstant(LShAmt, DL, VT)); 110604eeddc0SDimitry Andric SDNode *SRAI = CurDAG->getMachineNode( 110704eeddc0SDimitry Andric RISCV::SRAI, DL, VT, SDValue(SLLI, 0), 110804eeddc0SDimitry Andric CurDAG->getTargetConstant(LShAmt + ShAmt, DL, VT)); 110904eeddc0SDimitry Andric ReplaceNode(Node, SRAI); 111004eeddc0SDimitry Andric return; 1111fe6060f1SDimitry Andric } 1112bdd1243dSDimitry Andric case ISD::OR: 1113bdd1243dSDimitry Andric case ISD::XOR: 1114bdd1243dSDimitry Andric if (tryShrinkShlLogicImm(Node)) 1115bdd1243dSDimitry Andric return; 1116bdd1243dSDimitry Andric 1117bdd1243dSDimitry Andric break; 1118fe6060f1SDimitry Andric case ISD::AND: { 1119fe6060f1SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 1120fe6060f1SDimitry Andric if (!N1C) 1121fe6060f1SDimitry Andric break; 112206c3fb27SDimitry Andric uint64_t C1 = N1C->getZExtValue(); 112306c3fb27SDimitry Andric const bool isC1Mask = isMask_64(C1); 112406c3fb27SDimitry Andric const bool isC1ANDI = isInt<12>(C1); 1125fe6060f1SDimitry Andric 1126fe6060f1SDimitry Andric SDValue N0 = Node->getOperand(0); 1127fe6060f1SDimitry Andric 112806c3fb27SDimitry Andric auto tryUnsignedBitfieldExtract = [&](SDNode *Node, SDLoc DL, MVT VT, 112906c3fb27SDimitry Andric SDValue X, unsigned Msb, 113006c3fb27SDimitry Andric unsigned Lsb) { 113106c3fb27SDimitry Andric if (!Subtarget->hasVendorXTHeadBb()) 113206c3fb27SDimitry Andric return false; 113306c3fb27SDimitry Andric 113406c3fb27SDimitry Andric SDNode *TH_EXTU = CurDAG->getMachineNode( 113506c3fb27SDimitry Andric RISCV::TH_EXTU, DL, VT, X, CurDAG->getTargetConstant(Msb, DL, VT), 113606c3fb27SDimitry Andric CurDAG->getTargetConstant(Lsb, DL, VT)); 113706c3fb27SDimitry Andric ReplaceNode(Node, TH_EXTU); 113806c3fb27SDimitry Andric return true; 113906c3fb27SDimitry Andric }; 114006c3fb27SDimitry Andric 1141fe6060f1SDimitry Andric bool LeftShift = N0.getOpcode() == ISD::SHL; 1142bdd1243dSDimitry Andric if (LeftShift || N0.getOpcode() == ISD::SRL) { 1143fe6060f1SDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N0.getOperand(1)); 1144fe6060f1SDimitry Andric if (!C) 1145fe6060f1SDimitry Andric break; 1146753f127fSDimitry Andric unsigned C2 = C->getZExtValue(); 1147fe6060f1SDimitry Andric unsigned XLen = Subtarget->getXLen(); 1148753f127fSDimitry Andric assert((C2 > 0 && C2 < XLen) && "Unexpected shift amount!"); 1149fe6060f1SDimitry Andric 115081ad6265SDimitry Andric // Keep track of whether this is a c.andi. If we can't use c.andi, the 115181ad6265SDimitry Andric // shift pair might offer more compression opportunities. 115281ad6265SDimitry Andric // TODO: We could check for C extension here, but we don't have many lit 1153bdd1243dSDimitry Andric // tests with the C extension enabled so not checking gets better 1154bdd1243dSDimitry Andric // coverage. 115581ad6265SDimitry Andric // TODO: What if ANDI faster than shift? 115681ad6265SDimitry Andric bool IsCANDI = isInt<6>(N1C->getSExtValue()); 1157fe6060f1SDimitry Andric 1158fe6060f1SDimitry Andric // Clear irrelevant bits in the mask. 1159fe6060f1SDimitry Andric if (LeftShift) 1160fe6060f1SDimitry Andric C1 &= maskTrailingZeros<uint64_t>(C2); 1161fe6060f1SDimitry Andric else 1162fe6060f1SDimitry Andric C1 &= maskTrailingOnes<uint64_t>(XLen - C2); 1163fe6060f1SDimitry Andric 1164fe6060f1SDimitry Andric // Some transforms should only be done if the shift has a single use or 1165fe6060f1SDimitry Andric // the AND would become (srli (slli X, 32), 32) 1166fe6060f1SDimitry Andric bool OneUseOrZExtW = N0.hasOneUse() || C1 == UINT64_C(0xFFFFFFFF); 1167fe6060f1SDimitry Andric 1168fe6060f1SDimitry Andric SDValue X = N0.getOperand(0); 1169fe6060f1SDimitry Andric 1170fe6060f1SDimitry Andric // Turn (and (srl x, c2) c1) -> (srli (slli x, c3-c2), c3) if c1 is a mask 1171fe6060f1SDimitry Andric // with c3 leading zeros. 117206c3fb27SDimitry Andric if (!LeftShift && isC1Mask) { 1173bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(C1); 1174753f127fSDimitry Andric if (C2 < Leading) { 1175fe6060f1SDimitry Andric // If the number of leading zeros is C2+32 this can be SRLIW. 1176753f127fSDimitry Andric if (C2 + 32 == Leading) { 117781ad6265SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 117881ad6265SDimitry Andric RISCV::SRLIW, DL, VT, X, CurDAG->getTargetConstant(C2, DL, VT)); 1179fe6060f1SDimitry Andric ReplaceNode(Node, SRLIW); 1180fe6060f1SDimitry Andric return; 1181fe6060f1SDimitry Andric } 1182fe6060f1SDimitry Andric 1183bdd1243dSDimitry Andric // (and (srl (sexti32 Y), c2), c1) -> (srliw (sraiw Y, 31), c3 - 32) 1184bdd1243dSDimitry Andric // if c1 is a mask with c3 leading zeros and c2 >= 32 and c3-c2==1. 1185fe6060f1SDimitry Andric // 1186fe6060f1SDimitry Andric // This pattern occurs when (i32 (srl (sra 31), c3 - 32)) is type 1187fe6060f1SDimitry Andric // legalized and goes through DAG combine. 1188753f127fSDimitry Andric if (C2 >= 32 && (Leading - C2) == 1 && N0.hasOneUse() && 118981ad6265SDimitry Andric X.getOpcode() == ISD::SIGN_EXTEND_INREG && 119081ad6265SDimitry Andric cast<VTSDNode>(X.getOperand(1))->getVT() == MVT::i32) { 1191fe6060f1SDimitry Andric SDNode *SRAIW = 119281ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::SRAIW, DL, VT, X.getOperand(0), 119381ad6265SDimitry Andric CurDAG->getTargetConstant(31, DL, VT)); 1194fe6060f1SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 119581ad6265SDimitry Andric RISCV::SRLIW, DL, VT, SDValue(SRAIW, 0), 1196753f127fSDimitry Andric CurDAG->getTargetConstant(Leading - 32, DL, VT)); 1197fe6060f1SDimitry Andric ReplaceNode(Node, SRLIW); 1198fe6060f1SDimitry Andric return; 1199fe6060f1SDimitry Andric } 1200fe6060f1SDimitry Andric 120106c3fb27SDimitry Andric // Try to use an unsigned bitfield extract (e.g., th.extu) if 120206c3fb27SDimitry Andric // available. 120306c3fb27SDimitry Andric // Transform (and (srl x, C2), C1) 120406c3fb27SDimitry Andric // -> (<bfextract> x, msb, lsb) 120506c3fb27SDimitry Andric // 120606c3fb27SDimitry Andric // Make sure to keep this below the SRLIW cases, as we always want to 120706c3fb27SDimitry Andric // prefer the more common instruction. 120806c3fb27SDimitry Andric const unsigned Msb = llvm::bit_width(C1) + C2 - 1; 120906c3fb27SDimitry Andric const unsigned Lsb = C2; 121006c3fb27SDimitry Andric if (tryUnsignedBitfieldExtract(Node, DL, VT, X, Msb, Lsb)) 121106c3fb27SDimitry Andric return; 121206c3fb27SDimitry Andric 1213fe6060f1SDimitry Andric // (srli (slli x, c3-c2), c3). 121481ad6265SDimitry Andric // Skip if we could use (zext.w (sraiw X, C2)). 1215753f127fSDimitry Andric bool Skip = Subtarget->hasStdExtZba() && Leading == 32 && 121681ad6265SDimitry Andric X.getOpcode() == ISD::SIGN_EXTEND_INREG && 121781ad6265SDimitry Andric cast<VTSDNode>(X.getOperand(1))->getVT() == MVT::i32; 121806c3fb27SDimitry Andric // Also Skip if we can use bexti or th.tst. 121906c3fb27SDimitry Andric Skip |= HasBitTest && Leading == XLen - 1; 122081ad6265SDimitry Andric if (OneUseOrZExtW && !Skip) { 1221fe6060f1SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 122281ad6265SDimitry Andric RISCV::SLLI, DL, VT, X, 1223753f127fSDimitry Andric CurDAG->getTargetConstant(Leading - C2, DL, VT)); 1224753f127fSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1225753f127fSDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 1226753f127fSDimitry Andric CurDAG->getTargetConstant(Leading, DL, VT)); 1227fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 1228fe6060f1SDimitry Andric return; 1229fe6060f1SDimitry Andric } 1230fe6060f1SDimitry Andric } 1231fe6060f1SDimitry Andric } 1232fe6060f1SDimitry Andric 1233349cc55cSDimitry Andric // Turn (and (shl x, c2), c1) -> (srli (slli c2+c3), c3) if c1 is a mask 1234fe6060f1SDimitry Andric // shifted by c2 bits with c3 leading zeros. 1235fe6060f1SDimitry Andric if (LeftShift && isShiftedMask_64(C1)) { 1236bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(C1); 1237fe6060f1SDimitry Andric 1238753f127fSDimitry Andric if (C2 + Leading < XLen && 1239753f127fSDimitry Andric C1 == (maskTrailingOnes<uint64_t>(XLen - (C2 + Leading)) << C2)) { 1240fe6060f1SDimitry Andric // Use slli.uw when possible. 1241753f127fSDimitry Andric if ((XLen - (C2 + Leading)) == 32 && Subtarget->hasStdExtZba()) { 1242bdd1243dSDimitry Andric SDNode *SLLI_UW = 1243bdd1243dSDimitry Andric CurDAG->getMachineNode(RISCV::SLLI_UW, DL, VT, X, 1244bdd1243dSDimitry Andric CurDAG->getTargetConstant(C2, DL, VT)); 12451fd87a68SDimitry Andric ReplaceNode(Node, SLLI_UW); 1246fe6060f1SDimitry Andric return; 1247fe6060f1SDimitry Andric } 1248fe6060f1SDimitry Andric 1249fe6060f1SDimitry Andric // (srli (slli c2+c3), c3) 125081ad6265SDimitry Andric if (OneUseOrZExtW && !IsCANDI) { 1251fe6060f1SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 125281ad6265SDimitry Andric RISCV::SLLI, DL, VT, X, 1253753f127fSDimitry Andric CurDAG->getTargetConstant(C2 + Leading, DL, VT)); 1254753f127fSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1255753f127fSDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 1256753f127fSDimitry Andric CurDAG->getTargetConstant(Leading, DL, VT)); 1257fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 1258fe6060f1SDimitry Andric return; 1259fe6060f1SDimitry Andric } 1260fe6060f1SDimitry Andric } 1261fe6060f1SDimitry Andric } 1262fe6060f1SDimitry Andric 1263349cc55cSDimitry Andric // Turn (and (shr x, c2), c1) -> (slli (srli x, c2+c3), c3) if c1 is a 1264349cc55cSDimitry Andric // shifted mask with c2 leading zeros and c3 trailing zeros. 1265349cc55cSDimitry Andric if (!LeftShift && isShiftedMask_64(C1)) { 1266bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(C1); 126706c3fb27SDimitry Andric unsigned Trailing = llvm::countr_zero(C1); 1268bdd1243dSDimitry Andric if (Leading == C2 && C2 + Trailing < XLen && OneUseOrZExtW && 1269bdd1243dSDimitry Andric !IsCANDI) { 127081ad6265SDimitry Andric unsigned SrliOpc = RISCV::SRLI; 127181ad6265SDimitry Andric // If the input is zexti32 we should use SRLIW. 1272bdd1243dSDimitry Andric if (X.getOpcode() == ISD::AND && 1273bdd1243dSDimitry Andric isa<ConstantSDNode>(X.getOperand(1)) && 127481ad6265SDimitry Andric X.getConstantOperandVal(1) == UINT64_C(0xFFFFFFFF)) { 127581ad6265SDimitry Andric SrliOpc = RISCV::SRLIW; 127681ad6265SDimitry Andric X = X.getOperand(0); 127781ad6265SDimitry Andric } 1278349cc55cSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1279753f127fSDimitry Andric SrliOpc, DL, VT, X, 1280753f127fSDimitry Andric CurDAG->getTargetConstant(C2 + Trailing, DL, VT)); 1281bdd1243dSDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 1282bdd1243dSDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLI, 0), 1283753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 1284349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 1285349cc55cSDimitry Andric return; 1286349cc55cSDimitry Andric } 1287349cc55cSDimitry Andric // If the leading zero count is C2+32, we can use SRLIW instead of SRLI. 1288753f127fSDimitry Andric if (Leading > 32 && (Leading - 32) == C2 && C2 + Trailing < 32 && 128981ad6265SDimitry Andric OneUseOrZExtW && !IsCANDI) { 1290753f127fSDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 1291753f127fSDimitry Andric RISCV::SRLIW, DL, VT, X, 1292753f127fSDimitry Andric CurDAG->getTargetConstant(C2 + Trailing, DL, VT)); 1293bdd1243dSDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 1294bdd1243dSDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 1295753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 1296349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 1297349cc55cSDimitry Andric return; 1298349cc55cSDimitry Andric } 1299349cc55cSDimitry Andric } 1300349cc55cSDimitry Andric 1301349cc55cSDimitry Andric // Turn (and (shl x, c2), c1) -> (slli (srli x, c3-c2), c3) if c1 is a 1302349cc55cSDimitry Andric // shifted mask with no leading zeros and c3 trailing zeros. 1303349cc55cSDimitry Andric if (LeftShift && isShiftedMask_64(C1)) { 1304bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(C1); 130506c3fb27SDimitry Andric unsigned Trailing = llvm::countr_zero(C1); 1306753f127fSDimitry Andric if (Leading == 0 && C2 < Trailing && OneUseOrZExtW && !IsCANDI) { 1307349cc55cSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1308753f127fSDimitry Andric RISCV::SRLI, DL, VT, X, 1309753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)); 1310bdd1243dSDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 1311bdd1243dSDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLI, 0), 1312753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 1313349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 1314349cc55cSDimitry Andric return; 1315349cc55cSDimitry Andric } 1316349cc55cSDimitry Andric // If we have (32-C2) leading zeros, we can use SRLIW instead of SRLI. 1317753f127fSDimitry Andric if (C2 < Trailing && Leading + C2 == 32 && OneUseOrZExtW && !IsCANDI) { 1318753f127fSDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 1319753f127fSDimitry Andric RISCV::SRLIW, DL, VT, X, 1320753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)); 1321bdd1243dSDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 1322bdd1243dSDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 1323753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 1324349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 1325349cc55cSDimitry Andric return; 1326349cc55cSDimitry Andric } 1327349cc55cSDimitry Andric } 1328bdd1243dSDimitry Andric } 1329bdd1243dSDimitry Andric 133006c3fb27SDimitry Andric // If C1 masks off the upper bits only (but can't be formed as an 133106c3fb27SDimitry Andric // ANDI), use an unsigned bitfield extract (e.g., th.extu), if 133206c3fb27SDimitry Andric // available. 133306c3fb27SDimitry Andric // Transform (and x, C1) 133406c3fb27SDimitry Andric // -> (<bfextract> x, msb, lsb) 133506c3fb27SDimitry Andric if (isC1Mask && !isC1ANDI) { 133606c3fb27SDimitry Andric const unsigned Msb = llvm::bit_width(C1) - 1; 133706c3fb27SDimitry Andric if (tryUnsignedBitfieldExtract(Node, DL, VT, N0, Msb, 0)) 133806c3fb27SDimitry Andric return; 133906c3fb27SDimitry Andric } 134006c3fb27SDimitry Andric 1341bdd1243dSDimitry Andric if (tryShrinkShlLogicImm(Node)) 1342bdd1243dSDimitry Andric return; 1343349cc55cSDimitry Andric 1344fe6060f1SDimitry Andric break; 1345fe6060f1SDimitry Andric } 13460eae32dcSDimitry Andric case ISD::MUL: { 13470eae32dcSDimitry Andric // Special case for calculating (mul (and X, C2), C1) where the full product 13480eae32dcSDimitry Andric // fits in XLen bits. We can shift X left by the number of leading zeros in 13490eae32dcSDimitry Andric // C2 and shift C1 left by XLen-lzcnt(C2). This will ensure the final 13500eae32dcSDimitry Andric // product has XLen trailing zeros, putting it in the output of MULHU. This 13510eae32dcSDimitry Andric // can avoid materializing a constant in a register for C2. 13520eae32dcSDimitry Andric 13530eae32dcSDimitry Andric // RHS should be a constant. 13540eae32dcSDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 13550eae32dcSDimitry Andric if (!N1C || !N1C->hasOneUse()) 13560eae32dcSDimitry Andric break; 13570eae32dcSDimitry Andric 13580eae32dcSDimitry Andric // LHS should be an AND with constant. 13590eae32dcSDimitry Andric SDValue N0 = Node->getOperand(0); 13600eae32dcSDimitry Andric if (N0.getOpcode() != ISD::AND || !isa<ConstantSDNode>(N0.getOperand(1))) 13610eae32dcSDimitry Andric break; 13620eae32dcSDimitry Andric 13630eae32dcSDimitry Andric uint64_t C2 = cast<ConstantSDNode>(N0.getOperand(1))->getZExtValue(); 13640eae32dcSDimitry Andric 13650eae32dcSDimitry Andric // Constant should be a mask. 13660eae32dcSDimitry Andric if (!isMask_64(C2)) 13670eae32dcSDimitry Andric break; 13680eae32dcSDimitry Andric 136906c3fb27SDimitry Andric // If this can be an ANDI or ZEXT.H, don't do this if the ANDI/ZEXT has 137006c3fb27SDimitry Andric // multiple users or the constant is a simm12. This prevents inserting a 137106c3fb27SDimitry Andric // shift and still have uses of the AND/ZEXT. Shifting a simm12 will likely 137206c3fb27SDimitry Andric // make it more costly to materialize. Otherwise, using a SLLI might allow 137306c3fb27SDimitry Andric // it to be compressed. 1374fcaf7f86SDimitry Andric bool IsANDIOrZExt = 1375fcaf7f86SDimitry Andric isInt<12>(C2) || 137606c3fb27SDimitry Andric (C2 == UINT64_C(0xFFFF) && Subtarget->hasStdExtZbb()); 137706c3fb27SDimitry Andric // With XTHeadBb, we can use TH.EXTU. 137806c3fb27SDimitry Andric IsANDIOrZExt |= C2 == UINT64_C(0xFFFF) && Subtarget->hasVendorXTHeadBb(); 1379fcaf7f86SDimitry Andric if (IsANDIOrZExt && (isInt<12>(N1C->getSExtValue()) || !N0.hasOneUse())) 13800eae32dcSDimitry Andric break; 138106c3fb27SDimitry Andric // If this can be a ZEXT.w, don't do this if the ZEXT has multiple users or 138206c3fb27SDimitry Andric // the constant is a simm32. 138306c3fb27SDimitry Andric bool IsZExtW = C2 == UINT64_C(0xFFFFFFFF) && Subtarget->hasStdExtZba(); 138406c3fb27SDimitry Andric // With XTHeadBb, we can use TH.EXTU. 138506c3fb27SDimitry Andric IsZExtW |= C2 == UINT64_C(0xFFFFFFFF) && Subtarget->hasVendorXTHeadBb(); 138606c3fb27SDimitry Andric if (IsZExtW && (isInt<32>(N1C->getSExtValue()) || !N0.hasOneUse())) 138706c3fb27SDimitry Andric break; 13880eae32dcSDimitry Andric 13890eae32dcSDimitry Andric // We need to shift left the AND input and C1 by a total of XLen bits. 13900eae32dcSDimitry Andric 13910eae32dcSDimitry Andric // How far left do we need to shift the AND input? 13920eae32dcSDimitry Andric unsigned XLen = Subtarget->getXLen(); 1393bdd1243dSDimitry Andric unsigned LeadingZeros = XLen - llvm::bit_width(C2); 13940eae32dcSDimitry Andric 13950eae32dcSDimitry Andric // The constant gets shifted by the remaining amount unless that would 13960eae32dcSDimitry Andric // shift bits out. 13970eae32dcSDimitry Andric uint64_t C1 = N1C->getZExtValue(); 13980eae32dcSDimitry Andric unsigned ConstantShift = XLen - LeadingZeros; 1399bdd1243dSDimitry Andric if (ConstantShift > (XLen - llvm::bit_width(C1))) 14000eae32dcSDimitry Andric break; 14010eae32dcSDimitry Andric 14020eae32dcSDimitry Andric uint64_t ShiftedC1 = C1 << ConstantShift; 14030eae32dcSDimitry Andric // If this RV32, we need to sign extend the constant. 14040eae32dcSDimitry Andric if (XLen == 32) 140581ad6265SDimitry Andric ShiftedC1 = SignExtend64<32>(ShiftedC1); 14060eae32dcSDimitry Andric 14070eae32dcSDimitry Andric // Create (mulhu (slli X, lzcnt(C2)), C1 << (XLen - lzcnt(C2))). 140806c3fb27SDimitry Andric SDNode *Imm = selectImm(CurDAG, DL, VT, ShiftedC1, *Subtarget).getNode(); 14090eae32dcSDimitry Andric SDNode *SLLI = 14100eae32dcSDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0.getOperand(0), 14110eae32dcSDimitry Andric CurDAG->getTargetConstant(LeadingZeros, DL, VT)); 14120eae32dcSDimitry Andric SDNode *MULHU = CurDAG->getMachineNode(RISCV::MULHU, DL, VT, 14130eae32dcSDimitry Andric SDValue(SLLI, 0), SDValue(Imm, 0)); 14140eae32dcSDimitry Andric ReplaceNode(Node, MULHU); 14150eae32dcSDimitry Andric return; 14160eae32dcSDimitry Andric } 141706c3fb27SDimitry Andric case ISD::LOAD: { 141806c3fb27SDimitry Andric if (tryIndexedLoad(Node)) 141906c3fb27SDimitry Andric return; 142006c3fb27SDimitry Andric break; 142106c3fb27SDimitry Andric } 1422fe6060f1SDimitry Andric case ISD::INTRINSIC_WO_CHAIN: { 1423fe6060f1SDimitry Andric unsigned IntNo = Node->getConstantOperandVal(0); 1424fe6060f1SDimitry Andric switch (IntNo) { 1425fe6060f1SDimitry Andric // By default we do not custom select any intrinsic. 1426fe6060f1SDimitry Andric default: 1427fe6060f1SDimitry Andric break; 1428fe6060f1SDimitry Andric case Intrinsic::riscv_vmsgeu: 1429fe6060f1SDimitry Andric case Intrinsic::riscv_vmsge: { 1430fe6060f1SDimitry Andric SDValue Src1 = Node->getOperand(1); 1431fe6060f1SDimitry Andric SDValue Src2 = Node->getOperand(2); 143204eeddc0SDimitry Andric bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu; 143304eeddc0SDimitry Andric bool IsCmpUnsignedZero = false; 1434fe6060f1SDimitry Andric // Only custom select scalar second operand. 1435fe6060f1SDimitry Andric if (Src2.getValueType() != XLenVT) 1436fe6060f1SDimitry Andric break; 1437fe6060f1SDimitry Andric // Small constants are handled with patterns. 1438fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Src2)) { 1439fe6060f1SDimitry Andric int64_t CVal = C->getSExtValue(); 144004eeddc0SDimitry Andric if (CVal >= -15 && CVal <= 16) { 144104eeddc0SDimitry Andric if (!IsUnsigned || CVal != 0) 1442fe6060f1SDimitry Andric break; 144304eeddc0SDimitry Andric IsCmpUnsignedZero = true; 1444fe6060f1SDimitry Andric } 144504eeddc0SDimitry Andric } 1446fe6060f1SDimitry Andric MVT Src1VT = Src1.getSimpleValueType(); 144704eeddc0SDimitry Andric unsigned VMSLTOpcode, VMNANDOpcode, VMSetOpcode; 1448fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(Src1VT)) { 1449fe6060f1SDimitry Andric default: 1450fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 145104eeddc0SDimitry Andric #define CASE_VMSLT_VMNAND_VMSET_OPCODES(lmulenum, suffix, suffix_b) \ 145204eeddc0SDimitry Andric case RISCVII::VLMUL::lmulenum: \ 145304eeddc0SDimitry Andric VMSLTOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix \ 145404eeddc0SDimitry Andric : RISCV::PseudoVMSLT_VX_##suffix; \ 145504eeddc0SDimitry Andric VMNANDOpcode = RISCV::PseudoVMNAND_MM_##suffix; \ 145604eeddc0SDimitry Andric VMSetOpcode = RISCV::PseudoVMSET_M_##suffix_b; \ 1457fe6060f1SDimitry Andric break; 145804eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F8, MF8, B1) 145904eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F4, MF4, B2) 146004eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F2, MF2, B4) 146104eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_1, M1, B8) 146204eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_2, M2, B16) 146304eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_4, M4, B32) 146404eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_8, M8, B64) 146504eeddc0SDimitry Andric #undef CASE_VMSLT_VMNAND_VMSET_OPCODES 1466fe6060f1SDimitry Andric } 1467fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant( 1468fe6060f1SDimitry Andric Log2_32(Src1VT.getScalarSizeInBits()), DL, XLenVT); 1469fe6060f1SDimitry Andric SDValue VL; 1470fe6060f1SDimitry Andric selectVLOp(Node->getOperand(3), VL); 1471fe6060f1SDimitry Andric 147204eeddc0SDimitry Andric // If vmsgeu with 0 immediate, expand it to vmset. 147304eeddc0SDimitry Andric if (IsCmpUnsignedZero) { 147404eeddc0SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMSetOpcode, DL, VT, VL, SEW)); 147504eeddc0SDimitry Andric return; 147604eeddc0SDimitry Andric } 147704eeddc0SDimitry Andric 1478fe6060f1SDimitry Andric // Expand to 1479fe6060f1SDimitry Andric // vmslt{u}.vx vd, va, x; vmnand.mm vd, vd, vd 1480fe6060f1SDimitry Andric SDValue Cmp = SDValue( 1481fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTOpcode, DL, VT, {Src1, Src2, VL, SEW}), 1482fe6060f1SDimitry Andric 0); 1483fe6060f1SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMNANDOpcode, DL, VT, 1484fe6060f1SDimitry Andric {Cmp, Cmp, VL, SEW})); 1485fe6060f1SDimitry Andric return; 1486fe6060f1SDimitry Andric } 1487fe6060f1SDimitry Andric case Intrinsic::riscv_vmsgeu_mask: 1488fe6060f1SDimitry Andric case Intrinsic::riscv_vmsge_mask: { 1489fe6060f1SDimitry Andric SDValue Src1 = Node->getOperand(2); 1490fe6060f1SDimitry Andric SDValue Src2 = Node->getOperand(3); 149104eeddc0SDimitry Andric bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu_mask; 149204eeddc0SDimitry Andric bool IsCmpUnsignedZero = false; 1493fe6060f1SDimitry Andric // Only custom select scalar second operand. 1494fe6060f1SDimitry Andric if (Src2.getValueType() != XLenVT) 1495fe6060f1SDimitry Andric break; 1496fe6060f1SDimitry Andric // Small constants are handled with patterns. 1497fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Src2)) { 1498fe6060f1SDimitry Andric int64_t CVal = C->getSExtValue(); 149904eeddc0SDimitry Andric if (CVal >= -15 && CVal <= 16) { 150004eeddc0SDimitry Andric if (!IsUnsigned || CVal != 0) 1501fe6060f1SDimitry Andric break; 150204eeddc0SDimitry Andric IsCmpUnsignedZero = true; 1503fe6060f1SDimitry Andric } 150404eeddc0SDimitry Andric } 1505fe6060f1SDimitry Andric MVT Src1VT = Src1.getSimpleValueType(); 150604eeddc0SDimitry Andric unsigned VMSLTOpcode, VMSLTMaskOpcode, VMXOROpcode, VMANDNOpcode, 150781ad6265SDimitry Andric VMOROpcode; 1508fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(Src1VT)) { 1509fe6060f1SDimitry Andric default: 1510fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 151181ad6265SDimitry Andric #define CASE_VMSLT_OPCODES(lmulenum, suffix, suffix_b) \ 151204eeddc0SDimitry Andric case RISCVII::VLMUL::lmulenum: \ 151304eeddc0SDimitry Andric VMSLTOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix \ 151404eeddc0SDimitry Andric : RISCV::PseudoVMSLT_VX_##suffix; \ 151504eeddc0SDimitry Andric VMSLTMaskOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix##_MASK \ 151604eeddc0SDimitry Andric : RISCV::PseudoVMSLT_VX_##suffix##_MASK; \ 1517fe6060f1SDimitry Andric break; 151881ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_F8, MF8, B1) 151981ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_F4, MF4, B2) 152081ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_F2, MF2, B4) 152181ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_1, M1, B8) 152281ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_2, M2, B16) 152381ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_4, M4, B32) 152481ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_8, M8, B64) 152581ad6265SDimitry Andric #undef CASE_VMSLT_OPCODES 1526fe6060f1SDimitry Andric } 1527fe6060f1SDimitry Andric // Mask operations use the LMUL from the mask type. 1528fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(VT)) { 1529fe6060f1SDimitry Andric default: 1530fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 153181ad6265SDimitry Andric #define CASE_VMXOR_VMANDN_VMOR_OPCODES(lmulenum, suffix) \ 153204eeddc0SDimitry Andric case RISCVII::VLMUL::lmulenum: \ 153304eeddc0SDimitry Andric VMXOROpcode = RISCV::PseudoVMXOR_MM_##suffix; \ 153404eeddc0SDimitry Andric VMANDNOpcode = RISCV::PseudoVMANDN_MM_##suffix; \ 153581ad6265SDimitry Andric VMOROpcode = RISCV::PseudoVMOR_MM_##suffix; \ 1536fe6060f1SDimitry Andric break; 153781ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_F8, MF8) 153881ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_F4, MF4) 153981ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_F2, MF2) 154081ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_1, M1) 154181ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_2, M2) 154281ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_4, M4) 154381ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_8, M8) 154481ad6265SDimitry Andric #undef CASE_VMXOR_VMANDN_VMOR_OPCODES 1545fe6060f1SDimitry Andric } 1546fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant( 1547fe6060f1SDimitry Andric Log2_32(Src1VT.getScalarSizeInBits()), DL, XLenVT); 1548fe6060f1SDimitry Andric SDValue MaskSEW = CurDAG->getTargetConstant(0, DL, XLenVT); 1549fe6060f1SDimitry Andric SDValue VL; 1550fe6060f1SDimitry Andric selectVLOp(Node->getOperand(5), VL); 1551fe6060f1SDimitry Andric SDValue MaskedOff = Node->getOperand(1); 1552fe6060f1SDimitry Andric SDValue Mask = Node->getOperand(4); 155304eeddc0SDimitry Andric 155481ad6265SDimitry Andric // If vmsgeu_mask with 0 immediate, expand it to vmor mask, maskedoff. 155504eeddc0SDimitry Andric if (IsCmpUnsignedZero) { 155681ad6265SDimitry Andric // We don't need vmor if the MaskedOff and the Mask are the same 155781ad6265SDimitry Andric // value. 155881ad6265SDimitry Andric if (Mask == MaskedOff) { 155981ad6265SDimitry Andric ReplaceUses(Node, Mask.getNode()); 156081ad6265SDimitry Andric return; 156181ad6265SDimitry Andric } 156281ad6265SDimitry Andric ReplaceNode(Node, 156381ad6265SDimitry Andric CurDAG->getMachineNode(VMOROpcode, DL, VT, 156481ad6265SDimitry Andric {Mask, MaskedOff, VL, MaskSEW})); 156504eeddc0SDimitry Andric return; 156604eeddc0SDimitry Andric } 156704eeddc0SDimitry Andric 1568fe6060f1SDimitry Andric // If the MaskedOff value and the Mask are the same value use 1569349cc55cSDimitry Andric // vmslt{u}.vx vt, va, x; vmandn.mm vd, vd, vt 1570fe6060f1SDimitry Andric // This avoids needing to copy v0 to vd before starting the next sequence. 1571fe6060f1SDimitry Andric if (Mask == MaskedOff) { 1572fe6060f1SDimitry Andric SDValue Cmp = SDValue( 1573fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTOpcode, DL, VT, {Src1, Src2, VL, SEW}), 1574fe6060f1SDimitry Andric 0); 1575349cc55cSDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMANDNOpcode, DL, VT, 1576fe6060f1SDimitry Andric {Mask, Cmp, VL, MaskSEW})); 1577fe6060f1SDimitry Andric return; 1578fe6060f1SDimitry Andric } 1579fe6060f1SDimitry Andric 1580fe6060f1SDimitry Andric // Mask needs to be copied to V0. 1581fe6060f1SDimitry Andric SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, 1582fe6060f1SDimitry Andric RISCV::V0, Mask, SDValue()); 1583fe6060f1SDimitry Andric SDValue Glue = Chain.getValue(1); 1584fe6060f1SDimitry Andric SDValue V0 = CurDAG->getRegister(RISCV::V0, VT); 1585fe6060f1SDimitry Andric 1586fe6060f1SDimitry Andric // Otherwise use 1587fe6060f1SDimitry Andric // vmslt{u}.vx vd, va, x, v0.t; vmxor.mm vd, vd, v0 158881ad6265SDimitry Andric // The result is mask undisturbed. 158981ad6265SDimitry Andric // We use the same instructions to emulate mask agnostic behavior, because 159081ad6265SDimitry Andric // the agnostic result can be either undisturbed or all 1. 1591fe6060f1SDimitry Andric SDValue Cmp = SDValue( 1592fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTMaskOpcode, DL, VT, 1593fe6060f1SDimitry Andric {MaskedOff, Src1, Src2, V0, VL, SEW, Glue}), 1594fe6060f1SDimitry Andric 0); 159581ad6265SDimitry Andric // vmxor.mm vd, vd, v0 is used to update active value. 1596fe6060f1SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMXOROpcode, DL, VT, 1597fe6060f1SDimitry Andric {Cmp, Mask, VL, MaskSEW})); 1598fe6060f1SDimitry Andric return; 1599fe6060f1SDimitry Andric } 160006c3fb27SDimitry Andric case Intrinsic::riscv_vsetvli: 160106c3fb27SDimitry Andric case Intrinsic::riscv_vsetvlimax: 160204eeddc0SDimitry Andric return selectVSETVLI(Node); 1603fe6060f1SDimitry Andric } 1604fe6060f1SDimitry Andric break; 1605fe6060f1SDimitry Andric } 1606e8d8bef9SDimitry Andric case ISD::INTRINSIC_W_CHAIN: { 1607e8d8bef9SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 1608e8d8bef9SDimitry Andric switch (IntNo) { 1609e8d8bef9SDimitry Andric // By default we do not custom select any intrinsic. 1610e8d8bef9SDimitry Andric default: 16110b57cec5SDimitry Andric break; 1612e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg2: 1613e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg3: 1614e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg4: 1615e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg5: 1616e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg6: 1617e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg7: 1618e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg8: { 1619fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ false, /*IsStrided*/ false); 1620e8d8bef9SDimitry Andric return; 1621e8d8bef9SDimitry Andric } 1622e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg2_mask: 1623e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg3_mask: 1624e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg4_mask: 1625e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg5_mask: 1626e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg6_mask: 1627e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg7_mask: 1628e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg8_mask: { 1629fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ true, /*IsStrided*/ false); 1630e8d8bef9SDimitry Andric return; 1631e8d8bef9SDimitry Andric } 1632e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg2: 1633e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg3: 1634e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg4: 1635e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg5: 1636e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg6: 1637e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg7: 1638e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg8: { 1639fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ false, /*IsStrided*/ true); 1640e8d8bef9SDimitry Andric return; 1641e8d8bef9SDimitry Andric } 1642e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg2_mask: 1643e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg3_mask: 1644e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg4_mask: 1645e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg5_mask: 1646e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg6_mask: 1647e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg7_mask: 1648e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg8_mask: { 1649fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ true, /*IsStrided*/ true); 1650e8d8bef9SDimitry Andric return; 1651e8d8bef9SDimitry Andric } 1652e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg2: 1653e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg3: 1654e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg4: 1655e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg5: 1656e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg6: 1657e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg7: 1658e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg8: 1659fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ true); 1660fe6060f1SDimitry Andric return; 1661e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg2: 1662e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg3: 1663e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg4: 1664e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg5: 1665e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg6: 1666e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg7: 1667fe6060f1SDimitry Andric case Intrinsic::riscv_vluxseg8: 1668fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ false); 1669e8d8bef9SDimitry Andric return; 1670e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg2_mask: 1671e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg3_mask: 1672e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg4_mask: 1673e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg5_mask: 1674e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg6_mask: 1675e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg7_mask: 1676e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg8_mask: 1677fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ true); 1678fe6060f1SDimitry Andric return; 1679e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg2_mask: 1680e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg3_mask: 1681e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg4_mask: 1682e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg5_mask: 1683e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg6_mask: 1684e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg7_mask: 1685fe6060f1SDimitry Andric case Intrinsic::riscv_vluxseg8_mask: 1686fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ false); 1687fe6060f1SDimitry Andric return; 1688fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg8ff: 1689fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg7ff: 1690fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg6ff: 1691fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg5ff: 1692fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg4ff: 1693fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg3ff: 1694fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg2ff: { 1695fe6060f1SDimitry Andric selectVLSEGFF(Node, /*IsMasked*/ false); 1696fe6060f1SDimitry Andric return; 1697fe6060f1SDimitry Andric } 1698fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg8ff_mask: 1699fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg7ff_mask: 1700fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg6ff_mask: 1701fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg5ff_mask: 1702fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg4ff_mask: 1703fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg3ff_mask: 1704fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg2ff_mask: { 1705fe6060f1SDimitry Andric selectVLSEGFF(Node, /*IsMasked*/ true); 1706fe6060f1SDimitry Andric return; 1707fe6060f1SDimitry Andric } 1708fe6060f1SDimitry Andric case Intrinsic::riscv_vloxei: 1709fe6060f1SDimitry Andric case Intrinsic::riscv_vloxei_mask: 1710fe6060f1SDimitry Andric case Intrinsic::riscv_vluxei: 1711fe6060f1SDimitry Andric case Intrinsic::riscv_vluxei_mask: { 1712fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vloxei_mask || 1713fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vluxei_mask; 1714fe6060f1SDimitry Andric bool IsOrdered = IntNo == Intrinsic::riscv_vloxei || 1715fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vloxei_mask; 1716fe6060f1SDimitry Andric 1717fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1718fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1719fe6060f1SDimitry Andric 1720fe6060f1SDimitry Andric unsigned CurOp = 2; 1721fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 1722fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 1723fe6060f1SDimitry Andric 1724fe6060f1SDimitry Andric MVT IndexVT; 1725fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1726fe6060f1SDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 1727349cc55cSDimitry Andric /*IsLoad=*/true, &IndexVT); 1728fe6060f1SDimitry Andric 1729fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 1730fe6060f1SDimitry Andric "Element count mismatch"); 1731fe6060f1SDimitry Andric 1732fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1733fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 1734fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 173504eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 173604eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 173704eeddc0SDimitry Andric "values when XLEN=32"); 173804eeddc0SDimitry Andric } 1739fe6060f1SDimitry Andric const RISCV::VLX_VSXPseudo *P = RISCV::getVLXPseudo( 174006c3fb27SDimitry Andric IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 1741fe6060f1SDimitry Andric static_cast<unsigned>(IndexLMUL)); 1742fe6060f1SDimitry Andric MachineSDNode *Load = 1743fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1744fe6060f1SDimitry Andric 1745fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1746fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1747fe6060f1SDimitry Andric 1748fe6060f1SDimitry Andric ReplaceNode(Node, Load); 1749fe6060f1SDimitry Andric return; 1750fe6060f1SDimitry Andric } 1751349cc55cSDimitry Andric case Intrinsic::riscv_vlm: 1752fe6060f1SDimitry Andric case Intrinsic::riscv_vle: 1753fe6060f1SDimitry Andric case Intrinsic::riscv_vle_mask: 1754fe6060f1SDimitry Andric case Intrinsic::riscv_vlse: 1755fe6060f1SDimitry Andric case Intrinsic::riscv_vlse_mask: { 1756fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vle_mask || 1757fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vlse_mask; 1758fe6060f1SDimitry Andric bool IsStrided = 1759fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vlse || IntNo == Intrinsic::riscv_vlse_mask; 1760fe6060f1SDimitry Andric 1761fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1762fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1763fe6060f1SDimitry Andric 176406c3fb27SDimitry Andric // The riscv_vlm intrinsic are always tail agnostic and no passthru 176506c3fb27SDimitry Andric // operand at the IR level. In pseudos, they have both policy and 176606c3fb27SDimitry Andric // passthru operand. The passthru operand is needed to track the 176706c3fb27SDimitry Andric // "tail undefined" state, and the policy is there just for 176806c3fb27SDimitry Andric // for consistency - it will always be "don't care" for the 176906c3fb27SDimitry Andric // unmasked form. 177004eeddc0SDimitry Andric bool HasPassthruOperand = IntNo != Intrinsic::riscv_vlm; 177106c3fb27SDimitry Andric unsigned CurOp = 2; 1772fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 177306c3fb27SDimitry Andric if (HasPassthruOperand) 1774fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 177506c3fb27SDimitry Andric else { 177606c3fb27SDimitry Andric // We eagerly lower to implicit_def (instead of undef), as we 177706c3fb27SDimitry Andric // otherwise fail to select nodes such as: nxv1i1 = undef 177806c3fb27SDimitry Andric SDNode *Passthru = 177906c3fb27SDimitry Andric CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, VT); 178006c3fb27SDimitry Andric Operands.push_back(SDValue(Passthru, 0)); 178106c3fb27SDimitry Andric } 1782fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 1783349cc55cSDimitry Andric Operands, /*IsLoad=*/true); 1784fe6060f1SDimitry Andric 1785fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1786fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = 178706c3fb27SDimitry Andric RISCV::getVLEPseudo(IsMasked, IsStrided, /*FF*/ false, Log2SEW, 1788fe6060f1SDimitry Andric static_cast<unsigned>(LMUL)); 1789fe6060f1SDimitry Andric MachineSDNode *Load = 1790fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1791fe6060f1SDimitry Andric 1792fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1793fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1794fe6060f1SDimitry Andric 1795fe6060f1SDimitry Andric ReplaceNode(Node, Load); 1796fe6060f1SDimitry Andric return; 1797fe6060f1SDimitry Andric } 1798fe6060f1SDimitry Andric case Intrinsic::riscv_vleff: 1799fe6060f1SDimitry Andric case Intrinsic::riscv_vleff_mask: { 1800fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vleff_mask; 1801fe6060f1SDimitry Andric 1802fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1803fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1804fe6060f1SDimitry Andric 1805fe6060f1SDimitry Andric unsigned CurOp = 2; 1806fe6060f1SDimitry Andric SmallVector<SDValue, 7> Operands; 1807fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 1808fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1809349cc55cSDimitry Andric /*IsStridedOrIndexed*/ false, Operands, 1810349cc55cSDimitry Andric /*IsLoad=*/true); 1811fe6060f1SDimitry Andric 1812fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1813fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = 181406c3fb27SDimitry Andric RISCV::getVLEPseudo(IsMasked, /*Strided*/ false, /*FF*/ true, 181504eeddc0SDimitry Andric Log2SEW, static_cast<unsigned>(LMUL)); 181681ad6265SDimitry Andric MachineSDNode *Load = CurDAG->getMachineNode( 181781ad6265SDimitry Andric P->Pseudo, DL, Node->getVTList(), Operands); 1818fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1819fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1820fe6060f1SDimitry Andric 182181ad6265SDimitry Andric ReplaceNode(Node, Load); 18220b57cec5SDimitry Andric return; 18230b57cec5SDimitry Andric } 18240b57cec5SDimitry Andric } 18250b57cec5SDimitry Andric break; 18260b57cec5SDimitry Andric } 1827e8d8bef9SDimitry Andric case ISD::INTRINSIC_VOID: { 1828e8d8bef9SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 1829e8d8bef9SDimitry Andric switch (IntNo) { 1830e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg2: 1831e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg3: 1832e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg4: 1833e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg5: 1834e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg6: 1835e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg7: 1836e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg8: { 1837fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ false, /*IsStrided*/ false); 18380b57cec5SDimitry Andric return; 18390b57cec5SDimitry Andric } 1840e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg2_mask: 1841e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg3_mask: 1842e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg4_mask: 1843e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg5_mask: 1844e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg6_mask: 1845e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg7_mask: 1846e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg8_mask: { 1847fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ true, /*IsStrided*/ false); 1848e8d8bef9SDimitry Andric return; 1849e8d8bef9SDimitry Andric } 1850e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg2: 1851e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg3: 1852e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg4: 1853e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg5: 1854e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg6: 1855e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg7: 1856e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg8: { 1857fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ false, /*IsStrided*/ true); 1858e8d8bef9SDimitry Andric return; 1859e8d8bef9SDimitry Andric } 1860e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg2_mask: 1861e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg3_mask: 1862e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg4_mask: 1863e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg5_mask: 1864e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg6_mask: 1865e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg7_mask: 1866e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg8_mask: { 1867fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ true, /*IsStrided*/ true); 1868e8d8bef9SDimitry Andric return; 1869e8d8bef9SDimitry Andric } 1870e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg2: 1871e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg3: 1872e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg4: 1873e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg5: 1874e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg6: 1875e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg7: 1876e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg8: 1877fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ true); 1878fe6060f1SDimitry Andric return; 1879e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg2: 1880e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg3: 1881e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg4: 1882e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg5: 1883e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg6: 1884e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg7: 1885fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxseg8: 1886fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ false); 1887e8d8bef9SDimitry Andric return; 1888e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg2_mask: 1889e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg3_mask: 1890e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg4_mask: 1891e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg5_mask: 1892e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg6_mask: 1893e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg7_mask: 1894e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg8_mask: 1895fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ true); 1896fe6060f1SDimitry Andric return; 1897e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg2_mask: 1898e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg3_mask: 1899e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg4_mask: 1900e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg5_mask: 1901e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg6_mask: 1902e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg7_mask: 1903fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxseg8_mask: 1904fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ false); 1905fe6060f1SDimitry Andric return; 1906fe6060f1SDimitry Andric case Intrinsic::riscv_vsoxei: 1907fe6060f1SDimitry Andric case Intrinsic::riscv_vsoxei_mask: 1908fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxei: 1909fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxei_mask: { 1910fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vsoxei_mask || 1911fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsuxei_mask; 1912fe6060f1SDimitry Andric bool IsOrdered = IntNo == Intrinsic::riscv_vsoxei || 1913fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsoxei_mask; 1914fe6060f1SDimitry Andric 1915fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 1916fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1917fe6060f1SDimitry Andric 1918fe6060f1SDimitry Andric unsigned CurOp = 2; 1919fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 1920fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Store value. 1921fe6060f1SDimitry Andric 1922fe6060f1SDimitry Andric MVT IndexVT; 1923fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1924fe6060f1SDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 1925349cc55cSDimitry Andric /*IsLoad=*/false, &IndexVT); 1926fe6060f1SDimitry Andric 1927fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 1928fe6060f1SDimitry Andric "Element count mismatch"); 1929fe6060f1SDimitry Andric 1930fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1931fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 1932fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 193304eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 193404eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 193504eeddc0SDimitry Andric "values when XLEN=32"); 193604eeddc0SDimitry Andric } 1937fe6060f1SDimitry Andric const RISCV::VLX_VSXPseudo *P = RISCV::getVSXPseudo( 193806c3fb27SDimitry Andric IsMasked, IsOrdered, IndexLog2EEW, 193904eeddc0SDimitry Andric static_cast<unsigned>(LMUL), static_cast<unsigned>(IndexLMUL)); 1940fe6060f1SDimitry Andric MachineSDNode *Store = 1941fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1942fe6060f1SDimitry Andric 1943fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1944fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 1945fe6060f1SDimitry Andric 1946fe6060f1SDimitry Andric ReplaceNode(Node, Store); 1947fe6060f1SDimitry Andric return; 1948fe6060f1SDimitry Andric } 1949349cc55cSDimitry Andric case Intrinsic::riscv_vsm: 1950fe6060f1SDimitry Andric case Intrinsic::riscv_vse: 1951fe6060f1SDimitry Andric case Intrinsic::riscv_vse_mask: 1952fe6060f1SDimitry Andric case Intrinsic::riscv_vsse: 1953fe6060f1SDimitry Andric case Intrinsic::riscv_vsse_mask: { 1954fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vse_mask || 1955fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsse_mask; 1956fe6060f1SDimitry Andric bool IsStrided = 1957fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsse || IntNo == Intrinsic::riscv_vsse_mask; 1958fe6060f1SDimitry Andric 1959fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 1960fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1961fe6060f1SDimitry Andric 1962fe6060f1SDimitry Andric unsigned CurOp = 2; 1963fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 1964fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Store value. 1965fe6060f1SDimitry Andric 1966fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 1967fe6060f1SDimitry Andric Operands); 1968fe6060f1SDimitry Andric 1969fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1970fe6060f1SDimitry Andric const RISCV::VSEPseudo *P = RISCV::getVSEPseudo( 1971fe6060f1SDimitry Andric IsMasked, IsStrided, Log2SEW, static_cast<unsigned>(LMUL)); 1972fe6060f1SDimitry Andric MachineSDNode *Store = 1973fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1974fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1975fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 1976fe6060f1SDimitry Andric 1977fe6060f1SDimitry Andric ReplaceNode(Node, Store); 1978e8d8bef9SDimitry Andric return; 1979e8d8bef9SDimitry Andric } 1980e8d8bef9SDimitry Andric } 1981e8d8bef9SDimitry Andric break; 1982e8d8bef9SDimitry Andric } 1983fe6060f1SDimitry Andric case ISD::BITCAST: { 1984fe6060f1SDimitry Andric MVT SrcVT = Node->getOperand(0).getSimpleValueType(); 1985fe6060f1SDimitry Andric // Just drop bitcasts between vectors if both are fixed or both are 1986fe6060f1SDimitry Andric // scalable. 1987fe6060f1SDimitry Andric if ((VT.isScalableVector() && SrcVT.isScalableVector()) || 1988fe6060f1SDimitry Andric (VT.isFixedLengthVector() && SrcVT.isFixedLengthVector())) { 1989fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, 0), Node->getOperand(0)); 1990fe6060f1SDimitry Andric CurDAG->RemoveDeadNode(Node); 1991e8d8bef9SDimitry Andric return; 1992e8d8bef9SDimitry Andric } 1993fe6060f1SDimitry Andric break; 1994fe6060f1SDimitry Andric } 1995fe6060f1SDimitry Andric case ISD::INSERT_SUBVECTOR: { 1996fe6060f1SDimitry Andric SDValue V = Node->getOperand(0); 1997fe6060f1SDimitry Andric SDValue SubV = Node->getOperand(1); 1998fe6060f1SDimitry Andric SDLoc DL(SubV); 1999fe6060f1SDimitry Andric auto Idx = Node->getConstantOperandVal(2); 2000fe6060f1SDimitry Andric MVT SubVecVT = SubV.getSimpleValueType(); 2001fe6060f1SDimitry Andric 2002fe6060f1SDimitry Andric const RISCVTargetLowering &TLI = *Subtarget->getTargetLowering(); 2003fe6060f1SDimitry Andric MVT SubVecContainerVT = SubVecVT; 2004fe6060f1SDimitry Andric // Establish the correct scalable-vector types for any fixed-length type. 2005fe6060f1SDimitry Andric if (SubVecVT.isFixedLengthVector()) 2006fe6060f1SDimitry Andric SubVecContainerVT = TLI.getContainerForFixedLengthVector(SubVecVT); 2007fe6060f1SDimitry Andric if (VT.isFixedLengthVector()) 2008fe6060f1SDimitry Andric VT = TLI.getContainerForFixedLengthVector(VT); 2009fe6060f1SDimitry Andric 2010fe6060f1SDimitry Andric const auto *TRI = Subtarget->getRegisterInfo(); 2011fe6060f1SDimitry Andric unsigned SubRegIdx; 2012fe6060f1SDimitry Andric std::tie(SubRegIdx, Idx) = 2013fe6060f1SDimitry Andric RISCVTargetLowering::decomposeSubvectorInsertExtractToSubRegs( 2014fe6060f1SDimitry Andric VT, SubVecContainerVT, Idx, TRI); 2015fe6060f1SDimitry Andric 2016fe6060f1SDimitry Andric // If the Idx hasn't been completely eliminated then this is a subvector 2017fe6060f1SDimitry Andric // insert which doesn't naturally align to a vector register. These must 2018fe6060f1SDimitry Andric // be handled using instructions to manipulate the vector registers. 2019fe6060f1SDimitry Andric if (Idx != 0) 2020fe6060f1SDimitry Andric break; 2021fe6060f1SDimitry Andric 2022fe6060f1SDimitry Andric RISCVII::VLMUL SubVecLMUL = RISCVTargetLowering::getLMUL(SubVecContainerVT); 2023fe6060f1SDimitry Andric bool IsSubVecPartReg = SubVecLMUL == RISCVII::VLMUL::LMUL_F2 || 2024fe6060f1SDimitry Andric SubVecLMUL == RISCVII::VLMUL::LMUL_F4 || 2025fe6060f1SDimitry Andric SubVecLMUL == RISCVII::VLMUL::LMUL_F8; 2026fe6060f1SDimitry Andric (void)IsSubVecPartReg; // Silence unused variable warning without asserts. 2027fe6060f1SDimitry Andric assert((!IsSubVecPartReg || V.isUndef()) && 2028fe6060f1SDimitry Andric "Expecting lowering to have created legal INSERT_SUBVECTORs when " 2029fe6060f1SDimitry Andric "the subvector is smaller than a full-sized register"); 2030fe6060f1SDimitry Andric 2031fe6060f1SDimitry Andric // If we haven't set a SubRegIdx, then we must be going between 2032fe6060f1SDimitry Andric // equally-sized LMUL groups (e.g. VR -> VR). This can be done as a copy. 2033fe6060f1SDimitry Andric if (SubRegIdx == RISCV::NoSubRegister) { 2034fe6060f1SDimitry Andric unsigned InRegClassID = RISCVTargetLowering::getRegClassIDForVecVT(VT); 2035fe6060f1SDimitry Andric assert(RISCVTargetLowering::getRegClassIDForVecVT(SubVecContainerVT) == 2036fe6060f1SDimitry Andric InRegClassID && 2037fe6060f1SDimitry Andric "Unexpected subvector extraction"); 2038fe6060f1SDimitry Andric SDValue RC = CurDAG->getTargetConstant(InRegClassID, DL, XLenVT); 2039fe6060f1SDimitry Andric SDNode *NewNode = CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, 2040fe6060f1SDimitry Andric DL, VT, SubV, RC); 2041fe6060f1SDimitry Andric ReplaceNode(Node, NewNode); 2042fe6060f1SDimitry Andric return; 2043fe6060f1SDimitry Andric } 2044fe6060f1SDimitry Andric 2045fe6060f1SDimitry Andric SDValue Insert = CurDAG->getTargetInsertSubreg(SubRegIdx, DL, VT, V, SubV); 2046fe6060f1SDimitry Andric ReplaceNode(Node, Insert.getNode()); 2047fe6060f1SDimitry Andric return; 2048fe6060f1SDimitry Andric } 2049fe6060f1SDimitry Andric case ISD::EXTRACT_SUBVECTOR: { 2050fe6060f1SDimitry Andric SDValue V = Node->getOperand(0); 2051fe6060f1SDimitry Andric auto Idx = Node->getConstantOperandVal(1); 2052fe6060f1SDimitry Andric MVT InVT = V.getSimpleValueType(); 2053fe6060f1SDimitry Andric SDLoc DL(V); 2054fe6060f1SDimitry Andric 2055fe6060f1SDimitry Andric const RISCVTargetLowering &TLI = *Subtarget->getTargetLowering(); 2056fe6060f1SDimitry Andric MVT SubVecContainerVT = VT; 2057fe6060f1SDimitry Andric // Establish the correct scalable-vector types for any fixed-length type. 2058fe6060f1SDimitry Andric if (VT.isFixedLengthVector()) 2059fe6060f1SDimitry Andric SubVecContainerVT = TLI.getContainerForFixedLengthVector(VT); 2060fe6060f1SDimitry Andric if (InVT.isFixedLengthVector()) 2061fe6060f1SDimitry Andric InVT = TLI.getContainerForFixedLengthVector(InVT); 2062fe6060f1SDimitry Andric 2063fe6060f1SDimitry Andric const auto *TRI = Subtarget->getRegisterInfo(); 2064fe6060f1SDimitry Andric unsigned SubRegIdx; 2065fe6060f1SDimitry Andric std::tie(SubRegIdx, Idx) = 2066fe6060f1SDimitry Andric RISCVTargetLowering::decomposeSubvectorInsertExtractToSubRegs( 2067fe6060f1SDimitry Andric InVT, SubVecContainerVT, Idx, TRI); 2068fe6060f1SDimitry Andric 2069fe6060f1SDimitry Andric // If the Idx hasn't been completely eliminated then this is a subvector 2070fe6060f1SDimitry Andric // extract which doesn't naturally align to a vector register. These must 2071fe6060f1SDimitry Andric // be handled using instructions to manipulate the vector registers. 2072fe6060f1SDimitry Andric if (Idx != 0) 2073fe6060f1SDimitry Andric break; 2074fe6060f1SDimitry Andric 2075fe6060f1SDimitry Andric // If we haven't set a SubRegIdx, then we must be going between 2076fe6060f1SDimitry Andric // equally-sized LMUL types (e.g. VR -> VR). This can be done as a copy. 2077fe6060f1SDimitry Andric if (SubRegIdx == RISCV::NoSubRegister) { 2078fe6060f1SDimitry Andric unsigned InRegClassID = RISCVTargetLowering::getRegClassIDForVecVT(InVT); 2079fe6060f1SDimitry Andric assert(RISCVTargetLowering::getRegClassIDForVecVT(SubVecContainerVT) == 2080fe6060f1SDimitry Andric InRegClassID && 2081fe6060f1SDimitry Andric "Unexpected subvector extraction"); 2082fe6060f1SDimitry Andric SDValue RC = CurDAG->getTargetConstant(InRegClassID, DL, XLenVT); 2083fe6060f1SDimitry Andric SDNode *NewNode = 2084fe6060f1SDimitry Andric CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, VT, V, RC); 2085fe6060f1SDimitry Andric ReplaceNode(Node, NewNode); 2086fe6060f1SDimitry Andric return; 2087fe6060f1SDimitry Andric } 2088fe6060f1SDimitry Andric 2089fe6060f1SDimitry Andric SDValue Extract = CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, V); 2090fe6060f1SDimitry Andric ReplaceNode(Node, Extract.getNode()); 2091fe6060f1SDimitry Andric return; 2092fe6060f1SDimitry Andric } 209304eeddc0SDimitry Andric case RISCVISD::VMV_S_X_VL: 209404eeddc0SDimitry Andric case RISCVISD::VFMV_S_F_VL: 2095fe6060f1SDimitry Andric case RISCVISD::VMV_V_X_VL: 2096fe6060f1SDimitry Andric case RISCVISD::VFMV_V_F_VL: { 2097fe6060f1SDimitry Andric // Try to match splat of a scalar load to a strided load with stride of x0. 209804eeddc0SDimitry Andric bool IsScalarMove = Node->getOpcode() == RISCVISD::VMV_S_X_VL || 209904eeddc0SDimitry Andric Node->getOpcode() == RISCVISD::VFMV_S_F_VL; 2100bdd1243dSDimitry Andric if (!Node->getOperand(0).isUndef()) 210104eeddc0SDimitry Andric break; 2102bdd1243dSDimitry Andric SDValue Src = Node->getOperand(1); 2103fe6060f1SDimitry Andric auto *Ld = dyn_cast<LoadSDNode>(Src); 210406c3fb27SDimitry Andric // Can't fold load update node because the second 210506c3fb27SDimitry Andric // output is used so that load update node can't be removed. 210606c3fb27SDimitry Andric if (!Ld || Ld->isIndexed()) 2107fe6060f1SDimitry Andric break; 2108fe6060f1SDimitry Andric EVT MemVT = Ld->getMemoryVT(); 2109fe6060f1SDimitry Andric // The memory VT should be the same size as the element type. 2110fe6060f1SDimitry Andric if (MemVT.getStoreSize() != VT.getVectorElementType().getStoreSize()) 2111fe6060f1SDimitry Andric break; 2112fe6060f1SDimitry Andric if (!IsProfitableToFold(Src, Node, Node) || 2113fe6060f1SDimitry Andric !IsLegalToFold(Src, Node, Node, TM.getOptLevel())) 2114fe6060f1SDimitry Andric break; 2115fe6060f1SDimitry Andric 2116fe6060f1SDimitry Andric SDValue VL; 2117bdd1243dSDimitry Andric if (IsScalarMove) { 211804eeddc0SDimitry Andric // We could deal with more VL if we update the VSETVLI insert pass to 211904eeddc0SDimitry Andric // avoid introducing more VSETVLI. 212004eeddc0SDimitry Andric if (!isOneConstant(Node->getOperand(2))) 212104eeddc0SDimitry Andric break; 212204eeddc0SDimitry Andric selectVLOp(Node->getOperand(2), VL); 212304eeddc0SDimitry Andric } else 212481ad6265SDimitry Andric selectVLOp(Node->getOperand(2), VL); 2125fe6060f1SDimitry Andric 2126fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 2127fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(Log2SEW, DL, XLenVT); 2128fe6060f1SDimitry Andric 212906c3fb27SDimitry Andric // If VL=1, then we don't need to do a strided load and can just do a 213006c3fb27SDimitry Andric // regular load. 213106c3fb27SDimitry Andric bool IsStrided = !isOneConstant(VL); 213206c3fb27SDimitry Andric 213306c3fb27SDimitry Andric // Only do a strided load if we have optimized zero-stride vector load. 213406c3fb27SDimitry Andric if (IsStrided && !Subtarget->hasOptimizedZeroStrideLoad()) 213506c3fb27SDimitry Andric break; 213606c3fb27SDimitry Andric 21375f757f3fSDimitry Andric SmallVector<SDValue> Operands = { 21385f757f3fSDimitry Andric SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, VT), 0), 21395f757f3fSDimitry Andric Ld->getBasePtr()}; 214006c3fb27SDimitry Andric if (IsStrided) 214106c3fb27SDimitry Andric Operands.push_back(CurDAG->getRegister(RISCV::X0, XLenVT)); 214206c3fb27SDimitry Andric uint64_t Policy = RISCVII::MASK_AGNOSTIC | RISCVII::TAIL_AGNOSTIC; 214306c3fb27SDimitry Andric SDValue PolicyOp = CurDAG->getTargetConstant(Policy, DL, XLenVT); 214406c3fb27SDimitry Andric Operands.append({VL, SEW, PolicyOp, Ld->getChain()}); 2145fe6060f1SDimitry Andric 2146fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 2147fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = RISCV::getVLEPseudo( 214806c3fb27SDimitry Andric /*IsMasked*/ false, IsStrided, /*FF*/ false, 214904eeddc0SDimitry Andric Log2SEW, static_cast<unsigned>(LMUL)); 2150fe6060f1SDimitry Andric MachineSDNode *Load = 2151bdd1243dSDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, {VT, MVT::Other}, Operands); 2152bdd1243dSDimitry Andric // Update the chain. 2153bdd1243dSDimitry Andric ReplaceUses(Src.getValue(1), SDValue(Load, 1)); 2154bdd1243dSDimitry Andric // Record the mem-refs 215581ad6265SDimitry Andric CurDAG->setNodeMemRefs(Load, {Ld->getMemOperand()}); 2156bdd1243dSDimitry Andric // Replace the splat with the vlse. 2157fe6060f1SDimitry Andric ReplaceNode(Node, Load); 2158e8d8bef9SDimitry Andric return; 2159e8d8bef9SDimitry Andric } 216006c3fb27SDimitry Andric case ISD::PREFETCH: 216106c3fb27SDimitry Andric unsigned Locality = Node->getConstantOperandVal(3); 216206c3fb27SDimitry Andric if (Locality > 2) 216306c3fb27SDimitry Andric break; 216406c3fb27SDimitry Andric 216506c3fb27SDimitry Andric if (auto *LoadStoreMem = dyn_cast<MemSDNode>(Node)) { 216606c3fb27SDimitry Andric MachineMemOperand *MMO = LoadStoreMem->getMemOperand(); 216706c3fb27SDimitry Andric MMO->setFlags(MachineMemOperand::MONonTemporal); 216806c3fb27SDimitry Andric 216906c3fb27SDimitry Andric int NontemporalLevel = 0; 217006c3fb27SDimitry Andric switch (Locality) { 217106c3fb27SDimitry Andric case 0: 217206c3fb27SDimitry Andric NontemporalLevel = 3; // NTL.ALL 217306c3fb27SDimitry Andric break; 217406c3fb27SDimitry Andric case 1: 217506c3fb27SDimitry Andric NontemporalLevel = 1; // NTL.PALL 217606c3fb27SDimitry Andric break; 217706c3fb27SDimitry Andric case 2: 217806c3fb27SDimitry Andric NontemporalLevel = 0; // NTL.P1 217906c3fb27SDimitry Andric break; 218006c3fb27SDimitry Andric default: 218106c3fb27SDimitry Andric llvm_unreachable("unexpected locality value."); 218206c3fb27SDimitry Andric } 218306c3fb27SDimitry Andric 218406c3fb27SDimitry Andric if (NontemporalLevel & 0b1) 218506c3fb27SDimitry Andric MMO->setFlags(MONontemporalBit0); 218606c3fb27SDimitry Andric if (NontemporalLevel & 0b10) 218706c3fb27SDimitry Andric MMO->setFlags(MONontemporalBit1); 218806c3fb27SDimitry Andric } 218906c3fb27SDimitry Andric break; 2190e8d8bef9SDimitry Andric } 21910b57cec5SDimitry Andric 21920b57cec5SDimitry Andric // Select the default instruction. 21930b57cec5SDimitry Andric SelectCode(Node); 21940b57cec5SDimitry Andric } 21950b57cec5SDimitry Andric 21960b57cec5SDimitry Andric bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand( 21975f757f3fSDimitry Andric const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, 21985f757f3fSDimitry Andric std::vector<SDValue> &OutOps) { 219906c3fb27SDimitry Andric // Always produce a register and immediate operand, as expected by 220006c3fb27SDimitry Andric // RISCVAsmPrinter::PrintAsmMemoryOperand. 22010b57cec5SDimitry Andric switch (ConstraintID) { 22025f757f3fSDimitry Andric case InlineAsm::ConstraintCode::o: 22035f757f3fSDimitry Andric case InlineAsm::ConstraintCode::m: { 220406c3fb27SDimitry Andric SDValue Op0, Op1; 220506c3fb27SDimitry Andric bool Found = SelectAddrRegImm(Op, Op0, Op1); 220606c3fb27SDimitry Andric assert(Found && "SelectAddrRegImm should always succeed"); 220706c3fb27SDimitry Andric (void)Found; 220806c3fb27SDimitry Andric OutOps.push_back(Op0); 220906c3fb27SDimitry Andric OutOps.push_back(Op1); 22100b57cec5SDimitry Andric return false; 221106c3fb27SDimitry Andric } 22125f757f3fSDimitry Andric case InlineAsm::ConstraintCode::A: 22130b57cec5SDimitry Andric OutOps.push_back(Op); 221406c3fb27SDimitry Andric OutOps.push_back( 221506c3fb27SDimitry Andric CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getXLenVT())); 22160b57cec5SDimitry Andric return false; 22170b57cec5SDimitry Andric default: 221806c3fb27SDimitry Andric report_fatal_error("Unexpected asm memory constraint " + 221906c3fb27SDimitry Andric InlineAsm::getMemConstraintName(ConstraintID)); 22200b57cec5SDimitry Andric } 22210b57cec5SDimitry Andric 22220b57cec5SDimitry Andric return true; 22230b57cec5SDimitry Andric } 22240b57cec5SDimitry Andric 222581ad6265SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrFrameIndex(SDValue Addr, SDValue &Base, 222681ad6265SDimitry Andric SDValue &Offset) { 2227fe6060f1SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 22280b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT()); 222981ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), Subtarget->getXLenVT()); 22300b57cec5SDimitry Andric return true; 22310b57cec5SDimitry Andric } 223281ad6265SDimitry Andric 223381ad6265SDimitry Andric return false; 223481ad6265SDimitry Andric } 223581ad6265SDimitry Andric 223681ad6265SDimitry Andric // Select a frame index and an optional immediate offset from an ADD or OR. 223781ad6265SDimitry Andric bool RISCVDAGToDAGISel::SelectFrameAddrRegImm(SDValue Addr, SDValue &Base, 223881ad6265SDimitry Andric SDValue &Offset) { 223981ad6265SDimitry Andric if (SelectAddrFrameIndex(Addr, Base, Offset)) 224081ad6265SDimitry Andric return true; 224181ad6265SDimitry Andric 224281ad6265SDimitry Andric if (!CurDAG->isBaseWithConstantOffset(Addr)) 224381ad6265SDimitry Andric return false; 224481ad6265SDimitry Andric 224581ad6265SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) { 224681ad6265SDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 224781ad6265SDimitry Andric if (isInt<12>(CVal)) { 224881ad6265SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), 224981ad6265SDimitry Andric Subtarget->getXLenVT()); 225081ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(CVal, SDLoc(Addr), 225181ad6265SDimitry Andric Subtarget->getXLenVT()); 225281ad6265SDimitry Andric return true; 225381ad6265SDimitry Andric } 225481ad6265SDimitry Andric } 225581ad6265SDimitry Andric 22560b57cec5SDimitry Andric return false; 22570b57cec5SDimitry Andric } 22580b57cec5SDimitry Andric 2259753f127fSDimitry Andric // Fold constant addresses. 2260753f127fSDimitry Andric static bool selectConstantAddr(SelectionDAG *CurDAG, const SDLoc &DL, 2261753f127fSDimitry Andric const MVT VT, const RISCVSubtarget *Subtarget, 22625f757f3fSDimitry Andric SDValue Addr, SDValue &Base, SDValue &Offset, 22635f757f3fSDimitry Andric bool IsPrefetch = false) { 2264753f127fSDimitry Andric if (!isa<ConstantSDNode>(Addr)) 2265753f127fSDimitry Andric return false; 2266753f127fSDimitry Andric 2267753f127fSDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr)->getSExtValue(); 2268753f127fSDimitry Andric 2269753f127fSDimitry Andric // If the constant is a simm12, we can fold the whole constant and use X0 as 2270753f127fSDimitry Andric // the base. If the constant can be materialized with LUI+simm12, use LUI as 2271753f127fSDimitry Andric // the base. We can't use generateInstSeq because it favors LUI+ADDIW. 2272753f127fSDimitry Andric int64_t Lo12 = SignExtend64<12>(CVal); 2273753f127fSDimitry Andric int64_t Hi = (uint64_t)CVal - (uint64_t)Lo12; 2274753f127fSDimitry Andric if (!Subtarget->is64Bit() || isInt<32>(Hi)) { 22755f757f3fSDimitry Andric if (IsPrefetch && (Lo12 & 0b11111) != 0) 22765f757f3fSDimitry Andric return false; 22775f757f3fSDimitry Andric 2278753f127fSDimitry Andric if (Hi) { 2279753f127fSDimitry Andric int64_t Hi20 = (Hi >> 12) & 0xfffff; 2280753f127fSDimitry Andric Base = SDValue( 2281753f127fSDimitry Andric CurDAG->getMachineNode(RISCV::LUI, DL, VT, 2282753f127fSDimitry Andric CurDAG->getTargetConstant(Hi20, DL, VT)), 2283753f127fSDimitry Andric 0); 2284753f127fSDimitry Andric } else { 2285753f127fSDimitry Andric Base = CurDAG->getRegister(RISCV::X0, VT); 2286753f127fSDimitry Andric } 2287753f127fSDimitry Andric Offset = CurDAG->getTargetConstant(Lo12, DL, VT); 2288753f127fSDimitry Andric return true; 2289753f127fSDimitry Andric } 2290753f127fSDimitry Andric 2291753f127fSDimitry Andric // Ask how constant materialization would handle this constant. 22925f757f3fSDimitry Andric RISCVMatInt::InstSeq Seq = RISCVMatInt::generateInstSeq(CVal, *Subtarget); 2293753f127fSDimitry Andric 2294753f127fSDimitry Andric // If the last instruction would be an ADDI, we can fold its immediate and 2295753f127fSDimitry Andric // emit the rest of the sequence as the base. 2296bdd1243dSDimitry Andric if (Seq.back().getOpcode() != RISCV::ADDI) 2297753f127fSDimitry Andric return false; 2298bdd1243dSDimitry Andric Lo12 = Seq.back().getImm(); 22995f757f3fSDimitry Andric if (IsPrefetch && (Lo12 & 0b11111) != 0) 23005f757f3fSDimitry Andric return false; 2301753f127fSDimitry Andric 2302753f127fSDimitry Andric // Drop the last instruction. 2303753f127fSDimitry Andric Seq.pop_back(); 2304753f127fSDimitry Andric assert(!Seq.empty() && "Expected more instructions in sequence"); 2305753f127fSDimitry Andric 230606c3fb27SDimitry Andric Base = selectImmSeq(CurDAG, DL, VT, Seq); 2307753f127fSDimitry Andric Offset = CurDAG->getTargetConstant(Lo12, DL, VT); 2308753f127fSDimitry Andric return true; 2309753f127fSDimitry Andric } 2310753f127fSDimitry Andric 2311753f127fSDimitry Andric // Is this ADD instruction only used as the base pointer of scalar loads and 2312753f127fSDimitry Andric // stores? 2313753f127fSDimitry Andric static bool isWorthFoldingAdd(SDValue Add) { 2314bdd1243dSDimitry Andric for (auto *Use : Add->uses()) { 2315753f127fSDimitry Andric if (Use->getOpcode() != ISD::LOAD && Use->getOpcode() != ISD::STORE && 2316753f127fSDimitry Andric Use->getOpcode() != ISD::ATOMIC_LOAD && 2317753f127fSDimitry Andric Use->getOpcode() != ISD::ATOMIC_STORE) 2318753f127fSDimitry Andric return false; 2319753f127fSDimitry Andric EVT VT = cast<MemSDNode>(Use)->getMemoryVT(); 2320753f127fSDimitry Andric if (!VT.isScalarInteger() && VT != MVT::f16 && VT != MVT::f32 && 2321753f127fSDimitry Andric VT != MVT::f64) 2322753f127fSDimitry Andric return false; 2323753f127fSDimitry Andric // Don't allow stores of the value. It must be used as the address. 2324753f127fSDimitry Andric if (Use->getOpcode() == ISD::STORE && 2325753f127fSDimitry Andric cast<StoreSDNode>(Use)->getValue() == Add) 2326753f127fSDimitry Andric return false; 2327753f127fSDimitry Andric if (Use->getOpcode() == ISD::ATOMIC_STORE && 2328753f127fSDimitry Andric cast<AtomicSDNode>(Use)->getVal() == Add) 2329753f127fSDimitry Andric return false; 2330753f127fSDimitry Andric } 2331753f127fSDimitry Andric 2332fe6060f1SDimitry Andric return true; 2333e8d8bef9SDimitry Andric } 2334e8d8bef9SDimitry Andric 233506c3fb27SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrRegRegScale(SDValue Addr, 233606c3fb27SDimitry Andric unsigned MaxShiftAmount, 233706c3fb27SDimitry Andric SDValue &Base, SDValue &Index, 233806c3fb27SDimitry Andric SDValue &Scale) { 233906c3fb27SDimitry Andric EVT VT = Addr.getSimpleValueType(); 234006c3fb27SDimitry Andric auto UnwrapShl = [this, VT, MaxShiftAmount](SDValue N, SDValue &Index, 234106c3fb27SDimitry Andric SDValue &Shift) { 234206c3fb27SDimitry Andric uint64_t ShiftAmt = 0; 234306c3fb27SDimitry Andric Index = N; 234406c3fb27SDimitry Andric 234506c3fb27SDimitry Andric if (N.getOpcode() == ISD::SHL && isa<ConstantSDNode>(N.getOperand(1))) { 234606c3fb27SDimitry Andric // Only match shifts by a value in range [0, MaxShiftAmount]. 234706c3fb27SDimitry Andric if (N.getConstantOperandVal(1) <= MaxShiftAmount) { 234806c3fb27SDimitry Andric Index = N.getOperand(0); 234906c3fb27SDimitry Andric ShiftAmt = N.getConstantOperandVal(1); 235006c3fb27SDimitry Andric } 235106c3fb27SDimitry Andric } 235206c3fb27SDimitry Andric 235306c3fb27SDimitry Andric Shift = CurDAG->getTargetConstant(ShiftAmt, SDLoc(N), VT); 235406c3fb27SDimitry Andric return ShiftAmt != 0; 235506c3fb27SDimitry Andric }; 235606c3fb27SDimitry Andric 235706c3fb27SDimitry Andric if (Addr.getOpcode() == ISD::ADD) { 235806c3fb27SDimitry Andric if (auto *C1 = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { 235906c3fb27SDimitry Andric SDValue AddrB = Addr.getOperand(0); 236006c3fb27SDimitry Andric if (AddrB.getOpcode() == ISD::ADD && 236106c3fb27SDimitry Andric UnwrapShl(AddrB.getOperand(0), Index, Scale) && 236206c3fb27SDimitry Andric !isa<ConstantSDNode>(AddrB.getOperand(1)) && 236306c3fb27SDimitry Andric isInt<12>(C1->getSExtValue())) { 236406c3fb27SDimitry Andric // (add (add (shl A C2) B) C1) -> (add (add B C1) (shl A C2)) 236506c3fb27SDimitry Andric SDValue C1Val = 236606c3fb27SDimitry Andric CurDAG->getTargetConstant(C1->getZExtValue(), SDLoc(Addr), VT); 236706c3fb27SDimitry Andric Base = SDValue(CurDAG->getMachineNode(RISCV::ADDI, SDLoc(Addr), VT, 236806c3fb27SDimitry Andric AddrB.getOperand(1), C1Val), 236906c3fb27SDimitry Andric 0); 237006c3fb27SDimitry Andric return true; 237106c3fb27SDimitry Andric } 237206c3fb27SDimitry Andric } else if (UnwrapShl(Addr.getOperand(0), Index, Scale)) { 237306c3fb27SDimitry Andric Base = Addr.getOperand(1); 237406c3fb27SDimitry Andric return true; 237506c3fb27SDimitry Andric } else { 237606c3fb27SDimitry Andric UnwrapShl(Addr.getOperand(1), Index, Scale); 237706c3fb27SDimitry Andric Base = Addr.getOperand(0); 237806c3fb27SDimitry Andric return true; 237906c3fb27SDimitry Andric } 238006c3fb27SDimitry Andric } else if (UnwrapShl(Addr, Index, Scale)) { 238106c3fb27SDimitry Andric EVT VT = Addr.getValueType(); 238206c3fb27SDimitry Andric Base = CurDAG->getRegister(RISCV::X0, VT); 238306c3fb27SDimitry Andric return true; 238406c3fb27SDimitry Andric } 238506c3fb27SDimitry Andric 238606c3fb27SDimitry Andric return false; 238706c3fb27SDimitry Andric } 238806c3fb27SDimitry Andric 238981ad6265SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrRegImm(SDValue Addr, SDValue &Base, 239006c3fb27SDimitry Andric SDValue &Offset, bool IsINX) { 239181ad6265SDimitry Andric if (SelectAddrFrameIndex(Addr, Base, Offset)) 239281ad6265SDimitry Andric return true; 239381ad6265SDimitry Andric 239481ad6265SDimitry Andric SDLoc DL(Addr); 239581ad6265SDimitry Andric MVT VT = Addr.getSimpleValueType(); 239681ad6265SDimitry Andric 239781ad6265SDimitry Andric if (Addr.getOpcode() == RISCVISD::ADD_LO) { 239881ad6265SDimitry Andric Base = Addr.getOperand(0); 239981ad6265SDimitry Andric Offset = Addr.getOperand(1); 240081ad6265SDimitry Andric return true; 240181ad6265SDimitry Andric } 240281ad6265SDimitry Andric 240306c3fb27SDimitry Andric int64_t RV32ZdinxRange = IsINX ? 4 : 0; 240481ad6265SDimitry Andric if (CurDAG->isBaseWithConstantOffset(Addr)) { 240581ad6265SDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 240606c3fb27SDimitry Andric if (isInt<12>(CVal) && isInt<12>(CVal + RV32ZdinxRange)) { 240781ad6265SDimitry Andric Base = Addr.getOperand(0); 240881ad6265SDimitry Andric if (Base.getOpcode() == RISCVISD::ADD_LO) { 240981ad6265SDimitry Andric SDValue LoOperand = Base.getOperand(1); 241081ad6265SDimitry Andric if (auto *GA = dyn_cast<GlobalAddressSDNode>(LoOperand)) { 241181ad6265SDimitry Andric // If the Lo in (ADD_LO hi, lo) is a global variable's address 241281ad6265SDimitry Andric // (its low part, really), then we can rely on the alignment of that 241381ad6265SDimitry Andric // variable to provide a margin of safety before low part can overflow 241481ad6265SDimitry Andric // the 12 bits of the load/store offset. Check if CVal falls within 241581ad6265SDimitry Andric // that margin; if so (low part + CVal) can't overflow. 241681ad6265SDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 241781ad6265SDimitry Andric Align Alignment = commonAlignment( 241881ad6265SDimitry Andric GA->getGlobal()->getPointerAlignment(DL), GA->getOffset()); 241981ad6265SDimitry Andric if (CVal == 0 || Alignment > CVal) { 242081ad6265SDimitry Andric int64_t CombinedOffset = CVal + GA->getOffset(); 242181ad6265SDimitry Andric Base = Base.getOperand(0); 242281ad6265SDimitry Andric Offset = CurDAG->getTargetGlobalAddress( 242381ad6265SDimitry Andric GA->getGlobal(), SDLoc(LoOperand), LoOperand.getValueType(), 242481ad6265SDimitry Andric CombinedOffset, GA->getTargetFlags()); 242581ad6265SDimitry Andric return true; 242681ad6265SDimitry Andric } 242781ad6265SDimitry Andric } 242881ad6265SDimitry Andric } 242981ad6265SDimitry Andric 243081ad6265SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Base)) 243181ad6265SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), VT); 243281ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(CVal, DL, VT); 243381ad6265SDimitry Andric return true; 243481ad6265SDimitry Andric } 243581ad6265SDimitry Andric } 243681ad6265SDimitry Andric 243781ad6265SDimitry Andric // Handle ADD with large immediates. 243881ad6265SDimitry Andric if (Addr.getOpcode() == ISD::ADD && isa<ConstantSDNode>(Addr.getOperand(1))) { 243981ad6265SDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 244006c3fb27SDimitry Andric assert(!(isInt<12>(CVal) && isInt<12>(CVal + RV32ZdinxRange)) && 244106c3fb27SDimitry Andric "simm12 not already handled?"); 244281ad6265SDimitry Andric 2443753f127fSDimitry Andric // Handle immediates in the range [-4096,-2049] or [2048, 4094]. We can use 2444753f127fSDimitry Andric // an ADDI for part of the offset and fold the rest into the load/store. 2445753f127fSDimitry Andric // This mirrors the AddiPair PatFrag in RISCVInstrInfo.td. 244681ad6265SDimitry Andric if (isInt<12>(CVal / 2) && isInt<12>(CVal - CVal / 2)) { 244781ad6265SDimitry Andric int64_t Adj = CVal < 0 ? -2048 : 2047; 244881ad6265SDimitry Andric Base = SDValue( 244981ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::ADDI, DL, VT, Addr.getOperand(0), 245081ad6265SDimitry Andric CurDAG->getTargetConstant(Adj, DL, VT)), 245181ad6265SDimitry Andric 0); 245281ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(CVal - Adj, DL, VT); 245381ad6265SDimitry Andric return true; 245481ad6265SDimitry Andric } 2455753f127fSDimitry Andric 2456753f127fSDimitry Andric // For larger immediates, we might be able to save one instruction from 2457753f127fSDimitry Andric // constant materialization by folding the Lo12 bits of the immediate into 2458753f127fSDimitry Andric // the address. We should only do this if the ADD is only used by loads and 2459753f127fSDimitry Andric // stores that can fold the lo12 bits. Otherwise, the ADD will get iseled 2460753f127fSDimitry Andric // separately with the full materialized immediate creating extra 2461753f127fSDimitry Andric // instructions. 2462753f127fSDimitry Andric if (isWorthFoldingAdd(Addr) && 2463753f127fSDimitry Andric selectConstantAddr(CurDAG, DL, VT, Subtarget, Addr.getOperand(1), Base, 2464753f127fSDimitry Andric Offset)) { 2465753f127fSDimitry Andric // Insert an ADD instruction with the materialized Hi52 bits. 2466753f127fSDimitry Andric Base = SDValue( 2467753f127fSDimitry Andric CurDAG->getMachineNode(RISCV::ADD, DL, VT, Addr.getOperand(0), Base), 2468753f127fSDimitry Andric 0); 2469753f127fSDimitry Andric return true; 247081ad6265SDimitry Andric } 2471753f127fSDimitry Andric } 2472753f127fSDimitry Andric 2473753f127fSDimitry Andric if (selectConstantAddr(CurDAG, DL, VT, Subtarget, Addr, Base, Offset)) 2474753f127fSDimitry Andric return true; 247581ad6265SDimitry Andric 247681ad6265SDimitry Andric Base = Addr; 247781ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(0, DL, VT); 247881ad6265SDimitry Andric return true; 247981ad6265SDimitry Andric } 248081ad6265SDimitry Andric 24815f757f3fSDimitry Andric /// Similar to SelectAddrRegImm, except that the least significant 5 bits of 24825f757f3fSDimitry Andric /// Offset shoule be all zeros. 24835f757f3fSDimitry Andric bool RISCVDAGToDAGISel::SelectAddrRegImmLsb00000(SDValue Addr, SDValue &Base, 24845f757f3fSDimitry Andric SDValue &Offset) { 24855f757f3fSDimitry Andric if (SelectAddrFrameIndex(Addr, Base, Offset)) 24865f757f3fSDimitry Andric return true; 24875f757f3fSDimitry Andric 24885f757f3fSDimitry Andric SDLoc DL(Addr); 24895f757f3fSDimitry Andric MVT VT = Addr.getSimpleValueType(); 24905f757f3fSDimitry Andric 24915f757f3fSDimitry Andric if (CurDAG->isBaseWithConstantOffset(Addr)) { 24925f757f3fSDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 24935f757f3fSDimitry Andric if (isInt<12>(CVal)) { 24945f757f3fSDimitry Andric Base = Addr.getOperand(0); 24955f757f3fSDimitry Andric 24965f757f3fSDimitry Andric // Early-out if not a valid offset. 24975f757f3fSDimitry Andric if ((CVal & 0b11111) != 0) { 24985f757f3fSDimitry Andric Base = Addr; 24995f757f3fSDimitry Andric Offset = CurDAG->getTargetConstant(0, DL, VT); 25005f757f3fSDimitry Andric return true; 25015f757f3fSDimitry Andric } 25025f757f3fSDimitry Andric 25035f757f3fSDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Base)) 25045f757f3fSDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), VT); 25055f757f3fSDimitry Andric Offset = CurDAG->getTargetConstant(CVal, DL, VT); 25065f757f3fSDimitry Andric return true; 25075f757f3fSDimitry Andric } 25085f757f3fSDimitry Andric } 25095f757f3fSDimitry Andric 25105f757f3fSDimitry Andric // Handle ADD with large immediates. 25115f757f3fSDimitry Andric if (Addr.getOpcode() == ISD::ADD && isa<ConstantSDNode>(Addr.getOperand(1))) { 25125f757f3fSDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 25135f757f3fSDimitry Andric assert(!(isInt<12>(CVal) && isInt<12>(CVal)) && 25145f757f3fSDimitry Andric "simm12 not already handled?"); 25155f757f3fSDimitry Andric 25165f757f3fSDimitry Andric // Handle immediates in the range [-4096,-2049] or [2017, 4065]. We can save 25175f757f3fSDimitry Andric // one instruction by folding adjustment (-2048 or 2016) into the address. 25185f757f3fSDimitry Andric if ((-2049 >= CVal && CVal >= -4096) || (4065 >= CVal && CVal >= 2017)) { 25195f757f3fSDimitry Andric int64_t Adj = CVal < 0 ? -2048 : 2016; 25205f757f3fSDimitry Andric int64_t AdjustedOffset = CVal - Adj; 25215f757f3fSDimitry Andric Base = SDValue(CurDAG->getMachineNode( 25225f757f3fSDimitry Andric RISCV::ADDI, DL, VT, Addr.getOperand(0), 25235f757f3fSDimitry Andric CurDAG->getTargetConstant(AdjustedOffset, DL, VT)), 25245f757f3fSDimitry Andric 0); 25255f757f3fSDimitry Andric Offset = CurDAG->getTargetConstant(Adj, DL, VT); 25265f757f3fSDimitry Andric return true; 25275f757f3fSDimitry Andric } 25285f757f3fSDimitry Andric 25295f757f3fSDimitry Andric if (selectConstantAddr(CurDAG, DL, VT, Subtarget, Addr.getOperand(1), Base, 25305f757f3fSDimitry Andric Offset, true)) { 25315f757f3fSDimitry Andric // Insert an ADD instruction with the materialized Hi52 bits. 25325f757f3fSDimitry Andric Base = SDValue( 25335f757f3fSDimitry Andric CurDAG->getMachineNode(RISCV::ADD, DL, VT, Addr.getOperand(0), Base), 25345f757f3fSDimitry Andric 0); 25355f757f3fSDimitry Andric return true; 25365f757f3fSDimitry Andric } 25375f757f3fSDimitry Andric } 25385f757f3fSDimitry Andric 25395f757f3fSDimitry Andric if (selectConstantAddr(CurDAG, DL, VT, Subtarget, Addr, Base, Offset, true)) 25405f757f3fSDimitry Andric return true; 25415f757f3fSDimitry Andric 25425f757f3fSDimitry Andric Base = Addr; 25435f757f3fSDimitry Andric Offset = CurDAG->getTargetConstant(0, DL, VT); 25445f757f3fSDimitry Andric return true; 25455f757f3fSDimitry Andric } 25465f757f3fSDimitry Andric 2547fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth, 2548fe6060f1SDimitry Andric SDValue &ShAmt) { 2549bdd1243dSDimitry Andric ShAmt = N; 2550bdd1243dSDimitry Andric 25515f757f3fSDimitry Andric // Peek through zext. 25525f757f3fSDimitry Andric if (ShAmt->getOpcode() == ISD::ZERO_EXTEND) 25535f757f3fSDimitry Andric ShAmt = ShAmt.getOperand(0); 25545f757f3fSDimitry Andric 255506c3fb27SDimitry Andric // Shift instructions on RISC-V only read the lower 5 or 6 bits of the shift 2556fe6060f1SDimitry Andric // amount. If there is an AND on the shift amount, we can bypass it if it 2557fe6060f1SDimitry Andric // doesn't affect any of those bits. 25585f757f3fSDimitry Andric if (ShAmt.getOpcode() == ISD::AND && 25595f757f3fSDimitry Andric isa<ConstantSDNode>(ShAmt.getOperand(1))) { 2560bdd1243dSDimitry Andric const APInt &AndMask = ShAmt.getConstantOperandAPInt(1); 2561979e22ffSDimitry Andric 2562fe6060f1SDimitry Andric // Since the max shift amount is a power of 2 we can subtract 1 to make a 2563fe6060f1SDimitry Andric // mask that covers the bits needed to represent all shift amounts. 2564fe6060f1SDimitry Andric assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!"); 2565fe6060f1SDimitry Andric APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1); 2566e8d8bef9SDimitry Andric 2567fe6060f1SDimitry Andric if (ShMask.isSubsetOf(AndMask)) { 2568bdd1243dSDimitry Andric ShAmt = ShAmt.getOperand(0); 2569bdd1243dSDimitry Andric } else { 2570fe6060f1SDimitry Andric // SimplifyDemandedBits may have optimized the mask so try restoring any 2571fe6060f1SDimitry Andric // bits that are known zero. 2572bdd1243dSDimitry Andric KnownBits Known = CurDAG->computeKnownBits(ShAmt.getOperand(0)); 2573bdd1243dSDimitry Andric if (!ShMask.isSubsetOf(AndMask | Known.Zero)) 2574bdd1243dSDimitry Andric return true; 2575bdd1243dSDimitry Andric ShAmt = ShAmt.getOperand(0); 2576bdd1243dSDimitry Andric } 2577bdd1243dSDimitry Andric } 2578bdd1243dSDimitry Andric 2579bdd1243dSDimitry Andric if (ShAmt.getOpcode() == ISD::ADD && 2580bdd1243dSDimitry Andric isa<ConstantSDNode>(ShAmt.getOperand(1))) { 2581bdd1243dSDimitry Andric uint64_t Imm = ShAmt.getConstantOperandVal(1); 2582bdd1243dSDimitry Andric // If we are shifting by X+N where N == 0 mod Size, then just shift by X 2583bdd1243dSDimitry Andric // to avoid the ADD. 2584bdd1243dSDimitry Andric if (Imm != 0 && Imm % ShiftWidth == 0) { 2585bdd1243dSDimitry Andric ShAmt = ShAmt.getOperand(0); 2586fe6060f1SDimitry Andric return true; 2587fe6060f1SDimitry Andric } 2588bdd1243dSDimitry Andric } else if (ShAmt.getOpcode() == ISD::SUB && 2589bdd1243dSDimitry Andric isa<ConstantSDNode>(ShAmt.getOperand(0))) { 2590bdd1243dSDimitry Andric uint64_t Imm = ShAmt.getConstantOperandVal(0); 259181ad6265SDimitry Andric // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to 259281ad6265SDimitry Andric // generate a NEG instead of a SUB of a constant. 259381ad6265SDimitry Andric if (Imm != 0 && Imm % ShiftWidth == 0) { 2594bdd1243dSDimitry Andric SDLoc DL(ShAmt); 2595bdd1243dSDimitry Andric EVT VT = ShAmt.getValueType(); 259681ad6265SDimitry Andric SDValue Zero = CurDAG->getRegister(RISCV::X0, VT); 259781ad6265SDimitry Andric unsigned NegOpc = VT == MVT::i64 ? RISCV::SUBW : RISCV::SUB; 259881ad6265SDimitry Andric MachineSDNode *Neg = CurDAG->getMachineNode(NegOpc, DL, VT, Zero, 2599bdd1243dSDimitry Andric ShAmt.getOperand(1)); 260081ad6265SDimitry Andric ShAmt = SDValue(Neg, 0); 260181ad6265SDimitry Andric return true; 260281ad6265SDimitry Andric } 2603bdd1243dSDimitry Andric // If we are shifting by N-X where N == -1 mod Size, then just shift by ~X 2604bdd1243dSDimitry Andric // to generate a NOT instead of a SUB of a constant. 2605bdd1243dSDimitry Andric if (Imm % ShiftWidth == ShiftWidth - 1) { 2606bdd1243dSDimitry Andric SDLoc DL(ShAmt); 2607bdd1243dSDimitry Andric EVT VT = ShAmt.getValueType(); 2608bdd1243dSDimitry Andric MachineSDNode *Not = 2609bdd1243dSDimitry Andric CurDAG->getMachineNode(RISCV::XORI, DL, VT, ShAmt.getOperand(1), 2610bdd1243dSDimitry Andric CurDAG->getTargetConstant(-1, DL, VT)); 2611bdd1243dSDimitry Andric ShAmt = SDValue(Not, 0); 2612bdd1243dSDimitry Andric return true; 2613bdd1243dSDimitry Andric } 2614fe6060f1SDimitry Andric } 2615fe6060f1SDimitry Andric 2616fe6060f1SDimitry Andric return true; 2617fe6060f1SDimitry Andric } 2618fe6060f1SDimitry Andric 261906c3fb27SDimitry Andric /// RISC-V doesn't have general instructions for integer setne/seteq, but we can 262006c3fb27SDimitry Andric /// check for equality with 0. This function emits instructions that convert the 262106c3fb27SDimitry Andric /// seteq/setne into something that can be compared with 0. 262206c3fb27SDimitry Andric /// \p ExpectedCCVal indicates the condition code to attempt to match (e.g. 262306c3fb27SDimitry Andric /// ISD::SETNE). 262406c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectSETCC(SDValue N, ISD::CondCode ExpectedCCVal, 262506c3fb27SDimitry Andric SDValue &Val) { 262606c3fb27SDimitry Andric assert(ISD::isIntEqualitySetCC(ExpectedCCVal) && 262706c3fb27SDimitry Andric "Unexpected condition code!"); 262806c3fb27SDimitry Andric 262906c3fb27SDimitry Andric // We're looking for a setcc. 263006c3fb27SDimitry Andric if (N->getOpcode() != ISD::SETCC) 263106c3fb27SDimitry Andric return false; 263206c3fb27SDimitry Andric 263306c3fb27SDimitry Andric // Must be an equality comparison. 263406c3fb27SDimitry Andric ISD::CondCode CCVal = cast<CondCodeSDNode>(N->getOperand(2))->get(); 263506c3fb27SDimitry Andric if (CCVal != ExpectedCCVal) 263606c3fb27SDimitry Andric return false; 263706c3fb27SDimitry Andric 263806c3fb27SDimitry Andric SDValue LHS = N->getOperand(0); 263906c3fb27SDimitry Andric SDValue RHS = N->getOperand(1); 264006c3fb27SDimitry Andric 264106c3fb27SDimitry Andric if (!LHS.getValueType().isScalarInteger()) 264206c3fb27SDimitry Andric return false; 264306c3fb27SDimitry Andric 264406c3fb27SDimitry Andric // If the RHS side is 0, we don't need any extra instructions, return the LHS. 264506c3fb27SDimitry Andric if (isNullConstant(RHS)) { 264606c3fb27SDimitry Andric Val = LHS; 264706c3fb27SDimitry Andric return true; 264806c3fb27SDimitry Andric } 264906c3fb27SDimitry Andric 265006c3fb27SDimitry Andric SDLoc DL(N); 265106c3fb27SDimitry Andric 265206c3fb27SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(RHS)) { 265306c3fb27SDimitry Andric int64_t CVal = C->getSExtValue(); 265406c3fb27SDimitry Andric // If the RHS is -2048, we can use xori to produce 0 if the LHS is -2048 and 265506c3fb27SDimitry Andric // non-zero otherwise. 265606c3fb27SDimitry Andric if (CVal == -2048) { 265706c3fb27SDimitry Andric Val = 265806c3fb27SDimitry Andric SDValue(CurDAG->getMachineNode( 265906c3fb27SDimitry Andric RISCV::XORI, DL, N->getValueType(0), LHS, 266006c3fb27SDimitry Andric CurDAG->getTargetConstant(CVal, DL, N->getValueType(0))), 266106c3fb27SDimitry Andric 0); 266206c3fb27SDimitry Andric return true; 266306c3fb27SDimitry Andric } 266406c3fb27SDimitry Andric // If the RHS is [-2047,2048], we can use addi with -RHS to produce 0 if the 266506c3fb27SDimitry Andric // LHS is equal to the RHS and non-zero otherwise. 266606c3fb27SDimitry Andric if (isInt<12>(CVal) || CVal == 2048) { 266706c3fb27SDimitry Andric Val = 266806c3fb27SDimitry Andric SDValue(CurDAG->getMachineNode( 266906c3fb27SDimitry Andric RISCV::ADDI, DL, N->getValueType(0), LHS, 267006c3fb27SDimitry Andric CurDAG->getTargetConstant(-CVal, DL, N->getValueType(0))), 267106c3fb27SDimitry Andric 0); 267206c3fb27SDimitry Andric return true; 267306c3fb27SDimitry Andric } 267406c3fb27SDimitry Andric } 267506c3fb27SDimitry Andric 267606c3fb27SDimitry Andric // If nothing else we can XOR the LHS and RHS to produce zero if they are 267706c3fb27SDimitry Andric // equal and a non-zero value if they aren't. 267806c3fb27SDimitry Andric Val = SDValue( 267906c3fb27SDimitry Andric CurDAG->getMachineNode(RISCV::XOR, DL, N->getValueType(0), LHS, RHS), 0); 268006c3fb27SDimitry Andric return true; 268106c3fb27SDimitry Andric } 268206c3fb27SDimitry Andric 268306c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectSExtBits(SDValue N, unsigned Bits, SDValue &Val) { 2684fe6060f1SDimitry Andric if (N.getOpcode() == ISD::SIGN_EXTEND_INREG && 268506c3fb27SDimitry Andric cast<VTSDNode>(N.getOperand(1))->getVT().getSizeInBits() == Bits) { 2686fe6060f1SDimitry Andric Val = N.getOperand(0); 2687fe6060f1SDimitry Andric return true; 2688fe6060f1SDimitry Andric } 268906c3fb27SDimitry Andric 269006c3fb27SDimitry Andric auto UnwrapShlSra = [](SDValue N, unsigned ShiftAmt) { 269106c3fb27SDimitry Andric if (N.getOpcode() != ISD::SRA || !isa<ConstantSDNode>(N.getOperand(1))) 269206c3fb27SDimitry Andric return N; 269306c3fb27SDimitry Andric 269406c3fb27SDimitry Andric SDValue N0 = N.getOperand(0); 269506c3fb27SDimitry Andric if (N0.getOpcode() == ISD::SHL && isa<ConstantSDNode>(N0.getOperand(1)) && 269606c3fb27SDimitry Andric N.getConstantOperandVal(1) == ShiftAmt && 269706c3fb27SDimitry Andric N0.getConstantOperandVal(1) == ShiftAmt) 269806c3fb27SDimitry Andric return N0.getOperand(0); 269906c3fb27SDimitry Andric 270006c3fb27SDimitry Andric return N; 270106c3fb27SDimitry Andric }; 270206c3fb27SDimitry Andric 2703fe6060f1SDimitry Andric MVT VT = N.getSimpleValueType(); 270406c3fb27SDimitry Andric if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - Bits)) { 270506c3fb27SDimitry Andric Val = UnwrapShlSra(N, VT.getSizeInBits() - Bits); 2706fe6060f1SDimitry Andric return true; 2707fe6060f1SDimitry Andric } 2708fe6060f1SDimitry Andric 2709fe6060f1SDimitry Andric return false; 2710fe6060f1SDimitry Andric } 2711fe6060f1SDimitry Andric 2712bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::selectZExtBits(SDValue N, unsigned Bits, SDValue &Val) { 2713fe6060f1SDimitry Andric if (N.getOpcode() == ISD::AND) { 2714fe6060f1SDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1)); 2715bdd1243dSDimitry Andric if (C && C->getZExtValue() == maskTrailingOnes<uint64_t>(Bits)) { 2716fe6060f1SDimitry Andric Val = N.getOperand(0); 2717fe6060f1SDimitry Andric return true; 2718fe6060f1SDimitry Andric } 2719fe6060f1SDimitry Andric } 2720fe6060f1SDimitry Andric MVT VT = N.getSimpleValueType(); 2721bdd1243dSDimitry Andric APInt Mask = APInt::getBitsSetFrom(VT.getSizeInBits(), Bits); 2722fe6060f1SDimitry Andric if (CurDAG->MaskedValueIsZero(N, Mask)) { 2723fe6060f1SDimitry Andric Val = N; 2724fe6060f1SDimitry Andric return true; 2725fe6060f1SDimitry Andric } 2726fe6060f1SDimitry Andric 2727fe6060f1SDimitry Andric return false; 2728fe6060f1SDimitry Andric } 2729fe6060f1SDimitry Andric 2730753f127fSDimitry Andric /// Look for various patterns that can be done with a SHL that can be folded 2731753f127fSDimitry Andric /// into a SHXADD. \p ShAmt contains 1, 2, or 3 and is set based on which 2732753f127fSDimitry Andric /// SHXADD we are trying to match. 2733753f127fSDimitry Andric bool RISCVDAGToDAGISel::selectSHXADDOp(SDValue N, unsigned ShAmt, 2734753f127fSDimitry Andric SDValue &Val) { 2735753f127fSDimitry Andric if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) { 2736753f127fSDimitry Andric SDValue N0 = N.getOperand(0); 2737753f127fSDimitry Andric 2738753f127fSDimitry Andric bool LeftShift = N0.getOpcode() == ISD::SHL; 2739753f127fSDimitry Andric if ((LeftShift || N0.getOpcode() == ISD::SRL) && 2740753f127fSDimitry Andric isa<ConstantSDNode>(N0.getOperand(1))) { 2741753f127fSDimitry Andric uint64_t Mask = N.getConstantOperandVal(1); 2742753f127fSDimitry Andric unsigned C2 = N0.getConstantOperandVal(1); 2743753f127fSDimitry Andric 2744753f127fSDimitry Andric unsigned XLen = Subtarget->getXLen(); 2745753f127fSDimitry Andric if (LeftShift) 2746753f127fSDimitry Andric Mask &= maskTrailingZeros<uint64_t>(C2); 2747753f127fSDimitry Andric else 2748753f127fSDimitry Andric Mask &= maskTrailingOnes<uint64_t>(XLen - C2); 2749753f127fSDimitry Andric 2750753f127fSDimitry Andric // Look for (and (shl y, c2), c1) where c1 is a shifted mask with no 2751753f127fSDimitry Andric // leading zeros and c3 trailing zeros. We can use an SRLI by c2+c3 2752753f127fSDimitry Andric // followed by a SHXADD with c3 for the X amount. 2753753f127fSDimitry Andric if (isShiftedMask_64(Mask)) { 2754bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(Mask); 275506c3fb27SDimitry Andric unsigned Trailing = llvm::countr_zero(Mask); 2756753f127fSDimitry Andric if (LeftShift && Leading == 0 && C2 < Trailing && Trailing == ShAmt) { 2757753f127fSDimitry Andric SDLoc DL(N); 2758753f127fSDimitry Andric EVT VT = N.getValueType(); 2759753f127fSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 2760753f127fSDimitry Andric RISCV::SRLI, DL, VT, N0.getOperand(0), 2761753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)), 2762753f127fSDimitry Andric 0); 2763753f127fSDimitry Andric return true; 2764753f127fSDimitry Andric } 2765753f127fSDimitry Andric // Look for (and (shr y, c2), c1) where c1 is a shifted mask with c2 2766753f127fSDimitry Andric // leading zeros and c3 trailing zeros. We can use an SRLI by C3 2767753f127fSDimitry Andric // followed by a SHXADD using c3 for the X amount. 2768753f127fSDimitry Andric if (!LeftShift && Leading == C2 && Trailing == ShAmt) { 2769753f127fSDimitry Andric SDLoc DL(N); 2770753f127fSDimitry Andric EVT VT = N.getValueType(); 2771753f127fSDimitry Andric Val = SDValue( 2772753f127fSDimitry Andric CurDAG->getMachineNode( 2773753f127fSDimitry Andric RISCV::SRLI, DL, VT, N0.getOperand(0), 2774753f127fSDimitry Andric CurDAG->getTargetConstant(Leading + Trailing, DL, VT)), 2775753f127fSDimitry Andric 0); 2776753f127fSDimitry Andric return true; 2777753f127fSDimitry Andric } 2778753f127fSDimitry Andric } 2779753f127fSDimitry Andric } 2780753f127fSDimitry Andric } 2781753f127fSDimitry Andric 2782753f127fSDimitry Andric bool LeftShift = N.getOpcode() == ISD::SHL; 2783753f127fSDimitry Andric if ((LeftShift || N.getOpcode() == ISD::SRL) && 2784753f127fSDimitry Andric isa<ConstantSDNode>(N.getOperand(1))) { 2785753f127fSDimitry Andric SDValue N0 = N.getOperand(0); 2786753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && N0.hasOneUse() && 2787753f127fSDimitry Andric isa<ConstantSDNode>(N0.getOperand(1))) { 2788753f127fSDimitry Andric uint64_t Mask = N0.getConstantOperandVal(1); 2789753f127fSDimitry Andric if (isShiftedMask_64(Mask)) { 2790753f127fSDimitry Andric unsigned C1 = N.getConstantOperandVal(1); 2791753f127fSDimitry Andric unsigned XLen = Subtarget->getXLen(); 2792bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(Mask); 279306c3fb27SDimitry Andric unsigned Trailing = llvm::countr_zero(Mask); 2794753f127fSDimitry Andric // Look for (shl (and X, Mask), C1) where Mask has 32 leading zeros and 2795753f127fSDimitry Andric // C3 trailing zeros. If C1+C3==ShAmt we can use SRLIW+SHXADD. 2796753f127fSDimitry Andric if (LeftShift && Leading == 32 && Trailing > 0 && 2797753f127fSDimitry Andric (Trailing + C1) == ShAmt) { 2798753f127fSDimitry Andric SDLoc DL(N); 2799753f127fSDimitry Andric EVT VT = N.getValueType(); 2800753f127fSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 2801753f127fSDimitry Andric RISCV::SRLIW, DL, VT, N0.getOperand(0), 2802753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)), 2803753f127fSDimitry Andric 0); 2804753f127fSDimitry Andric return true; 2805753f127fSDimitry Andric } 2806753f127fSDimitry Andric // Look for (srl (and X, Mask), C1) where Mask has 32 leading zeros and 2807753f127fSDimitry Andric // C3 trailing zeros. If C3-C1==ShAmt we can use SRLIW+SHXADD. 2808753f127fSDimitry Andric if (!LeftShift && Leading == 32 && Trailing > C1 && 2809753f127fSDimitry Andric (Trailing - C1) == ShAmt) { 2810753f127fSDimitry Andric SDLoc DL(N); 2811753f127fSDimitry Andric EVT VT = N.getValueType(); 2812753f127fSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 2813753f127fSDimitry Andric RISCV::SRLIW, DL, VT, N0.getOperand(0), 2814753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)), 2815753f127fSDimitry Andric 0); 2816753f127fSDimitry Andric return true; 2817753f127fSDimitry Andric } 2818753f127fSDimitry Andric } 2819753f127fSDimitry Andric } 2820753f127fSDimitry Andric } 2821753f127fSDimitry Andric 2822753f127fSDimitry Andric return false; 2823753f127fSDimitry Andric } 2824753f127fSDimitry Andric 2825bdd1243dSDimitry Andric /// Look for various patterns that can be done with a SHL that can be folded 2826bdd1243dSDimitry Andric /// into a SHXADD_UW. \p ShAmt contains 1, 2, or 3 and is set based on which 2827bdd1243dSDimitry Andric /// SHXADD_UW we are trying to match. 2828bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::selectSHXADD_UWOp(SDValue N, unsigned ShAmt, 2829bdd1243dSDimitry Andric SDValue &Val) { 2830bdd1243dSDimitry Andric if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1)) && 2831bdd1243dSDimitry Andric N.hasOneUse()) { 2832bdd1243dSDimitry Andric SDValue N0 = N.getOperand(0); 2833bdd1243dSDimitry Andric if (N0.getOpcode() == ISD::SHL && isa<ConstantSDNode>(N0.getOperand(1)) && 2834bdd1243dSDimitry Andric N0.hasOneUse()) { 2835bdd1243dSDimitry Andric uint64_t Mask = N.getConstantOperandVal(1); 2836bdd1243dSDimitry Andric unsigned C2 = N0.getConstantOperandVal(1); 2837bdd1243dSDimitry Andric 2838bdd1243dSDimitry Andric Mask &= maskTrailingZeros<uint64_t>(C2); 2839bdd1243dSDimitry Andric 2840bdd1243dSDimitry Andric // Look for (and (shl y, c2), c1) where c1 is a shifted mask with 2841bdd1243dSDimitry Andric // 32-ShAmt leading zeros and c2 trailing zeros. We can use SLLI by 2842bdd1243dSDimitry Andric // c2-ShAmt followed by SHXADD_UW with ShAmt for the X amount. 2843bdd1243dSDimitry Andric if (isShiftedMask_64(Mask)) { 284406c3fb27SDimitry Andric unsigned Leading = llvm::countl_zero(Mask); 284506c3fb27SDimitry Andric unsigned Trailing = llvm::countr_zero(Mask); 2846bdd1243dSDimitry Andric if (Leading == 32 - ShAmt && Trailing == C2 && Trailing > ShAmt) { 2847bdd1243dSDimitry Andric SDLoc DL(N); 2848bdd1243dSDimitry Andric EVT VT = N.getValueType(); 2849bdd1243dSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 2850bdd1243dSDimitry Andric RISCV::SLLI, DL, VT, N0.getOperand(0), 2851bdd1243dSDimitry Andric CurDAG->getTargetConstant(C2 - ShAmt, DL, VT)), 2852bdd1243dSDimitry Andric 0); 2853bdd1243dSDimitry Andric return true; 2854bdd1243dSDimitry Andric } 2855bdd1243dSDimitry Andric } 2856bdd1243dSDimitry Andric } 2857bdd1243dSDimitry Andric } 2858bdd1243dSDimitry Andric 2859bdd1243dSDimitry Andric return false; 2860bdd1243dSDimitry Andric } 2861bdd1243dSDimitry Andric 28625f757f3fSDimitry Andric static bool vectorPseudoHasAllNBitUsers(SDNode *User, unsigned UserOpNo, 28635f757f3fSDimitry Andric unsigned Bits, 28645f757f3fSDimitry Andric const TargetInstrInfo *TII) { 28655f757f3fSDimitry Andric unsigned MCOpcode = RISCV::getRVVMCOpcode(User->getMachineOpcode()); 28665f757f3fSDimitry Andric 28675f757f3fSDimitry Andric if (!MCOpcode) 28685f757f3fSDimitry Andric return false; 28695f757f3fSDimitry Andric 28705f757f3fSDimitry Andric const MCInstrDesc &MCID = TII->get(User->getMachineOpcode()); 28715f757f3fSDimitry Andric const uint64_t TSFlags = MCID.TSFlags; 28725f757f3fSDimitry Andric if (!RISCVII::hasSEWOp(TSFlags)) 28735f757f3fSDimitry Andric return false; 28745f757f3fSDimitry Andric assert(RISCVII::hasVLOp(TSFlags)); 28755f757f3fSDimitry Andric 28765f757f3fSDimitry Andric bool HasGlueOp = User->getGluedNode() != nullptr; 28775f757f3fSDimitry Andric unsigned ChainOpIdx = User->getNumOperands() - HasGlueOp - 1; 28785f757f3fSDimitry Andric bool HasChainOp = User->getOperand(ChainOpIdx).getValueType() == MVT::Other; 28795f757f3fSDimitry Andric bool HasVecPolicyOp = RISCVII::hasVecPolicyOp(TSFlags); 28805f757f3fSDimitry Andric unsigned VLIdx = 28815f757f3fSDimitry Andric User->getNumOperands() - HasVecPolicyOp - HasChainOp - HasGlueOp - 2; 28825f757f3fSDimitry Andric const unsigned Log2SEW = User->getConstantOperandVal(VLIdx + 1); 28835f757f3fSDimitry Andric 28845f757f3fSDimitry Andric if (UserOpNo == VLIdx) 28855f757f3fSDimitry Andric return false; 28865f757f3fSDimitry Andric 28875f757f3fSDimitry Andric auto NumDemandedBits = 28885f757f3fSDimitry Andric RISCV::getVectorLowDemandedScalarBits(MCOpcode, Log2SEW); 28895f757f3fSDimitry Andric return NumDemandedBits && Bits >= *NumDemandedBits; 28905f757f3fSDimitry Andric } 28915f757f3fSDimitry Andric 2892349cc55cSDimitry Andric // Return true if all users of this SDNode* only consume the lower \p Bits. 2893349cc55cSDimitry Andric // This can be used to form W instructions for add/sub/mul/shl even when the 2894349cc55cSDimitry Andric // root isn't a sext_inreg. This can allow the ADDW/SUBW/MULW/SLLIW to CSE if 2895349cc55cSDimitry Andric // SimplifyDemandedBits has made it so some users see a sext_inreg and some 2896349cc55cSDimitry Andric // don't. The sext_inreg+add/sub/mul/shl will get selected, but still leave 2897349cc55cSDimitry Andric // the add/sub/mul/shl to become non-W instructions. By checking the users we 2898349cc55cSDimitry Andric // may be able to use a W instruction and CSE with the other instruction if 2899349cc55cSDimitry Andric // this has happened. We could try to detect that the CSE opportunity exists 2900349cc55cSDimitry Andric // before doing this, but that would be more complicated. 2901bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::hasAllNBitUsers(SDNode *Node, unsigned Bits, 2902bdd1243dSDimitry Andric const unsigned Depth) const { 2903349cc55cSDimitry Andric assert((Node->getOpcode() == ISD::ADD || Node->getOpcode() == ISD::SUB || 2904349cc55cSDimitry Andric Node->getOpcode() == ISD::MUL || Node->getOpcode() == ISD::SHL || 2905bdd1243dSDimitry Andric Node->getOpcode() == ISD::SRL || Node->getOpcode() == ISD::AND || 2906bdd1243dSDimitry Andric Node->getOpcode() == ISD::OR || Node->getOpcode() == ISD::XOR || 2907349cc55cSDimitry Andric Node->getOpcode() == ISD::SIGN_EXTEND_INREG || 2908bdd1243dSDimitry Andric isa<ConstantSDNode>(Node) || Depth != 0) && 2909349cc55cSDimitry Andric "Unexpected opcode"); 2910349cc55cSDimitry Andric 2911bdd1243dSDimitry Andric if (Depth >= SelectionDAG::MaxRecursionDepth) 2912bdd1243dSDimitry Andric return false; 2913bdd1243dSDimitry Andric 29145f757f3fSDimitry Andric // The PatFrags that call this may run before RISCVGenDAGISel.inc has checked 29155f757f3fSDimitry Andric // the VT. Ensure the type is scalar to avoid wasting time on vectors. 29165f757f3fSDimitry Andric if (Depth == 0 && !Node->getValueType(0).isScalarInteger()) 29175f757f3fSDimitry Andric return false; 29185f757f3fSDimitry Andric 2919349cc55cSDimitry Andric for (auto UI = Node->use_begin(), UE = Node->use_end(); UI != UE; ++UI) { 2920349cc55cSDimitry Andric SDNode *User = *UI; 2921349cc55cSDimitry Andric // Users of this node should have already been instruction selected 2922349cc55cSDimitry Andric if (!User->isMachineOpcode()) 2923349cc55cSDimitry Andric return false; 2924349cc55cSDimitry Andric 2925349cc55cSDimitry Andric // TODO: Add more opcodes? 2926349cc55cSDimitry Andric switch (User->getMachineOpcode()) { 2927349cc55cSDimitry Andric default: 29285f757f3fSDimitry Andric if (vectorPseudoHasAllNBitUsers(User, UI.getOperandNo(), Bits, TII)) 29295f757f3fSDimitry Andric break; 2930349cc55cSDimitry Andric return false; 2931349cc55cSDimitry Andric case RISCV::ADDW: 2932349cc55cSDimitry Andric case RISCV::ADDIW: 2933349cc55cSDimitry Andric case RISCV::SUBW: 2934349cc55cSDimitry Andric case RISCV::MULW: 2935349cc55cSDimitry Andric case RISCV::SLLW: 2936349cc55cSDimitry Andric case RISCV::SLLIW: 2937349cc55cSDimitry Andric case RISCV::SRAW: 2938349cc55cSDimitry Andric case RISCV::SRAIW: 2939349cc55cSDimitry Andric case RISCV::SRLW: 2940349cc55cSDimitry Andric case RISCV::SRLIW: 2941349cc55cSDimitry Andric case RISCV::DIVW: 2942349cc55cSDimitry Andric case RISCV::DIVUW: 2943349cc55cSDimitry Andric case RISCV::REMW: 2944349cc55cSDimitry Andric case RISCV::REMUW: 2945349cc55cSDimitry Andric case RISCV::ROLW: 2946349cc55cSDimitry Andric case RISCV::RORW: 2947349cc55cSDimitry Andric case RISCV::RORIW: 2948349cc55cSDimitry Andric case RISCV::CLZW: 2949349cc55cSDimitry Andric case RISCV::CTZW: 2950349cc55cSDimitry Andric case RISCV::CPOPW: 29511fd87a68SDimitry Andric case RISCV::SLLI_UW: 295281ad6265SDimitry Andric case RISCV::FMV_W_X: 2953349cc55cSDimitry Andric case RISCV::FCVT_H_W: 2954349cc55cSDimitry Andric case RISCV::FCVT_H_WU: 2955349cc55cSDimitry Andric case RISCV::FCVT_S_W: 2956349cc55cSDimitry Andric case RISCV::FCVT_S_WU: 2957349cc55cSDimitry Andric case RISCV::FCVT_D_W: 2958349cc55cSDimitry Andric case RISCV::FCVT_D_WU: 295906c3fb27SDimitry Andric case RISCV::TH_REVW: 296006c3fb27SDimitry Andric case RISCV::TH_SRRIW: 2961349cc55cSDimitry Andric if (Bits < 32) 2962349cc55cSDimitry Andric return false; 2963349cc55cSDimitry Andric break; 2964bdd1243dSDimitry Andric case RISCV::SLL: 2965bdd1243dSDimitry Andric case RISCV::SRA: 2966bdd1243dSDimitry Andric case RISCV::SRL: 2967bdd1243dSDimitry Andric case RISCV::ROL: 2968bdd1243dSDimitry Andric case RISCV::ROR: 2969bdd1243dSDimitry Andric case RISCV::BSET: 2970bdd1243dSDimitry Andric case RISCV::BCLR: 2971bdd1243dSDimitry Andric case RISCV::BINV: 2972bdd1243dSDimitry Andric // Shift amount operands only use log2(Xlen) bits. 2973bdd1243dSDimitry Andric if (UI.getOperandNo() != 1 || Bits < Log2_32(Subtarget->getXLen())) 2974bdd1243dSDimitry Andric return false; 2975bdd1243dSDimitry Andric break; 2976349cc55cSDimitry Andric case RISCV::SLLI: 2977349cc55cSDimitry Andric // SLLI only uses the lower (XLen - ShAmt) bits. 2978349cc55cSDimitry Andric if (Bits < Subtarget->getXLen() - User->getConstantOperandVal(1)) 2979349cc55cSDimitry Andric return false; 2980349cc55cSDimitry Andric break; 298104eeddc0SDimitry Andric case RISCV::ANDI: 2982bdd1243dSDimitry Andric if (Bits >= (unsigned)llvm::bit_width(User->getConstantOperandVal(1))) 298304eeddc0SDimitry Andric break; 2984bdd1243dSDimitry Andric goto RecCheck; 2985bdd1243dSDimitry Andric case RISCV::ORI: { 2986bdd1243dSDimitry Andric uint64_t Imm = cast<ConstantSDNode>(User->getOperand(1))->getSExtValue(); 2987bdd1243dSDimitry Andric if (Bits >= (unsigned)llvm::bit_width<uint64_t>(~Imm)) 2988bdd1243dSDimitry Andric break; 2989bdd1243dSDimitry Andric [[fallthrough]]; 2990bdd1243dSDimitry Andric } 2991bdd1243dSDimitry Andric case RISCV::AND: 2992bdd1243dSDimitry Andric case RISCV::OR: 2993bdd1243dSDimitry Andric case RISCV::XOR: 2994bdd1243dSDimitry Andric case RISCV::XORI: 2995bdd1243dSDimitry Andric case RISCV::ANDN: 2996bdd1243dSDimitry Andric case RISCV::ORN: 2997bdd1243dSDimitry Andric case RISCV::XNOR: 2998bdd1243dSDimitry Andric case RISCV::SH1ADD: 2999bdd1243dSDimitry Andric case RISCV::SH2ADD: 3000bdd1243dSDimitry Andric case RISCV::SH3ADD: 3001bdd1243dSDimitry Andric RecCheck: 3002bdd1243dSDimitry Andric if (hasAllNBitUsers(User, Bits, Depth + 1)) 3003bdd1243dSDimitry Andric break; 3004bdd1243dSDimitry Andric return false; 3005bdd1243dSDimitry Andric case RISCV::SRLI: { 3006bdd1243dSDimitry Andric unsigned ShAmt = User->getConstantOperandVal(1); 3007bdd1243dSDimitry Andric // If we are shifting right by less than Bits, and users don't demand any 3008bdd1243dSDimitry Andric // bits that were shifted into [Bits-1:0], then we can consider this as an 3009bdd1243dSDimitry Andric // N-Bit user. 3010bdd1243dSDimitry Andric if (Bits > ShAmt && hasAllNBitUsers(User, Bits - ShAmt, Depth + 1)) 3011bdd1243dSDimitry Andric break; 3012bdd1243dSDimitry Andric return false; 3013bdd1243dSDimitry Andric } 30141fd87a68SDimitry Andric case RISCV::SEXT_B: 3015bdd1243dSDimitry Andric case RISCV::PACKH: 301604eeddc0SDimitry Andric if (Bits < 8) 301704eeddc0SDimitry Andric return false; 301804eeddc0SDimitry Andric break; 30191fd87a68SDimitry Andric case RISCV::SEXT_H: 302081ad6265SDimitry Andric case RISCV::FMV_H_X: 30211fd87a68SDimitry Andric case RISCV::ZEXT_H_RV32: 30221fd87a68SDimitry Andric case RISCV::ZEXT_H_RV64: 3023bdd1243dSDimitry Andric case RISCV::PACKW: 302404eeddc0SDimitry Andric if (Bits < 16) 302504eeddc0SDimitry Andric return false; 302604eeddc0SDimitry Andric break; 3027bdd1243dSDimitry Andric case RISCV::PACK: 3028bdd1243dSDimitry Andric if (Bits < (Subtarget->getXLen() / 2)) 3029bdd1243dSDimitry Andric return false; 3030bdd1243dSDimitry Andric break; 30311fd87a68SDimitry Andric case RISCV::ADD_UW: 30321fd87a68SDimitry Andric case RISCV::SH1ADD_UW: 30331fd87a68SDimitry Andric case RISCV::SH2ADD_UW: 30341fd87a68SDimitry Andric case RISCV::SH3ADD_UW: 3035349cc55cSDimitry Andric // The first operand to add.uw/shXadd.uw is implicitly zero extended from 3036349cc55cSDimitry Andric // 32 bits. 3037349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 32) 3038349cc55cSDimitry Andric return false; 3039349cc55cSDimitry Andric break; 3040349cc55cSDimitry Andric case RISCV::SB: 3041349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 8) 3042349cc55cSDimitry Andric return false; 3043349cc55cSDimitry Andric break; 3044349cc55cSDimitry Andric case RISCV::SH: 3045349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 16) 3046349cc55cSDimitry Andric return false; 3047349cc55cSDimitry Andric break; 3048349cc55cSDimitry Andric case RISCV::SW: 3049349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 32) 3050349cc55cSDimitry Andric return false; 3051349cc55cSDimitry Andric break; 3052349cc55cSDimitry Andric } 3053349cc55cSDimitry Andric } 3054349cc55cSDimitry Andric 3055349cc55cSDimitry Andric return true; 3056349cc55cSDimitry Andric } 3057349cc55cSDimitry Andric 305806c3fb27SDimitry Andric // Select a constant that can be represented as (sign_extend(imm5) << imm2). 305906c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectSimm5Shl2(SDValue N, SDValue &Simm5, 306006c3fb27SDimitry Andric SDValue &Shl2) { 306106c3fb27SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(N)) { 306206c3fb27SDimitry Andric int64_t Offset = C->getSExtValue(); 306306c3fb27SDimitry Andric int64_t Shift; 306406c3fb27SDimitry Andric for (Shift = 0; Shift < 4; Shift++) 306506c3fb27SDimitry Andric if (isInt<5>(Offset >> Shift) && ((Offset % (1LL << Shift)) == 0)) 306606c3fb27SDimitry Andric break; 306706c3fb27SDimitry Andric 306806c3fb27SDimitry Andric // Constant cannot be encoded. 306906c3fb27SDimitry Andric if (Shift == 4) 307006c3fb27SDimitry Andric return false; 307106c3fb27SDimitry Andric 307206c3fb27SDimitry Andric EVT Ty = N->getValueType(0); 307306c3fb27SDimitry Andric Simm5 = CurDAG->getTargetConstant(Offset >> Shift, SDLoc(N), Ty); 307406c3fb27SDimitry Andric Shl2 = CurDAG->getTargetConstant(Shift, SDLoc(N), Ty); 307506c3fb27SDimitry Andric return true; 307606c3fb27SDimitry Andric } 307706c3fb27SDimitry Andric 307806c3fb27SDimitry Andric return false; 307906c3fb27SDimitry Andric } 308006c3fb27SDimitry Andric 3081fe6060f1SDimitry Andric // Select VL as a 5 bit immediate or a value that will become a register. This 3082fe6060f1SDimitry Andric // allows us to choose betwen VSETIVLI or VSETVLI later. 3083d409305fSDimitry Andric bool RISCVDAGToDAGISel::selectVLOp(SDValue N, SDValue &VL) { 3084d409305fSDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N); 308581ad6265SDimitry Andric if (C && isUInt<5>(C->getZExtValue())) { 3086fe6060f1SDimitry Andric VL = CurDAG->getTargetConstant(C->getZExtValue(), SDLoc(N), 3087fe6060f1SDimitry Andric N->getValueType(0)); 308806c3fb27SDimitry Andric } else if (C && C->isAllOnes()) { 308981ad6265SDimitry Andric // Treat all ones as VLMax. 309081ad6265SDimitry Andric VL = CurDAG->getTargetConstant(RISCV::VLMaxSentinel, SDLoc(N), 309181ad6265SDimitry Andric N->getValueType(0)); 309281ad6265SDimitry Andric } else if (isa<RegisterSDNode>(N) && 309381ad6265SDimitry Andric cast<RegisterSDNode>(N)->getReg() == RISCV::X0) { 309481ad6265SDimitry Andric // All our VL operands use an operand that allows GPRNoX0 or an immediate 309581ad6265SDimitry Andric // as the register class. Convert X0 to a special immediate to pass the 309681ad6265SDimitry Andric // MachineVerifier. This is recognized specially by the vsetvli insertion 309781ad6265SDimitry Andric // pass. 309881ad6265SDimitry Andric VL = CurDAG->getTargetConstant(RISCV::VLMaxSentinel, SDLoc(N), 309981ad6265SDimitry Andric N->getValueType(0)); 310081ad6265SDimitry Andric } else { 3101d409305fSDimitry Andric VL = N; 310281ad6265SDimitry Andric } 3103d409305fSDimitry Andric 3104d409305fSDimitry Andric return true; 3105d409305fSDimitry Andric } 3106d409305fSDimitry Andric 31075f757f3fSDimitry Andric static SDValue findVSplat(SDValue N) { 31085f757f3fSDimitry Andric if (N.getOpcode() == ISD::INSERT_SUBVECTOR) { 31095f757f3fSDimitry Andric if (!N.getOperand(0).isUndef()) 31105f757f3fSDimitry Andric return SDValue(); 31115f757f3fSDimitry Andric N = N.getOperand(1); 31125f757f3fSDimitry Andric } 31135f757f3fSDimitry Andric SDValue Splat = N; 31145f757f3fSDimitry Andric if ((Splat.getOpcode() != RISCVISD::VMV_V_X_VL && 31155f757f3fSDimitry Andric Splat.getOpcode() != RISCVISD::VMV_S_X_VL) || 31165f757f3fSDimitry Andric !Splat.getOperand(0).isUndef()) 31175f757f3fSDimitry Andric return SDValue(); 31185f757f3fSDimitry Andric assert(Splat.getNumOperands() == 3 && "Unexpected number of operands"); 31195f757f3fSDimitry Andric return Splat; 31205f757f3fSDimitry Andric } 31215f757f3fSDimitry Andric 3122e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::selectVSplat(SDValue N, SDValue &SplatVal) { 31235f757f3fSDimitry Andric SDValue Splat = findVSplat(N); 31245f757f3fSDimitry Andric if (!Splat) 3125e8d8bef9SDimitry Andric return false; 31265f757f3fSDimitry Andric 31275f757f3fSDimitry Andric SplatVal = Splat.getOperand(1); 3128979e22ffSDimitry Andric return true; 3129979e22ffSDimitry Andric } 3130e8d8bef9SDimitry Andric 31315f757f3fSDimitry Andric static bool selectVSplatImmHelper(SDValue N, SDValue &SplatVal, 3132fe6060f1SDimitry Andric SelectionDAG &DAG, 3133fe6060f1SDimitry Andric const RISCVSubtarget &Subtarget, 31345f757f3fSDimitry Andric std::function<bool(int64_t)> ValidateImm) { 31355f757f3fSDimitry Andric SDValue Splat = findVSplat(N); 31365f757f3fSDimitry Andric if (!Splat || !isa<ConstantSDNode>(Splat.getOperand(1))) 3137979e22ffSDimitry Andric return false; 3138e8d8bef9SDimitry Andric 31395f757f3fSDimitry Andric const unsigned SplatEltSize = Splat.getScalarValueSizeInBits(); 31405f757f3fSDimitry Andric assert(Subtarget.getXLenVT() == Splat.getOperand(1).getSimpleValueType() && 31415f757f3fSDimitry Andric "Unexpected splat operand type"); 3142e8d8bef9SDimitry Andric 314381ad6265SDimitry Andric // The semantics of RISCVISD::VMV_V_X_VL is that when the operand 314481ad6265SDimitry Andric // type is wider than the resulting vector element type: an implicit 314581ad6265SDimitry Andric // truncation first takes place. Therefore, perform a manual 314681ad6265SDimitry Andric // truncation/sign-extension in order to ignore any truncated bits and catch 314781ad6265SDimitry Andric // any zero-extended immediate. 3148e8d8bef9SDimitry Andric // For example, we wish to match (i8 -1) -> (XLenVT 255) as a simm5 by first 3149e8d8bef9SDimitry Andric // sign-extending to (XLenVT -1). 31505f757f3fSDimitry Andric APInt SplatConst = Splat.getConstantOperandAPInt(1).sextOrTrunc(SplatEltSize); 31515f757f3fSDimitry Andric 31525f757f3fSDimitry Andric int64_t SplatImm = SplatConst.getSExtValue(); 3153979e22ffSDimitry Andric 3154fe6060f1SDimitry Andric if (!ValidateImm(SplatImm)) 3155e8d8bef9SDimitry Andric return false; 3156979e22ffSDimitry Andric 31575f757f3fSDimitry Andric SplatVal = DAG.getTargetConstant(SplatImm, SDLoc(N), Subtarget.getXLenVT()); 3158979e22ffSDimitry Andric return true; 3159979e22ffSDimitry Andric } 3160e8d8bef9SDimitry Andric 3161fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5(SDValue N, SDValue &SplatVal) { 31625f757f3fSDimitry Andric return selectVSplatImmHelper(N, SplatVal, *CurDAG, *Subtarget, 3163fe6060f1SDimitry Andric [](int64_t Imm) { return isInt<5>(Imm); }); 3164fe6060f1SDimitry Andric } 3165fe6060f1SDimitry Andric 3166fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5Plus1(SDValue N, SDValue &SplatVal) { 31675f757f3fSDimitry Andric return selectVSplatImmHelper( 3168fe6060f1SDimitry Andric N, SplatVal, *CurDAG, *Subtarget, 3169fe6060f1SDimitry Andric [](int64_t Imm) { return (isInt<5>(Imm) && Imm != -16) || Imm == 16; }); 3170fe6060f1SDimitry Andric } 3171fe6060f1SDimitry Andric 3172fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5Plus1NonZero(SDValue N, 3173fe6060f1SDimitry Andric SDValue &SplatVal) { 31745f757f3fSDimitry Andric return selectVSplatImmHelper( 3175fe6060f1SDimitry Andric N, SplatVal, *CurDAG, *Subtarget, [](int64_t Imm) { 3176fe6060f1SDimitry Andric return Imm != 0 && ((isInt<5>(Imm) && Imm != -16) || Imm == 16); 3177fe6060f1SDimitry Andric }); 3178fe6060f1SDimitry Andric } 3179fe6060f1SDimitry Andric 318006c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatUimm(SDValue N, unsigned Bits, 318106c3fb27SDimitry Andric SDValue &SplatVal) { 31825f757f3fSDimitry Andric return selectVSplatImmHelper( 31835f757f3fSDimitry Andric N, SplatVal, *CurDAG, *Subtarget, 31845f757f3fSDimitry Andric [Bits](int64_t Imm) { return isUIntN(Bits, Imm); }); 3185979e22ffSDimitry Andric } 3186979e22ffSDimitry Andric 31875f757f3fSDimitry Andric bool RISCVDAGToDAGISel::selectLow8BitsVSplat(SDValue N, SDValue &SplatVal) { 31885f757f3fSDimitry Andric // Truncates are custom lowered during legalization. 31895f757f3fSDimitry Andric auto IsTrunc = [this](SDValue N) { 31905f757f3fSDimitry Andric if (N->getOpcode() != RISCVISD::TRUNCATE_VECTOR_VL) 31915f757f3fSDimitry Andric return false; 31925f757f3fSDimitry Andric SDValue VL; 31935f757f3fSDimitry Andric selectVLOp(N->getOperand(2), VL); 31945f757f3fSDimitry Andric // Any vmset_vl is ok, since any bits past VL are undefined and we can 31955f757f3fSDimitry Andric // assume they are set. 31965f757f3fSDimitry Andric return N->getOperand(1).getOpcode() == RISCVISD::VMSET_VL && 31975f757f3fSDimitry Andric isa<ConstantSDNode>(VL) && 31985f757f3fSDimitry Andric cast<ConstantSDNode>(VL)->getSExtValue() == RISCV::VLMaxSentinel; 31995f757f3fSDimitry Andric }; 32005f757f3fSDimitry Andric 32015f757f3fSDimitry Andric // We can have multiple nested truncates, so unravel them all if needed. 32025f757f3fSDimitry Andric while (N->getOpcode() == ISD::SIGN_EXTEND || 32035f757f3fSDimitry Andric N->getOpcode() == ISD::ZERO_EXTEND || IsTrunc(N)) { 32045f757f3fSDimitry Andric if (!N.hasOneUse() || 32055f757f3fSDimitry Andric N.getValueType().getSizeInBits().getKnownMinValue() < 8) 320606c3fb27SDimitry Andric return false; 320706c3fb27SDimitry Andric N = N->getOperand(0); 320806c3fb27SDimitry Andric } 32095f757f3fSDimitry Andric 321006c3fb27SDimitry Andric return selectVSplat(N, SplatVal); 321106c3fb27SDimitry Andric } 321206c3fb27SDimitry Andric 321306c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectFPImm(SDValue N, SDValue &Imm) { 321406c3fb27SDimitry Andric ConstantFPSDNode *CFP = dyn_cast<ConstantFPSDNode>(N.getNode()); 321506c3fb27SDimitry Andric if (!CFP) 321606c3fb27SDimitry Andric return false; 321706c3fb27SDimitry Andric const APFloat &APF = CFP->getValueAPF(); 321806c3fb27SDimitry Andric // td can handle +0.0 already. 321906c3fb27SDimitry Andric if (APF.isPosZero()) 322006c3fb27SDimitry Andric return false; 322106c3fb27SDimitry Andric 322206c3fb27SDimitry Andric MVT VT = CFP->getSimpleValueType(0); 322306c3fb27SDimitry Andric 32245f757f3fSDimitry Andric // Even if this FPImm requires an additional FNEG (i.e. the second element of 32255f757f3fSDimitry Andric // the returned pair is true) we still prefer FLI + FNEG over immediate 32265f757f3fSDimitry Andric // materialization as the latter might generate a longer instruction sequence. 32275f757f3fSDimitry Andric if (static_cast<const RISCVTargetLowering *>(TLI) 32285f757f3fSDimitry Andric ->getLegalZfaFPImm(APF, VT) 32295f757f3fSDimitry Andric .first >= 0) 323006c3fb27SDimitry Andric return false; 323106c3fb27SDimitry Andric 323206c3fb27SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 323306c3fb27SDimitry Andric if (VT == MVT::f64 && !Subtarget->is64Bit()) { 323406c3fb27SDimitry Andric assert(APF.isNegZero() && "Unexpected constant."); 323506c3fb27SDimitry Andric return false; 323606c3fb27SDimitry Andric } 323706c3fb27SDimitry Andric SDLoc DL(N); 323806c3fb27SDimitry Andric Imm = selectImm(CurDAG, DL, XLenVT, APF.bitcastToAPInt().getSExtValue(), 323906c3fb27SDimitry Andric *Subtarget); 324006c3fb27SDimitry Andric return true; 324106c3fb27SDimitry Andric } 324206c3fb27SDimitry Andric 3243fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectRVVSimm5(SDValue N, unsigned Width, 3244fe6060f1SDimitry Andric SDValue &Imm) { 3245fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(N)) { 3246fe6060f1SDimitry Andric int64_t ImmVal = SignExtend64(C->getSExtValue(), Width); 3247fe6060f1SDimitry Andric 3248fe6060f1SDimitry Andric if (!isInt<5>(ImmVal)) 3249fe6060f1SDimitry Andric return false; 3250fe6060f1SDimitry Andric 3251fe6060f1SDimitry Andric Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), Subtarget->getXLenVT()); 3252fe6060f1SDimitry Andric return true; 3253fe6060f1SDimitry Andric } 3254fe6060f1SDimitry Andric 3255fe6060f1SDimitry Andric return false; 3256fe6060f1SDimitry Andric } 3257fe6060f1SDimitry Andric 3258349cc55cSDimitry Andric // Try to remove sext.w if the input is a W instruction or can be made into 3259349cc55cSDimitry Andric // a W instruction cheaply. 3260349cc55cSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeSExtW(SDNode *N) { 3261349cc55cSDimitry Andric // Look for the sext.w pattern, addiw rd, rs1, 0. 3262349cc55cSDimitry Andric if (N->getMachineOpcode() != RISCV::ADDIW || 3263349cc55cSDimitry Andric !isNullConstant(N->getOperand(1))) 3264349cc55cSDimitry Andric return false; 3265349cc55cSDimitry Andric 3266349cc55cSDimitry Andric SDValue N0 = N->getOperand(0); 3267349cc55cSDimitry Andric if (!N0.isMachineOpcode()) 3268349cc55cSDimitry Andric return false; 3269349cc55cSDimitry Andric 3270349cc55cSDimitry Andric switch (N0.getMachineOpcode()) { 3271349cc55cSDimitry Andric default: 3272349cc55cSDimitry Andric break; 3273349cc55cSDimitry Andric case RISCV::ADD: 3274349cc55cSDimitry Andric case RISCV::ADDI: 3275349cc55cSDimitry Andric case RISCV::SUB: 3276349cc55cSDimitry Andric case RISCV::MUL: 3277349cc55cSDimitry Andric case RISCV::SLLI: { 3278349cc55cSDimitry Andric // Convert sext.w+add/sub/mul to their W instructions. This will create 3279349cc55cSDimitry Andric // a new independent instruction. This improves latency. 3280349cc55cSDimitry Andric unsigned Opc; 3281349cc55cSDimitry Andric switch (N0.getMachineOpcode()) { 3282349cc55cSDimitry Andric default: 3283349cc55cSDimitry Andric llvm_unreachable("Unexpected opcode!"); 3284349cc55cSDimitry Andric case RISCV::ADD: Opc = RISCV::ADDW; break; 3285349cc55cSDimitry Andric case RISCV::ADDI: Opc = RISCV::ADDIW; break; 3286349cc55cSDimitry Andric case RISCV::SUB: Opc = RISCV::SUBW; break; 3287349cc55cSDimitry Andric case RISCV::MUL: Opc = RISCV::MULW; break; 3288349cc55cSDimitry Andric case RISCV::SLLI: Opc = RISCV::SLLIW; break; 3289349cc55cSDimitry Andric } 3290349cc55cSDimitry Andric 3291349cc55cSDimitry Andric SDValue N00 = N0.getOperand(0); 3292349cc55cSDimitry Andric SDValue N01 = N0.getOperand(1); 3293349cc55cSDimitry Andric 3294349cc55cSDimitry Andric // Shift amount needs to be uimm5. 3295349cc55cSDimitry Andric if (N0.getMachineOpcode() == RISCV::SLLI && 3296349cc55cSDimitry Andric !isUInt<5>(cast<ConstantSDNode>(N01)->getSExtValue())) 3297349cc55cSDimitry Andric break; 3298349cc55cSDimitry Andric 3299349cc55cSDimitry Andric SDNode *Result = 3300349cc55cSDimitry Andric CurDAG->getMachineNode(Opc, SDLoc(N), N->getValueType(0), 3301349cc55cSDimitry Andric N00, N01); 3302349cc55cSDimitry Andric ReplaceUses(N, Result); 3303349cc55cSDimitry Andric return true; 3304349cc55cSDimitry Andric } 3305349cc55cSDimitry Andric case RISCV::ADDW: 3306349cc55cSDimitry Andric case RISCV::ADDIW: 3307349cc55cSDimitry Andric case RISCV::SUBW: 3308349cc55cSDimitry Andric case RISCV::MULW: 3309349cc55cSDimitry Andric case RISCV::SLLIW: 3310bdd1243dSDimitry Andric case RISCV::PACKW: 331106c3fb27SDimitry Andric case RISCV::TH_MULAW: 331206c3fb27SDimitry Andric case RISCV::TH_MULAH: 331306c3fb27SDimitry Andric case RISCV::TH_MULSW: 331406c3fb27SDimitry Andric case RISCV::TH_MULSH: 33155f757f3fSDimitry Andric if (N0.getValueType() == MVT::i32) 33165f757f3fSDimitry Andric break; 33175f757f3fSDimitry Andric 3318349cc55cSDimitry Andric // Result is already sign extended just remove the sext.w. 3319349cc55cSDimitry Andric // NOTE: We only handle the nodes that are selected with hasAllWUsers. 3320349cc55cSDimitry Andric ReplaceUses(N, N0.getNode()); 3321349cc55cSDimitry Andric return true; 3322349cc55cSDimitry Andric } 3323349cc55cSDimitry Andric 3324349cc55cSDimitry Andric return false; 33250b57cec5SDimitry Andric } 33260b57cec5SDimitry Andric 332706c3fb27SDimitry Andric static bool usesAllOnesMask(SDValue MaskOp, SDValue GlueOp) { 332881ad6265SDimitry Andric // Check that we're using V0 as a mask register. 332906c3fb27SDimitry Andric if (!isa<RegisterSDNode>(MaskOp) || 333006c3fb27SDimitry Andric cast<RegisterSDNode>(MaskOp)->getReg() != RISCV::V0) 333181ad6265SDimitry Andric return false; 333281ad6265SDimitry Andric 333381ad6265SDimitry Andric // The glued user defines V0. 333406c3fb27SDimitry Andric const auto *Glued = GlueOp.getNode(); 333581ad6265SDimitry Andric 333681ad6265SDimitry Andric if (!Glued || Glued->getOpcode() != ISD::CopyToReg) 333781ad6265SDimitry Andric return false; 333881ad6265SDimitry Andric 333981ad6265SDimitry Andric // Check that we're defining V0 as a mask register. 334081ad6265SDimitry Andric if (!isa<RegisterSDNode>(Glued->getOperand(1)) || 334181ad6265SDimitry Andric cast<RegisterSDNode>(Glued->getOperand(1))->getReg() != RISCV::V0) 334281ad6265SDimitry Andric return false; 334381ad6265SDimitry Andric 334481ad6265SDimitry Andric // Check the instruction defining V0; it needs to be a VMSET pseudo. 334581ad6265SDimitry Andric SDValue MaskSetter = Glued->getOperand(2); 334681ad6265SDimitry Andric 33475f757f3fSDimitry Andric // Sometimes the VMSET is wrapped in a COPY_TO_REGCLASS, e.g. if the mask came 33485f757f3fSDimitry Andric // from an extract_subvector or insert_subvector. 33495f757f3fSDimitry Andric if (MaskSetter->isMachineOpcode() && 33505f757f3fSDimitry Andric MaskSetter->getMachineOpcode() == RISCV::COPY_TO_REGCLASS) 33515f757f3fSDimitry Andric MaskSetter = MaskSetter->getOperand(0); 33525f757f3fSDimitry Andric 335381ad6265SDimitry Andric const auto IsVMSet = [](unsigned Opc) { 335481ad6265SDimitry Andric return Opc == RISCV::PseudoVMSET_M_B1 || Opc == RISCV::PseudoVMSET_M_B16 || 335581ad6265SDimitry Andric Opc == RISCV::PseudoVMSET_M_B2 || Opc == RISCV::PseudoVMSET_M_B32 || 335681ad6265SDimitry Andric Opc == RISCV::PseudoVMSET_M_B4 || Opc == RISCV::PseudoVMSET_M_B64 || 335781ad6265SDimitry Andric Opc == RISCV::PseudoVMSET_M_B8; 335881ad6265SDimitry Andric }; 335981ad6265SDimitry Andric 336081ad6265SDimitry Andric // TODO: Check that the VMSET is the expected bitwidth? The pseudo has 336181ad6265SDimitry Andric // undefined behaviour if it's the wrong bitwidth, so we could choose to 336281ad6265SDimitry Andric // assume that it's all-ones? Same applies to its VL. 3363bdd1243dSDimitry Andric return MaskSetter->isMachineOpcode() && 3364bdd1243dSDimitry Andric IsVMSet(MaskSetter.getMachineOpcode()); 3365bdd1243dSDimitry Andric } 3366bdd1243dSDimitry Andric 336706c3fb27SDimitry Andric // Return true if we can make sure mask of N is all-ones mask. 336806c3fb27SDimitry Andric static bool usesAllOnesMask(SDNode *N, unsigned MaskOpIdx) { 336906c3fb27SDimitry Andric return usesAllOnesMask(N->getOperand(MaskOpIdx), 337006c3fb27SDimitry Andric N->getOperand(N->getNumOperands() - 1)); 337106c3fb27SDimitry Andric } 337206c3fb27SDimitry Andric 337306c3fb27SDimitry Andric static bool isImplicitDef(SDValue V) { 337406c3fb27SDimitry Andric return V.isMachineOpcode() && 337506c3fb27SDimitry Andric V.getMachineOpcode() == TargetOpcode::IMPLICIT_DEF; 337606c3fb27SDimitry Andric } 337706c3fb27SDimitry Andric 3378bdd1243dSDimitry Andric // Optimize masked RVV pseudo instructions with a known all-ones mask to their 3379bdd1243dSDimitry Andric // corresponding "unmasked" pseudo versions. The mask we're interested in will 3380bdd1243dSDimitry Andric // take the form of a V0 physical register operand, with a glued 3381bdd1243dSDimitry Andric // register-setting instruction. 33825f757f3fSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeMaskedRVV(MachineSDNode *N) { 3383bdd1243dSDimitry Andric const RISCV::RISCVMaskedPseudoInfo *I = 3384bdd1243dSDimitry Andric RISCV::getMaskedPseudoInfo(N->getMachineOpcode()); 3385bdd1243dSDimitry Andric if (!I) 3386bdd1243dSDimitry Andric return false; 3387bdd1243dSDimitry Andric 3388bdd1243dSDimitry Andric unsigned MaskOpIdx = I->MaskOpIdx; 3389bdd1243dSDimitry Andric if (!usesAllOnesMask(N, MaskOpIdx)) 339081ad6265SDimitry Andric return false; 339181ad6265SDimitry Andric 339206c3fb27SDimitry Andric // There are two classes of pseudos in the table - compares and 339306c3fb27SDimitry Andric // everything else. See the comment on RISCVMaskedPseudo for details. 339406c3fb27SDimitry Andric const unsigned Opc = I->UnmaskedPseudo; 339506c3fb27SDimitry Andric const MCInstrDesc &MCID = TII->get(Opc); 339606c3fb27SDimitry Andric const bool UseTUPseudo = RISCVII::hasVecPolicyOp(MCID.TSFlags); 339706c3fb27SDimitry Andric #ifndef NDEBUG 339806c3fb27SDimitry Andric const MCInstrDesc &MaskedMCID = TII->get(N->getMachineOpcode()); 339906c3fb27SDimitry Andric assert(RISCVII::hasVecPolicyOp(MaskedMCID.TSFlags) == 340006c3fb27SDimitry Andric RISCVII::hasVecPolicyOp(MCID.TSFlags) && 340106c3fb27SDimitry Andric "Masked and unmasked pseudos are inconsistent"); 340206c3fb27SDimitry Andric const bool HasTiedDest = RISCVII::isFirstDefTiedToFirstUse(MCID); 340306c3fb27SDimitry Andric assert(UseTUPseudo == HasTiedDest && "Unexpected pseudo structure"); 340406c3fb27SDimitry Andric #endif 340581ad6265SDimitry Andric 340681ad6265SDimitry Andric SmallVector<SDValue, 8> Ops; 340706c3fb27SDimitry Andric // Skip the merge operand at index 0 if !UseTUPseudo. 340806c3fb27SDimitry Andric for (unsigned I = !UseTUPseudo, E = N->getNumOperands(); I != E; I++) { 340906c3fb27SDimitry Andric // Skip the mask, and the Glue. 341081ad6265SDimitry Andric SDValue Op = N->getOperand(I); 341106c3fb27SDimitry Andric if (I == MaskOpIdx || Op.getValueType() == MVT::Glue) 341281ad6265SDimitry Andric continue; 341381ad6265SDimitry Andric Ops.push_back(Op); 341481ad6265SDimitry Andric } 341581ad6265SDimitry Andric 341681ad6265SDimitry Andric // Transitively apply any node glued to our new node. 3417bdd1243dSDimitry Andric const auto *Glued = N->getGluedNode(); 341881ad6265SDimitry Andric if (auto *TGlued = Glued->getGluedNode()) 341981ad6265SDimitry Andric Ops.push_back(SDValue(TGlued, TGlued->getNumValues() - 1)); 342081ad6265SDimitry Andric 34215f757f3fSDimitry Andric MachineSDNode *Result = 34225f757f3fSDimitry Andric CurDAG->getMachineNode(Opc, SDLoc(N), N->getVTList(), Ops); 34235f757f3fSDimitry Andric 34245f757f3fSDimitry Andric if (!N->memoperands_empty()) 34255f757f3fSDimitry Andric CurDAG->setNodeMemRefs(Result, N->memoperands()); 34265f757f3fSDimitry Andric 3427bdd1243dSDimitry Andric Result->setFlags(N->getFlags()); 342881ad6265SDimitry Andric ReplaceUses(N, Result); 342981ad6265SDimitry Andric 343081ad6265SDimitry Andric return true; 343181ad6265SDimitry Andric } 343281ad6265SDimitry Andric 343306c3fb27SDimitry Andric static bool IsVMerge(SDNode *N) { 34345f757f3fSDimitry Andric return RISCV::getRVVMCOpcode(N->getMachineOpcode()) == RISCV::VMERGE_VVM; 343506c3fb27SDimitry Andric } 3436bdd1243dSDimitry Andric 343706c3fb27SDimitry Andric static bool IsVMv(SDNode *N) { 34385f757f3fSDimitry Andric return RISCV::getRVVMCOpcode(N->getMachineOpcode()) == RISCV::VMV_V_V; 343906c3fb27SDimitry Andric } 344006c3fb27SDimitry Andric 344106c3fb27SDimitry Andric static unsigned GetVMSetForLMul(RISCVII::VLMUL LMUL) { 344206c3fb27SDimitry Andric switch (LMUL) { 344306c3fb27SDimitry Andric case RISCVII::LMUL_F8: 344406c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B1; 344506c3fb27SDimitry Andric case RISCVII::LMUL_F4: 344606c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B2; 344706c3fb27SDimitry Andric case RISCVII::LMUL_F2: 344806c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B4; 344906c3fb27SDimitry Andric case RISCVII::LMUL_1: 345006c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B8; 345106c3fb27SDimitry Andric case RISCVII::LMUL_2: 345206c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B16; 345306c3fb27SDimitry Andric case RISCVII::LMUL_4: 345406c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B32; 345506c3fb27SDimitry Andric case RISCVII::LMUL_8: 345606c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B64; 345706c3fb27SDimitry Andric case RISCVII::LMUL_RESERVED: 345806c3fb27SDimitry Andric llvm_unreachable("Unexpected LMUL"); 345906c3fb27SDimitry Andric } 346006c3fb27SDimitry Andric llvm_unreachable("Unknown VLMUL enum"); 346106c3fb27SDimitry Andric } 346206c3fb27SDimitry Andric 346306c3fb27SDimitry Andric // Try to fold away VMERGE_VVM instructions. We handle these cases: 346406c3fb27SDimitry Andric // -Masked TU VMERGE_VVM combined with an unmasked TA instruction instruction 346506c3fb27SDimitry Andric // folds to a masked TU instruction. VMERGE_VVM must have have merge operand 346606c3fb27SDimitry Andric // same as false operand. 346706c3fb27SDimitry Andric // -Masked TA VMERGE_VVM combined with an unmasked TA instruction fold to a 346806c3fb27SDimitry Andric // masked TA instruction. 346906c3fb27SDimitry Andric // -Unmasked TU VMERGE_VVM combined with a masked MU TA instruction folds to 347006c3fb27SDimitry Andric // masked TU instruction. Both instructions must have the same merge operand. 347106c3fb27SDimitry Andric // VMERGE_VVM must have have merge operand same as false operand. 347206c3fb27SDimitry Andric // Note: The VMERGE_VVM forms above (TA, and TU) refer to the policy implied, 347306c3fb27SDimitry Andric // not the pseudo name. That is, a TA VMERGE_VVM can be either the _TU pseudo 347406c3fb27SDimitry Andric // form with an IMPLICIT_DEF passthrough operand or the unsuffixed (TA) pseudo 347506c3fb27SDimitry Andric // form. 347606c3fb27SDimitry Andric bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) { 347706c3fb27SDimitry Andric SDValue Merge, False, True, VL, Mask, Glue; 347806c3fb27SDimitry Andric // A vmv.v.v is equivalent to a vmerge with an all-ones mask. 347906c3fb27SDimitry Andric if (IsVMv(N)) { 348006c3fb27SDimitry Andric Merge = N->getOperand(0); 348106c3fb27SDimitry Andric False = N->getOperand(0); 348206c3fb27SDimitry Andric True = N->getOperand(1); 348306c3fb27SDimitry Andric VL = N->getOperand(2); 348406c3fb27SDimitry Andric // A vmv.v.v won't have a Mask or Glue, instead we'll construct an all-ones 348506c3fb27SDimitry Andric // mask later below. 348606c3fb27SDimitry Andric } else { 348706c3fb27SDimitry Andric assert(IsVMerge(N)); 348806c3fb27SDimitry Andric Merge = N->getOperand(0); 348906c3fb27SDimitry Andric False = N->getOperand(1); 349006c3fb27SDimitry Andric True = N->getOperand(2); 349106c3fb27SDimitry Andric Mask = N->getOperand(3); 349206c3fb27SDimitry Andric VL = N->getOperand(4); 349306c3fb27SDimitry Andric // We always have a glue node for the mask at v0. 349406c3fb27SDimitry Andric Glue = N->getOperand(N->getNumOperands() - 1); 349506c3fb27SDimitry Andric } 349606c3fb27SDimitry Andric assert(!Mask || cast<RegisterSDNode>(Mask)->getReg() == RISCV::V0); 349706c3fb27SDimitry Andric assert(!Glue || Glue.getValueType() == MVT::Glue); 349806c3fb27SDimitry Andric 349906c3fb27SDimitry Andric // We require that either merge and false are the same, or that merge 350006c3fb27SDimitry Andric // is undefined. 350106c3fb27SDimitry Andric if (Merge != False && !isImplicitDef(Merge)) 350206c3fb27SDimitry Andric return false; 3503bdd1243dSDimitry Andric 3504bdd1243dSDimitry Andric assert(True.getResNo() == 0 && 3505bdd1243dSDimitry Andric "Expect True is the first output of an instruction."); 3506bdd1243dSDimitry Andric 3507bdd1243dSDimitry Andric // Need N is the exactly one using True. 3508bdd1243dSDimitry Andric if (!True.hasOneUse()) 3509bdd1243dSDimitry Andric return false; 3510bdd1243dSDimitry Andric 3511bdd1243dSDimitry Andric if (!True.isMachineOpcode()) 3512bdd1243dSDimitry Andric return false; 3513bdd1243dSDimitry Andric 3514bdd1243dSDimitry Andric unsigned TrueOpc = True.getMachineOpcode(); 351506c3fb27SDimitry Andric const MCInstrDesc &TrueMCID = TII->get(TrueOpc); 351606c3fb27SDimitry Andric uint64_t TrueTSFlags = TrueMCID.TSFlags; 351706c3fb27SDimitry Andric bool HasTiedDest = RISCVII::isFirstDefTiedToFirstUse(TrueMCID); 3518bdd1243dSDimitry Andric 351906c3fb27SDimitry Andric bool IsMasked = false; 3520bdd1243dSDimitry Andric const RISCV::RISCVMaskedPseudoInfo *Info = 352106c3fb27SDimitry Andric RISCV::lookupMaskedIntrinsicByUnmasked(TrueOpc); 352206c3fb27SDimitry Andric if (!Info && HasTiedDest) { 352306c3fb27SDimitry Andric Info = RISCV::getMaskedPseudoInfo(TrueOpc); 352406c3fb27SDimitry Andric IsMasked = true; 352506c3fb27SDimitry Andric } 3526bdd1243dSDimitry Andric 3527bdd1243dSDimitry Andric if (!Info) 3528bdd1243dSDimitry Andric return false; 3529bdd1243dSDimitry Andric 35305f757f3fSDimitry Andric // When Mask is not a true mask, this transformation is illegal for some 35315f757f3fSDimitry Andric // operations whose results are affected by mask, like viota.m. 35325f757f3fSDimitry Andric if (Info->MaskAffectsResult && Mask && !usesAllOnesMask(Mask, Glue)) 35335f757f3fSDimitry Andric return false; 35345f757f3fSDimitry Andric 353506c3fb27SDimitry Andric if (HasTiedDest && !isImplicitDef(True->getOperand(0))) { 353606c3fb27SDimitry Andric // The vmerge instruction must be TU. 353706c3fb27SDimitry Andric // FIXME: This could be relaxed, but we need to handle the policy for the 353806c3fb27SDimitry Andric // resulting op correctly. 353906c3fb27SDimitry Andric if (isImplicitDef(Merge)) 354006c3fb27SDimitry Andric return false; 354106c3fb27SDimitry Andric SDValue MergeOpTrue = True->getOperand(0); 354206c3fb27SDimitry Andric // Both the vmerge instruction and the True instruction must have the same 354306c3fb27SDimitry Andric // merge operand. 354406c3fb27SDimitry Andric if (False != MergeOpTrue) 354506c3fb27SDimitry Andric return false; 354606c3fb27SDimitry Andric } 354706c3fb27SDimitry Andric 354806c3fb27SDimitry Andric if (IsMasked) { 354906c3fb27SDimitry Andric assert(HasTiedDest && "Expected tied dest"); 355006c3fb27SDimitry Andric // The vmerge instruction must be TU. 355106c3fb27SDimitry Andric if (isImplicitDef(Merge)) 355206c3fb27SDimitry Andric return false; 355306c3fb27SDimitry Andric // The vmerge instruction must have an all 1s mask since we're going to keep 355406c3fb27SDimitry Andric // the mask from the True instruction. 355506c3fb27SDimitry Andric // FIXME: Support mask agnostic True instruction which would have an 355606c3fb27SDimitry Andric // undef merge operand. 355706c3fb27SDimitry Andric if (Mask && !usesAllOnesMask(Mask, Glue)) 355806c3fb27SDimitry Andric return false; 355906c3fb27SDimitry Andric } 356006c3fb27SDimitry Andric 356106c3fb27SDimitry Andric // Skip if True has side effect. 356206c3fb27SDimitry Andric // TODO: Support vleff and vlsegff. 356306c3fb27SDimitry Andric if (TII->get(TrueOpc).hasUnmodeledSideEffects()) 356406c3fb27SDimitry Andric return false; 356506c3fb27SDimitry Andric 356606c3fb27SDimitry Andric // The last operand of a masked instruction may be glued. 356706c3fb27SDimitry Andric bool HasGlueOp = True->getGluedNode() != nullptr; 356806c3fb27SDimitry Andric 356906c3fb27SDimitry Andric // The chain operand may exist either before the glued operands or in the last 357006c3fb27SDimitry Andric // position. 357106c3fb27SDimitry Andric unsigned TrueChainOpIdx = True.getNumOperands() - HasGlueOp - 1; 3572bdd1243dSDimitry Andric bool HasChainOp = 357306c3fb27SDimitry Andric True.getOperand(TrueChainOpIdx).getValueType() == MVT::Other; 3574bdd1243dSDimitry Andric 3575bdd1243dSDimitry Andric if (HasChainOp) { 3576bdd1243dSDimitry Andric // Avoid creating cycles in the DAG. We must ensure that none of the other 3577bdd1243dSDimitry Andric // operands depend on True through it's Chain. 3578bdd1243dSDimitry Andric SmallVector<const SDNode *, 4> LoopWorklist; 3579bdd1243dSDimitry Andric SmallPtrSet<const SDNode *, 16> Visited; 3580bdd1243dSDimitry Andric LoopWorklist.push_back(False.getNode()); 358106c3fb27SDimitry Andric if (Mask) 3582bdd1243dSDimitry Andric LoopWorklist.push_back(Mask.getNode()); 3583bdd1243dSDimitry Andric LoopWorklist.push_back(VL.getNode()); 358406c3fb27SDimitry Andric if (Glue) 358506c3fb27SDimitry Andric LoopWorklist.push_back(Glue.getNode()); 3586bdd1243dSDimitry Andric if (SDNode::hasPredecessorHelper(True.getNode(), Visited, LoopWorklist)) 3587bdd1243dSDimitry Andric return false; 3588bdd1243dSDimitry Andric } 3589bdd1243dSDimitry Andric 359006c3fb27SDimitry Andric // The vector policy operand may be present for masked intrinsics 359106c3fb27SDimitry Andric bool HasVecPolicyOp = RISCVII::hasVecPolicyOp(TrueTSFlags); 359206c3fb27SDimitry Andric unsigned TrueVLIndex = 359306c3fb27SDimitry Andric True.getNumOperands() - HasVecPolicyOp - HasChainOp - HasGlueOp - 2; 3594bdd1243dSDimitry Andric SDValue TrueVL = True.getOperand(TrueVLIndex); 359506c3fb27SDimitry Andric SDValue SEW = True.getOperand(TrueVLIndex + 1); 3596bdd1243dSDimitry Andric 359706c3fb27SDimitry Andric auto GetMinVL = [](SDValue LHS, SDValue RHS) { 359806c3fb27SDimitry Andric if (LHS == RHS) 359906c3fb27SDimitry Andric return LHS; 360006c3fb27SDimitry Andric if (isAllOnesConstant(LHS)) 360106c3fb27SDimitry Andric return RHS; 360206c3fb27SDimitry Andric if (isAllOnesConstant(RHS)) 360306c3fb27SDimitry Andric return LHS; 360406c3fb27SDimitry Andric auto *CLHS = dyn_cast<ConstantSDNode>(LHS); 360506c3fb27SDimitry Andric auto *CRHS = dyn_cast<ConstantSDNode>(RHS); 360606c3fb27SDimitry Andric if (!CLHS || !CRHS) 360706c3fb27SDimitry Andric return SDValue(); 360806c3fb27SDimitry Andric return CLHS->getZExtValue() <= CRHS->getZExtValue() ? LHS : RHS; 3609bdd1243dSDimitry Andric }; 3610bdd1243dSDimitry Andric 361106c3fb27SDimitry Andric // Because N and True must have the same merge operand (or True's operand is 361206c3fb27SDimitry Andric // implicit_def), the "effective" body is the minimum of their VLs. 36138a4dda33SDimitry Andric SDValue OrigVL = VL; 361406c3fb27SDimitry Andric VL = GetMinVL(TrueVL, VL); 361506c3fb27SDimitry Andric if (!VL) 361606c3fb27SDimitry Andric return false; 361706c3fb27SDimitry Andric 361806c3fb27SDimitry Andric // If we end up changing the VL or mask of True, then we need to make sure it 361906c3fb27SDimitry Andric // doesn't raise any observable fp exceptions, since changing the active 362006c3fb27SDimitry Andric // elements will affect how fflags is set. 362106c3fb27SDimitry Andric if (TrueVL != VL || !IsMasked) 362206c3fb27SDimitry Andric if (mayRaiseFPException(True.getNode()) && 362306c3fb27SDimitry Andric !True->getFlags().hasNoFPExcept()) 3624bdd1243dSDimitry Andric return false; 3625bdd1243dSDimitry Andric 3626bdd1243dSDimitry Andric SDLoc DL(N); 362706c3fb27SDimitry Andric 362806c3fb27SDimitry Andric // From the preconditions we checked above, we know the mask and thus glue 362906c3fb27SDimitry Andric // for the result node will be taken from True. 363006c3fb27SDimitry Andric if (IsMasked) { 363106c3fb27SDimitry Andric Mask = True->getOperand(Info->MaskOpIdx); 363206c3fb27SDimitry Andric Glue = True->getOperand(True->getNumOperands() - 1); 363306c3fb27SDimitry Andric assert(Glue.getValueType() == MVT::Glue); 363406c3fb27SDimitry Andric } 363506c3fb27SDimitry Andric // If we end up using the vmerge mask the vmerge is actually a vmv.v.v, create 363606c3fb27SDimitry Andric // an all-ones mask to use. 363706c3fb27SDimitry Andric else if (IsVMv(N)) { 363806c3fb27SDimitry Andric unsigned TSFlags = TII->get(N->getMachineOpcode()).TSFlags; 363906c3fb27SDimitry Andric unsigned VMSetOpc = GetVMSetForLMul(RISCVII::getLMul(TSFlags)); 364006c3fb27SDimitry Andric ElementCount EC = N->getValueType(0).getVectorElementCount(); 364106c3fb27SDimitry Andric MVT MaskVT = MVT::getVectorVT(MVT::i1, EC); 364206c3fb27SDimitry Andric 364306c3fb27SDimitry Andric SDValue AllOnesMask = 364406c3fb27SDimitry Andric SDValue(CurDAG->getMachineNode(VMSetOpc, DL, MaskVT, VL, SEW), 0); 364506c3fb27SDimitry Andric SDValue MaskCopy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, 364606c3fb27SDimitry Andric RISCV::V0, AllOnesMask, SDValue()); 364706c3fb27SDimitry Andric Mask = CurDAG->getRegister(RISCV::V0, MaskVT); 364806c3fb27SDimitry Andric Glue = MaskCopy.getValue(1); 364906c3fb27SDimitry Andric } 365006c3fb27SDimitry Andric 3651bdd1243dSDimitry Andric unsigned MaskedOpc = Info->MaskedPseudo; 365206c3fb27SDimitry Andric #ifndef NDEBUG 365306c3fb27SDimitry Andric const MCInstrDesc &MaskedMCID = TII->get(MaskedOpc); 365406c3fb27SDimitry Andric assert(RISCVII::hasVecPolicyOp(MaskedMCID.TSFlags) && 3655bdd1243dSDimitry Andric "Expected instructions with mask have policy operand."); 365606c3fb27SDimitry Andric assert(MaskedMCID.getOperandConstraint(MaskedMCID.getNumDefs(), 365706c3fb27SDimitry Andric MCOI::TIED_TO) == 0 && 365806c3fb27SDimitry Andric "Expected instructions with mask have a tied dest."); 365906c3fb27SDimitry Andric #endif 366006c3fb27SDimitry Andric 36618a4dda33SDimitry Andric // Use a tumu policy, relaxing it to tail agnostic provided that the merge 36628a4dda33SDimitry Andric // operand is undefined. 36638a4dda33SDimitry Andric // 36648a4dda33SDimitry Andric // However, if the VL became smaller than what the vmerge had originally, then 36658a4dda33SDimitry Andric // elements past VL that were previously in the vmerge's body will have moved 36668a4dda33SDimitry Andric // to the tail. In that case we always need to use tail undisturbed to 36678a4dda33SDimitry Andric // preserve them. 36688a4dda33SDimitry Andric bool MergeVLShrunk = VL != OrigVL; 36698a4dda33SDimitry Andric uint64_t Policy = (isImplicitDef(Merge) && !MergeVLShrunk) 36708a4dda33SDimitry Andric ? RISCVII::TAIL_AGNOSTIC 36718a4dda33SDimitry Andric : /*TUMU*/ 0; 367206c3fb27SDimitry Andric SDValue PolicyOp = 367306c3fb27SDimitry Andric CurDAG->getTargetConstant(Policy, DL, Subtarget->getXLenVT()); 367406c3fb27SDimitry Andric 3675bdd1243dSDimitry Andric 3676bdd1243dSDimitry Andric SmallVector<SDValue, 8> Ops; 3677bdd1243dSDimitry Andric Ops.push_back(False); 367806c3fb27SDimitry Andric 367906c3fb27SDimitry Andric const bool HasRoundingMode = RISCVII::hasRoundModeOp(TrueTSFlags); 368006c3fb27SDimitry Andric const unsigned NormalOpsEnd = TrueVLIndex - IsMasked - HasRoundingMode; 368106c3fb27SDimitry Andric assert(!IsMasked || NormalOpsEnd == Info->MaskOpIdx); 368206c3fb27SDimitry Andric Ops.append(True->op_begin() + HasTiedDest, True->op_begin() + NormalOpsEnd); 368306c3fb27SDimitry Andric 368406c3fb27SDimitry Andric Ops.push_back(Mask); 368506c3fb27SDimitry Andric 368606c3fb27SDimitry Andric // For unmasked "VOp" with rounding mode operand, that is interfaces like 368706c3fb27SDimitry Andric // (..., rm, vl) or (..., rm, vl, policy). 368806c3fb27SDimitry Andric // Its masked version is (..., vm, rm, vl, policy). 368906c3fb27SDimitry Andric // Check the rounding mode pseudo nodes under RISCVInstrInfoVPseudos.td 369006c3fb27SDimitry Andric if (HasRoundingMode) 369106c3fb27SDimitry Andric Ops.push_back(True->getOperand(TrueVLIndex - 1)); 369206c3fb27SDimitry Andric 369306c3fb27SDimitry Andric Ops.append({VL, SEW, PolicyOp}); 3694bdd1243dSDimitry Andric 3695bdd1243dSDimitry Andric // Result node should have chain operand of True. 3696bdd1243dSDimitry Andric if (HasChainOp) 369706c3fb27SDimitry Andric Ops.push_back(True.getOperand(TrueChainOpIdx)); 3698bdd1243dSDimitry Andric 369906c3fb27SDimitry Andric // Add the glue for the CopyToReg of mask->v0. 370006c3fb27SDimitry Andric Ops.push_back(Glue); 3701bdd1243dSDimitry Andric 37025f757f3fSDimitry Andric MachineSDNode *Result = 3703bdd1243dSDimitry Andric CurDAG->getMachineNode(MaskedOpc, DL, True->getVTList(), Ops); 3704bdd1243dSDimitry Andric Result->setFlags(True->getFlags()); 3705bdd1243dSDimitry Andric 37065f757f3fSDimitry Andric if (!cast<MachineSDNode>(True)->memoperands_empty()) 37075f757f3fSDimitry Andric CurDAG->setNodeMemRefs(Result, cast<MachineSDNode>(True)->memoperands()); 37085f757f3fSDimitry Andric 3709bdd1243dSDimitry Andric // Replace vmerge.vvm node by Result. 3710bdd1243dSDimitry Andric ReplaceUses(SDValue(N, 0), SDValue(Result, 0)); 3711bdd1243dSDimitry Andric 3712bdd1243dSDimitry Andric // Replace another value of True. E.g. chain and VL. 3713bdd1243dSDimitry Andric for (unsigned Idx = 1; Idx < True->getNumValues(); ++Idx) 3714bdd1243dSDimitry Andric ReplaceUses(True.getValue(Idx), SDValue(Result, Idx)); 3715bdd1243dSDimitry Andric 3716bdd1243dSDimitry Andric return true; 3717bdd1243dSDimitry Andric } 3718bdd1243dSDimitry Andric 3719bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeMergeVVMFold() { 3720bdd1243dSDimitry Andric bool MadeChange = false; 3721bdd1243dSDimitry Andric SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); 3722bdd1243dSDimitry Andric 3723bdd1243dSDimitry Andric while (Position != CurDAG->allnodes_begin()) { 3724bdd1243dSDimitry Andric SDNode *N = &*--Position; 3725bdd1243dSDimitry Andric if (N->use_empty() || !N->isMachineOpcode()) 3726bdd1243dSDimitry Andric continue; 3727bdd1243dSDimitry Andric 372806c3fb27SDimitry Andric if (IsVMerge(N) || IsVMv(N)) 372906c3fb27SDimitry Andric MadeChange |= performCombineVMergeAndVOps(N); 3730bdd1243dSDimitry Andric } 3731bdd1243dSDimitry Andric return MadeChange; 3732bdd1243dSDimitry Andric } 3733bdd1243dSDimitry Andric 37345f757f3fSDimitry Andric /// If our passthru is an implicit_def, use noreg instead. This side 37355f757f3fSDimitry Andric /// steps issues with MachineCSE not being able to CSE expressions with 37365f757f3fSDimitry Andric /// IMPLICIT_DEF operands while preserving the semantic intent. See 37375f757f3fSDimitry Andric /// pr64282 for context. Note that this transform is the last one 37385f757f3fSDimitry Andric /// performed at ISEL DAG to DAG. 37395f757f3fSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeNoRegPassThru() { 37405f757f3fSDimitry Andric bool MadeChange = false; 37415f757f3fSDimitry Andric SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); 37425f757f3fSDimitry Andric 37435f757f3fSDimitry Andric while (Position != CurDAG->allnodes_begin()) { 37445f757f3fSDimitry Andric SDNode *N = &*--Position; 37455f757f3fSDimitry Andric if (N->use_empty() || !N->isMachineOpcode()) 37465f757f3fSDimitry Andric continue; 37475f757f3fSDimitry Andric 37485f757f3fSDimitry Andric const unsigned Opc = N->getMachineOpcode(); 37495f757f3fSDimitry Andric if (!RISCVVPseudosTable::getPseudoInfo(Opc) || 37505f757f3fSDimitry Andric !RISCVII::isFirstDefTiedToFirstUse(TII->get(Opc)) || 37515f757f3fSDimitry Andric !isImplicitDef(N->getOperand(0))) 37525f757f3fSDimitry Andric continue; 37535f757f3fSDimitry Andric 37545f757f3fSDimitry Andric SmallVector<SDValue> Ops; 37555f757f3fSDimitry Andric Ops.push_back(CurDAG->getRegister(RISCV::NoRegister, N->getValueType(0))); 37565f757f3fSDimitry Andric for (unsigned I = 1, E = N->getNumOperands(); I != E; I++) { 37575f757f3fSDimitry Andric SDValue Op = N->getOperand(I); 37585f757f3fSDimitry Andric Ops.push_back(Op); 37595f757f3fSDimitry Andric } 37605f757f3fSDimitry Andric 37615f757f3fSDimitry Andric MachineSDNode *Result = 37625f757f3fSDimitry Andric CurDAG->getMachineNode(Opc, SDLoc(N), N->getVTList(), Ops); 37635f757f3fSDimitry Andric Result->setFlags(N->getFlags()); 37645f757f3fSDimitry Andric CurDAG->setNodeMemRefs(Result, cast<MachineSDNode>(N)->memoperands()); 37655f757f3fSDimitry Andric ReplaceUses(N, Result); 37665f757f3fSDimitry Andric MadeChange = true; 37675f757f3fSDimitry Andric } 37685f757f3fSDimitry Andric return MadeChange; 37695f757f3fSDimitry Andric } 37705f757f3fSDimitry Andric 37715f757f3fSDimitry Andric 37720b57cec5SDimitry Andric // This pass converts a legalized DAG into a RISCV-specific DAG, ready 37730b57cec5SDimitry Andric // for instruction scheduling. 377481ad6265SDimitry Andric FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM, 37755f757f3fSDimitry Andric CodeGenOptLevel OptLevel) { 377681ad6265SDimitry Andric return new RISCVDAGToDAGISel(TM, OptLevel); 37770b57cec5SDimitry Andric } 3778bdd1243dSDimitry Andric 3779bdd1243dSDimitry Andric char RISCVDAGToDAGISel::ID = 0; 3780bdd1243dSDimitry Andric 3781bdd1243dSDimitry Andric INITIALIZE_PASS(RISCVDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false) 3782