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 46fe6060f1SDimitry Andric #include "RISCVGenSearchableTables.inc" 47bdd1243dSDimitry Andric } // namespace llvm::RISCV 48bdd1243dSDimitry Andric 49fe6060f1SDimitry Andric void RISCVDAGToDAGISel::PreprocessISelDAG() { 50753f127fSDimitry Andric SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); 51fe6060f1SDimitry Andric 52753f127fSDimitry Andric bool MadeChange = false; 53753f127fSDimitry Andric while (Position != CurDAG->allnodes_begin()) { 54753f127fSDimitry Andric SDNode *N = &*--Position; 55753f127fSDimitry Andric if (N->use_empty()) 56753f127fSDimitry Andric continue; 57753f127fSDimitry Andric 58753f127fSDimitry Andric SDValue Result; 59753f127fSDimitry Andric switch (N->getOpcode()) { 60753f127fSDimitry Andric case ISD::SPLAT_VECTOR: { 6181ad6265SDimitry Andric // Convert integer SPLAT_VECTOR to VMV_V_X_VL and floating-point 6281ad6265SDimitry Andric // SPLAT_VECTOR to VFMV_V_F_VL to reduce isel burden. 6381ad6265SDimitry Andric MVT VT = N->getSimpleValueType(0); 6481ad6265SDimitry Andric unsigned Opc = 6581ad6265SDimitry Andric VT.isInteger() ? RISCVISD::VMV_V_X_VL : RISCVISD::VFMV_V_F_VL; 6681ad6265SDimitry Andric SDLoc DL(N); 6781ad6265SDimitry Andric SDValue VL = CurDAG->getRegister(RISCV::X0, Subtarget->getXLenVT()); 685f757f3fSDimitry Andric SDValue Src = N->getOperand(0); 695f757f3fSDimitry Andric if (VT.isInteger()) 705f757f3fSDimitry Andric Src = CurDAG->getNode(ISD::ANY_EXTEND, DL, Subtarget->getXLenVT(), 715f757f3fSDimitry Andric N->getOperand(0)); 725f757f3fSDimitry Andric Result = CurDAG->getNode(Opc, DL, VT, CurDAG->getUNDEF(VT), Src, VL); 73753f127fSDimitry Andric break; 7481ad6265SDimitry Andric } 75753f127fSDimitry Andric case RISCVISD::SPLAT_VECTOR_SPLIT_I64_VL: { 76fe6060f1SDimitry Andric // Lower SPLAT_VECTOR_SPLIT_I64 to two scalar stores and a stride 0 vector 77fe6060f1SDimitry Andric // load. Done after lowering and combining so that we have a chance to 78fe6060f1SDimitry Andric // optimize this to VMV_V_X_VL when the upper bits aren't needed. 7981ad6265SDimitry Andric assert(N->getNumOperands() == 4 && "Unexpected number of operands"); 80fe6060f1SDimitry Andric MVT VT = N->getSimpleValueType(0); 8181ad6265SDimitry Andric SDValue Passthru = N->getOperand(0); 8281ad6265SDimitry Andric SDValue Lo = N->getOperand(1); 8381ad6265SDimitry Andric SDValue Hi = N->getOperand(2); 8481ad6265SDimitry Andric SDValue VL = N->getOperand(3); 85fe6060f1SDimitry Andric assert(VT.getVectorElementType() == MVT::i64 && VT.isScalableVector() && 86fe6060f1SDimitry Andric Lo.getValueType() == MVT::i32 && Hi.getValueType() == MVT::i32 && 87fe6060f1SDimitry Andric "Unexpected VTs!"); 88fe6060f1SDimitry Andric MachineFunction &MF = CurDAG->getMachineFunction(); 89fe6060f1SDimitry Andric SDLoc DL(N); 90fe6060f1SDimitry Andric 9106c3fb27SDimitry Andric // Create temporary stack for each expanding node. 92fe6060f1SDimitry Andric SDValue StackSlot = 935f757f3fSDimitry Andric CurDAG->CreateStackTemporary(TypeSize::getFixed(8), Align(8)); 9406c3fb27SDimitry Andric int FI = cast<FrameIndexSDNode>(StackSlot.getNode())->getIndex(); 9506c3fb27SDimitry Andric MachinePointerInfo MPI = MachinePointerInfo::getFixedStack(MF, FI); 96fe6060f1SDimitry Andric 97fe6060f1SDimitry Andric SDValue Chain = CurDAG->getEntryNode(); 98fe6060f1SDimitry Andric Lo = CurDAG->getStore(Chain, DL, Lo, StackSlot, MPI, Align(8)); 99fe6060f1SDimitry Andric 100fe6060f1SDimitry Andric SDValue OffsetSlot = 1015f757f3fSDimitry Andric CurDAG->getMemBasePlusOffset(StackSlot, TypeSize::getFixed(4), DL); 102fe6060f1SDimitry Andric Hi = CurDAG->getStore(Chain, DL, Hi, OffsetSlot, MPI.getWithOffset(4), 103fe6060f1SDimitry Andric Align(8)); 104fe6060f1SDimitry Andric 105fe6060f1SDimitry Andric Chain = CurDAG->getNode(ISD::TokenFactor, DL, MVT::Other, Lo, Hi); 106fe6060f1SDimitry Andric 107fe6060f1SDimitry Andric SDVTList VTs = CurDAG->getVTList({VT, MVT::Other}); 108fe6060f1SDimitry Andric SDValue IntID = 109fe6060f1SDimitry Andric CurDAG->getTargetConstant(Intrinsic::riscv_vlse, DL, MVT::i64); 11004eeddc0SDimitry Andric SDValue Ops[] = {Chain, 11104eeddc0SDimitry Andric IntID, 11281ad6265SDimitry Andric Passthru, 11304eeddc0SDimitry Andric StackSlot, 11404eeddc0SDimitry Andric CurDAG->getRegister(RISCV::X0, MVT::i64), 11504eeddc0SDimitry Andric VL}; 116fe6060f1SDimitry Andric 117753f127fSDimitry Andric Result = CurDAG->getMemIntrinsicNode(ISD::INTRINSIC_W_CHAIN, DL, VTs, Ops, 118753f127fSDimitry Andric MVT::i64, MPI, Align(8), 119fe6060f1SDimitry Andric MachineMemOperand::MOLoad); 120753f127fSDimitry Andric break; 121fe6060f1SDimitry Andric } 122fe6060f1SDimitry Andric } 123fe6060f1SDimitry Andric 124753f127fSDimitry Andric if (Result) { 12506c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "RISC-V DAG preprocessing replacing:\nOld: "); 126753f127fSDimitry Andric LLVM_DEBUG(N->dump(CurDAG)); 127753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "\nNew: "); 128753f127fSDimitry Andric LLVM_DEBUG(Result->dump(CurDAG)); 129753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "\n"); 130753f127fSDimitry Andric 131753f127fSDimitry Andric CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0), Result); 132753f127fSDimitry Andric MadeChange = true; 133753f127fSDimitry Andric } 134753f127fSDimitry Andric } 135753f127fSDimitry Andric 136753f127fSDimitry Andric if (MadeChange) 137753f127fSDimitry Andric CurDAG->RemoveDeadNodes(); 138753f127fSDimitry Andric } 139753f127fSDimitry Andric 1400b57cec5SDimitry Andric void RISCVDAGToDAGISel::PostprocessISelDAG() { 14181ad6265SDimitry Andric HandleSDNode Dummy(CurDAG->getRoot()); 142349cc55cSDimitry Andric SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); 143349cc55cSDimitry Andric 144349cc55cSDimitry Andric bool MadeChange = false; 145349cc55cSDimitry Andric while (Position != CurDAG->allnodes_begin()) { 146349cc55cSDimitry Andric SDNode *N = &*--Position; 147349cc55cSDimitry Andric // Skip dead nodes and any non-machine opcodes. 148349cc55cSDimitry Andric if (N->use_empty() || !N->isMachineOpcode()) 149349cc55cSDimitry Andric continue; 150349cc55cSDimitry Andric 151349cc55cSDimitry Andric MadeChange |= doPeepholeSExtW(N); 1525f757f3fSDimitry Andric 1535f757f3fSDimitry Andric // FIXME: This is here only because the VMerge transform doesn't 1545f757f3fSDimitry Andric // know how to handle masked true inputs. Once that has been moved 1555f757f3fSDimitry Andric // to post-ISEL, this can be deleted as well. 1565f757f3fSDimitry Andric MadeChange |= doPeepholeMaskedRVV(cast<MachineSDNode>(N)); 157349cc55cSDimitry Andric } 158349cc55cSDimitry Andric 15981ad6265SDimitry Andric CurDAG->setRoot(Dummy.getValue()); 16081ad6265SDimitry Andric 161bdd1243dSDimitry Andric MadeChange |= doPeepholeMergeVVMFold(); 162bdd1243dSDimitry Andric 1635f757f3fSDimitry Andric // After we're done with everything else, convert IMPLICIT_DEF 1645f757f3fSDimitry Andric // passthru operands to NoRegister. This is required to workaround 1655f757f3fSDimitry Andric // an optimization deficiency in MachineCSE. This really should 1665f757f3fSDimitry Andric // be merged back into each of the patterns (i.e. there's no good 1675f757f3fSDimitry Andric // reason not to go directly to NoReg), but is being done this way 1685f757f3fSDimitry Andric // to allow easy backporting. 1695f757f3fSDimitry Andric MadeChange |= doPeepholeNoRegPassThru(); 1705f757f3fSDimitry Andric 171349cc55cSDimitry Andric if (MadeChange) 172349cc55cSDimitry Andric CurDAG->RemoveDeadNodes(); 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 17506c3fb27SDimitry Andric static SDValue selectImmSeq(SelectionDAG *CurDAG, const SDLoc &DL, const MVT VT, 17681ad6265SDimitry Andric RISCVMatInt::InstSeq &Seq) { 17781ad6265SDimitry Andric SDValue SrcReg = CurDAG->getRegister(RISCV::X0, VT); 17806c3fb27SDimitry Andric for (const RISCVMatInt::Inst &Inst : Seq) { 179bdd1243dSDimitry Andric SDValue SDImm = CurDAG->getTargetConstant(Inst.getImm(), DL, VT); 18006c3fb27SDimitry Andric SDNode *Result = nullptr; 18181ad6265SDimitry Andric switch (Inst.getOpndKind()) { 18281ad6265SDimitry Andric case RISCVMatInt::Imm: 183bdd1243dSDimitry Andric Result = CurDAG->getMachineNode(Inst.getOpcode(), DL, VT, SDImm); 18481ad6265SDimitry Andric break; 18581ad6265SDimitry Andric case RISCVMatInt::RegX0: 186bdd1243dSDimitry Andric Result = CurDAG->getMachineNode(Inst.getOpcode(), DL, VT, SrcReg, 18781ad6265SDimitry Andric CurDAG->getRegister(RISCV::X0, VT)); 18881ad6265SDimitry Andric break; 18981ad6265SDimitry Andric case RISCVMatInt::RegReg: 190bdd1243dSDimitry Andric Result = CurDAG->getMachineNode(Inst.getOpcode(), DL, VT, SrcReg, SrcReg); 19181ad6265SDimitry Andric break; 19281ad6265SDimitry Andric case RISCVMatInt::RegImm: 193bdd1243dSDimitry Andric Result = CurDAG->getMachineNode(Inst.getOpcode(), DL, VT, SrcReg, SDImm); 19481ad6265SDimitry Andric break; 19581ad6265SDimitry Andric } 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric // Only the first instruction has X0 as its source. 1980b57cec5SDimitry Andric SrcReg = SDValue(Result, 0); 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric 20106c3fb27SDimitry Andric return SrcReg; 2020b57cec5SDimitry Andric } 2030b57cec5SDimitry Andric 20406c3fb27SDimitry Andric static SDValue selectImm(SelectionDAG *CurDAG, const SDLoc &DL, const MVT VT, 20581ad6265SDimitry Andric int64_t Imm, const RISCVSubtarget &Subtarget) { 2065f757f3fSDimitry Andric RISCVMatInt::InstSeq Seq = RISCVMatInt::generateInstSeq(Imm, Subtarget); 20781ad6265SDimitry Andric 2085f757f3fSDimitry Andric // Use a rematerializable pseudo instruction for short sequences if enabled. 2095f757f3fSDimitry Andric if (Seq.size() == 2 && UsePseudoMovImm) 2105f757f3fSDimitry Andric return SDValue( 2115f757f3fSDimitry Andric CurDAG->getMachineNode(RISCV::PseudoMovImm, DL, VT, 2125f757f3fSDimitry Andric CurDAG->getTargetConstant(Imm, DL, VT)), 2135f757f3fSDimitry Andric 0); 2145f757f3fSDimitry Andric 2155f757f3fSDimitry Andric // See if we can create this constant as (ADD (SLLI X, C), X) where X is at 21606c3fb27SDimitry Andric // worst an LUI+ADDIW. This will require an extra register, but avoids a 21706c3fb27SDimitry Andric // constant pool. 2185f757f3fSDimitry Andric // If we have Zba we can use (ADD_UW X, (SLLI X, 32)) to handle cases where 2195f757f3fSDimitry Andric // low and high 32 bits are the same and bit 31 and 63 are set. 22006c3fb27SDimitry Andric if (Seq.size() > 3) { 2215f757f3fSDimitry Andric unsigned ShiftAmt, AddOpc; 22206c3fb27SDimitry Andric RISCVMatInt::InstSeq SeqLo = 2235f757f3fSDimitry Andric RISCVMatInt::generateTwoRegInstSeq(Imm, Subtarget, ShiftAmt, AddOpc); 2245f757f3fSDimitry Andric if (!SeqLo.empty() && (SeqLo.size() + 2) < Seq.size()) { 22506c3fb27SDimitry Andric SDValue Lo = selectImmSeq(CurDAG, DL, VT, SeqLo); 22606c3fb27SDimitry Andric 22706c3fb27SDimitry Andric SDValue SLLI = SDValue( 22806c3fb27SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, Lo, 2295f757f3fSDimitry Andric CurDAG->getTargetConstant(ShiftAmt, DL, VT)), 23006c3fb27SDimitry Andric 0); 2315f757f3fSDimitry Andric return SDValue(CurDAG->getMachineNode(AddOpc, DL, VT, Lo, SLLI), 0); 23206c3fb27SDimitry Andric } 23306c3fb27SDimitry Andric } 23406c3fb27SDimitry Andric 23506c3fb27SDimitry Andric // Otherwise, use the original sequence. 23681ad6265SDimitry Andric return selectImmSeq(CurDAG, DL, VT, Seq); 23781ad6265SDimitry Andric } 23881ad6265SDimitry Andric 23981ad6265SDimitry Andric static SDValue createTuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs, 24081ad6265SDimitry Andric unsigned NF, RISCVII::VLMUL LMUL) { 24181ad6265SDimitry Andric static const unsigned M1TupleRegClassIDs[] = { 24281ad6265SDimitry Andric RISCV::VRN2M1RegClassID, RISCV::VRN3M1RegClassID, RISCV::VRN4M1RegClassID, 24381ad6265SDimitry Andric RISCV::VRN5M1RegClassID, RISCV::VRN6M1RegClassID, RISCV::VRN7M1RegClassID, 24481ad6265SDimitry Andric RISCV::VRN8M1RegClassID}; 24581ad6265SDimitry Andric static const unsigned M2TupleRegClassIDs[] = {RISCV::VRN2M2RegClassID, 24681ad6265SDimitry Andric RISCV::VRN3M2RegClassID, 24781ad6265SDimitry Andric RISCV::VRN4M2RegClassID}; 24881ad6265SDimitry Andric 249e8d8bef9SDimitry Andric assert(Regs.size() >= 2 && Regs.size() <= 8); 250e8d8bef9SDimitry Andric 25181ad6265SDimitry Andric unsigned RegClassID; 25281ad6265SDimitry Andric unsigned SubReg0; 25381ad6265SDimitry Andric switch (LMUL) { 25481ad6265SDimitry Andric default: 25581ad6265SDimitry Andric llvm_unreachable("Invalid LMUL."); 25681ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_F8: 25781ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_F4: 25881ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_F2: 25981ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_1: 26081ad6265SDimitry Andric static_assert(RISCV::sub_vrm1_7 == RISCV::sub_vrm1_0 + 7, 26181ad6265SDimitry Andric "Unexpected subreg numbering"); 26281ad6265SDimitry Andric SubReg0 = RISCV::sub_vrm1_0; 26381ad6265SDimitry Andric RegClassID = M1TupleRegClassIDs[NF - 2]; 26481ad6265SDimitry Andric break; 26581ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_2: 26681ad6265SDimitry Andric static_assert(RISCV::sub_vrm2_3 == RISCV::sub_vrm2_0 + 3, 26781ad6265SDimitry Andric "Unexpected subreg numbering"); 26881ad6265SDimitry Andric SubReg0 = RISCV::sub_vrm2_0; 26981ad6265SDimitry Andric RegClassID = M2TupleRegClassIDs[NF - 2]; 27081ad6265SDimitry Andric break; 27181ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_4: 27281ad6265SDimitry Andric static_assert(RISCV::sub_vrm4_1 == RISCV::sub_vrm4_0 + 1, 27381ad6265SDimitry Andric "Unexpected subreg numbering"); 27481ad6265SDimitry Andric SubReg0 = RISCV::sub_vrm4_0; 27581ad6265SDimitry Andric RegClassID = RISCV::VRN2M4RegClassID; 27681ad6265SDimitry Andric break; 27781ad6265SDimitry Andric } 27881ad6265SDimitry Andric 279e8d8bef9SDimitry Andric SDLoc DL(Regs[0]); 280e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Ops; 281e8d8bef9SDimitry Andric 282e8d8bef9SDimitry Andric Ops.push_back(CurDAG.getTargetConstant(RegClassID, DL, MVT::i32)); 283e8d8bef9SDimitry Andric 284e8d8bef9SDimitry Andric for (unsigned I = 0; I < Regs.size(); ++I) { 285e8d8bef9SDimitry Andric Ops.push_back(Regs[I]); 286e8d8bef9SDimitry Andric Ops.push_back(CurDAG.getTargetConstant(SubReg0 + I, DL, MVT::i32)); 287e8d8bef9SDimitry Andric } 288e8d8bef9SDimitry Andric SDNode *N = 289e8d8bef9SDimitry Andric CurDAG.getMachineNode(TargetOpcode::REG_SEQUENCE, DL, MVT::Untyped, Ops); 290e8d8bef9SDimitry Andric return SDValue(N, 0); 291e8d8bef9SDimitry Andric } 292e8d8bef9SDimitry Andric 293fe6060f1SDimitry Andric void RISCVDAGToDAGISel::addVectorLoadStoreOperands( 294fe6060f1SDimitry Andric SDNode *Node, unsigned Log2SEW, const SDLoc &DL, unsigned CurOp, 295fe6060f1SDimitry Andric bool IsMasked, bool IsStridedOrIndexed, SmallVectorImpl<SDValue> &Operands, 296349cc55cSDimitry Andric bool IsLoad, MVT *IndexVT) { 297fe6060f1SDimitry Andric SDValue Chain = Node->getOperand(0); 298fe6060f1SDimitry Andric SDValue Glue; 299fe6060f1SDimitry Andric 300753f127fSDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Base pointer. 301fe6060f1SDimitry Andric 302fe6060f1SDimitry Andric if (IsStridedOrIndexed) { 303fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Index. 304fe6060f1SDimitry Andric if (IndexVT) 305fe6060f1SDimitry Andric *IndexVT = Operands.back()->getSimpleValueType(0); 306fe6060f1SDimitry Andric } 307fe6060f1SDimitry Andric 308fe6060f1SDimitry Andric if (IsMasked) { 309fe6060f1SDimitry Andric // Mask needs to be copied to V0. 310fe6060f1SDimitry Andric SDValue Mask = Node->getOperand(CurOp++); 311fe6060f1SDimitry Andric Chain = CurDAG->getCopyToReg(Chain, DL, RISCV::V0, Mask, SDValue()); 312fe6060f1SDimitry Andric Glue = Chain.getValue(1); 313fe6060f1SDimitry Andric Operands.push_back(CurDAG->getRegister(RISCV::V0, Mask.getValueType())); 314fe6060f1SDimitry Andric } 315fe6060f1SDimitry Andric SDValue VL; 316fe6060f1SDimitry Andric selectVLOp(Node->getOperand(CurOp++), VL); 317fe6060f1SDimitry Andric Operands.push_back(VL); 318fe6060f1SDimitry Andric 319fe6060f1SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 320fe6060f1SDimitry Andric SDValue SEWOp = CurDAG->getTargetConstant(Log2SEW, DL, XLenVT); 321fe6060f1SDimitry Andric Operands.push_back(SEWOp); 322fe6060f1SDimitry Andric 32306c3fb27SDimitry Andric // At the IR layer, all the masked load intrinsics have policy operands, 32406c3fb27SDimitry Andric // none of the others do. All have passthru operands. For our pseudos, 32506c3fb27SDimitry Andric // all loads have policy operands. 32606c3fb27SDimitry Andric if (IsLoad) { 32706c3fb27SDimitry Andric uint64_t Policy = RISCVII::MASK_AGNOSTIC; 32806c3fb27SDimitry Andric if (IsMasked) 32906c3fb27SDimitry Andric Policy = Node->getConstantOperandVal(CurOp++); 330349cc55cSDimitry Andric SDValue PolicyOp = CurDAG->getTargetConstant(Policy, DL, XLenVT); 331349cc55cSDimitry Andric Operands.push_back(PolicyOp); 332349cc55cSDimitry Andric } 333349cc55cSDimitry Andric 334fe6060f1SDimitry Andric Operands.push_back(Chain); // Chain. 335fe6060f1SDimitry Andric if (Glue) 336fe6060f1SDimitry Andric Operands.push_back(Glue); 337fe6060f1SDimitry Andric } 338fe6060f1SDimitry Andric 339fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLSEG(SDNode *Node, bool IsMasked, 340e8d8bef9SDimitry Andric bool IsStrided) { 341e8d8bef9SDimitry Andric SDLoc DL(Node); 342e8d8bef9SDimitry Andric unsigned NF = Node->getNumValues() - 1; 343fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 344fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 345fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 346e8d8bef9SDimitry Andric 347fe6060f1SDimitry Andric unsigned CurOp = 2; 348fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 34981ad6265SDimitry Andric 350fe6060f1SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp, 351fe6060f1SDimitry Andric Node->op_begin() + CurOp + NF); 35281ad6265SDimitry Andric SDValue Merge = createTuple(*CurDAG, Regs, NF, LMUL); 35381ad6265SDimitry Andric Operands.push_back(Merge); 35481ad6265SDimitry Andric CurOp += NF; 355fe6060f1SDimitry Andric 356fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 357349cc55cSDimitry Andric Operands, /*IsLoad=*/true); 358fe6060f1SDimitry Andric 359fe6060f1SDimitry Andric const RISCV::VLSEGPseudo *P = 36006c3fb27SDimitry Andric RISCV::getVLSEGPseudo(NF, IsMasked, IsStrided, /*FF*/ false, Log2SEW, 361fe6060f1SDimitry Andric static_cast<unsigned>(LMUL)); 362fe6060f1SDimitry Andric MachineSDNode *Load = 363e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands); 364fe6060f1SDimitry Andric 365fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 366fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 367fe6060f1SDimitry Andric 368e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 369fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) { 370fe6060f1SDimitry Andric unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I); 371e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 372fe6060f1SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg)); 373fe6060f1SDimitry Andric } 374e8d8bef9SDimitry Andric 375e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); 376e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 377e8d8bef9SDimitry Andric } 378e8d8bef9SDimitry Andric 379fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLSEGFF(SDNode *Node, bool IsMasked) { 380e8d8bef9SDimitry Andric SDLoc DL(Node); 381fe6060f1SDimitry Andric unsigned NF = Node->getNumValues() - 2; // Do not count VL and Chain. 382fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 383e8d8bef9SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 384fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 385fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 386e8d8bef9SDimitry Andric 387fe6060f1SDimitry Andric unsigned CurOp = 2; 388e8d8bef9SDimitry Andric SmallVector<SDValue, 7> Operands; 38981ad6265SDimitry Andric 390fe6060f1SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp, 391fe6060f1SDimitry Andric Node->op_begin() + CurOp + NF); 392e8d8bef9SDimitry Andric SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL); 393fe6060f1SDimitry Andric Operands.push_back(MaskedOff); 39481ad6265SDimitry Andric CurOp += NF; 395e8d8bef9SDimitry Andric 396fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 397349cc55cSDimitry Andric /*IsStridedOrIndexed*/ false, Operands, 398349cc55cSDimitry Andric /*IsLoad=*/true); 399fe6060f1SDimitry Andric 400fe6060f1SDimitry Andric const RISCV::VLSEGPseudo *P = 40106c3fb27SDimitry Andric RISCV::getVLSEGPseudo(NF, IsMasked, /*Strided*/ false, /*FF*/ true, 402fe6060f1SDimitry Andric Log2SEW, static_cast<unsigned>(LMUL)); 403fe6060f1SDimitry Andric MachineSDNode *Load = CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, 40481ad6265SDimitry Andric XLenVT, MVT::Other, Operands); 405fe6060f1SDimitry Andric 406fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 407fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 408fe6060f1SDimitry Andric 409e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 410fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) { 411fe6060f1SDimitry Andric unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I); 412e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 413fe6060f1SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg)); 414fe6060f1SDimitry Andric } 415fe6060f1SDimitry Andric 41681ad6265SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); // VL 41781ad6265SDimitry Andric ReplaceUses(SDValue(Node, NF + 1), SDValue(Load, 2)); // Chain 418fe6060f1SDimitry Andric CurDAG->RemoveDeadNode(Node); 419fe6060f1SDimitry Andric } 420fe6060f1SDimitry Andric 421fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLXSEG(SDNode *Node, bool IsMasked, 422fe6060f1SDimitry Andric bool IsOrdered) { 423fe6060f1SDimitry Andric SDLoc DL(Node); 424fe6060f1SDimitry Andric unsigned NF = Node->getNumValues() - 1; 425fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 426fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 427fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 428fe6060f1SDimitry Andric 429fe6060f1SDimitry Andric unsigned CurOp = 2; 430fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 43181ad6265SDimitry Andric 432fe6060f1SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp, 433fe6060f1SDimitry Andric Node->op_begin() + CurOp + NF); 434fe6060f1SDimitry Andric SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL); 435fe6060f1SDimitry Andric Operands.push_back(MaskedOff); 43681ad6265SDimitry Andric CurOp += NF; 437fe6060f1SDimitry Andric 438fe6060f1SDimitry Andric MVT IndexVT; 439fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 440349cc55cSDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 441349cc55cSDimitry Andric /*IsLoad=*/true, &IndexVT); 442fe6060f1SDimitry Andric 443fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 444fe6060f1SDimitry Andric "Element count mismatch"); 445fe6060f1SDimitry Andric 446fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 447fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 44804eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 44904eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 45004eeddc0SDimitry Andric "values when XLEN=32"); 45104eeddc0SDimitry Andric } 452fe6060f1SDimitry Andric const RISCV::VLXSEGPseudo *P = RISCV::getVLXSEGPseudo( 45306c3fb27SDimitry Andric NF, IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 454fe6060f1SDimitry Andric static_cast<unsigned>(IndexLMUL)); 455fe6060f1SDimitry Andric MachineSDNode *Load = 456fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands); 457fe6060f1SDimitry Andric 458fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 459fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 460fe6060f1SDimitry Andric 461fe6060f1SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 462fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) { 463fe6060f1SDimitry Andric unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I); 464fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, I), 465fe6060f1SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg)); 466fe6060f1SDimitry Andric } 467e8d8bef9SDimitry Andric 468e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); 469e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 470e8d8bef9SDimitry Andric } 471e8d8bef9SDimitry Andric 472fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVSSEG(SDNode *Node, bool IsMasked, 473e8d8bef9SDimitry Andric bool IsStrided) { 474e8d8bef9SDimitry Andric SDLoc DL(Node); 475e8d8bef9SDimitry Andric unsigned NF = Node->getNumOperands() - 4; 476e8d8bef9SDimitry Andric if (IsStrided) 477e8d8bef9SDimitry Andric NF--; 478fe6060f1SDimitry Andric if (IsMasked) 479e8d8bef9SDimitry Andric NF--; 480fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 481fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 482fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 483e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 484e8d8bef9SDimitry Andric SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL); 485fe6060f1SDimitry Andric 486fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 487e8d8bef9SDimitry Andric Operands.push_back(StoreVal); 488fe6060f1SDimitry Andric unsigned CurOp = 2 + NF; 489fe6060f1SDimitry Andric 490fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 491fe6060f1SDimitry Andric Operands); 492fe6060f1SDimitry Andric 493fe6060f1SDimitry Andric const RISCV::VSSEGPseudo *P = RISCV::getVSSEGPseudo( 494fe6060f1SDimitry Andric NF, IsMasked, IsStrided, Log2SEW, static_cast<unsigned>(LMUL)); 495fe6060f1SDimitry Andric MachineSDNode *Store = 496e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands); 497fe6060f1SDimitry Andric 498fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 499fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 500fe6060f1SDimitry Andric 501e8d8bef9SDimitry Andric ReplaceNode(Node, Store); 502e8d8bef9SDimitry Andric } 503e8d8bef9SDimitry Andric 504fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVSXSEG(SDNode *Node, bool IsMasked, 505fe6060f1SDimitry Andric bool IsOrdered) { 506e8d8bef9SDimitry Andric SDLoc DL(Node); 507e8d8bef9SDimitry Andric unsigned NF = Node->getNumOperands() - 5; 508fe6060f1SDimitry Andric if (IsMasked) 509fe6060f1SDimitry Andric --NF; 510fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 511fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 512fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 513e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 514e8d8bef9SDimitry Andric SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL); 515e8d8bef9SDimitry Andric 516fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 517fe6060f1SDimitry Andric Operands.push_back(StoreVal); 518fe6060f1SDimitry Andric unsigned CurOp = 2 + NF; 519fe6060f1SDimitry Andric 520fe6060f1SDimitry Andric MVT IndexVT; 521fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 522349cc55cSDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 523349cc55cSDimitry Andric /*IsLoad=*/false, &IndexVT); 524fe6060f1SDimitry Andric 525fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 526fe6060f1SDimitry Andric "Element count mismatch"); 527fe6060f1SDimitry Andric 528fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 529fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 53004eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 53104eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 53204eeddc0SDimitry Andric "values when XLEN=32"); 53304eeddc0SDimitry Andric } 534fe6060f1SDimitry Andric const RISCV::VSXSEGPseudo *P = RISCV::getVSXSEGPseudo( 535fe6060f1SDimitry Andric NF, IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 536e8d8bef9SDimitry Andric static_cast<unsigned>(IndexLMUL)); 537fe6060f1SDimitry Andric MachineSDNode *Store = 538e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands); 539fe6060f1SDimitry Andric 540fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 541fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 542fe6060f1SDimitry Andric 543e8d8bef9SDimitry Andric ReplaceNode(Node, Store); 544e8d8bef9SDimitry Andric } 545e8d8bef9SDimitry Andric 54604eeddc0SDimitry Andric void RISCVDAGToDAGISel::selectVSETVLI(SDNode *Node) { 54704eeddc0SDimitry Andric if (!Subtarget->hasVInstructions()) 54804eeddc0SDimitry Andric return; 54904eeddc0SDimitry Andric 55006c3fb27SDimitry Andric assert(Node->getOpcode() == ISD::INTRINSIC_WO_CHAIN && "Unexpected opcode"); 55104eeddc0SDimitry Andric 55204eeddc0SDimitry Andric SDLoc DL(Node); 55304eeddc0SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 55404eeddc0SDimitry Andric 55506c3fb27SDimitry Andric unsigned IntNo = Node->getConstantOperandVal(0); 55604eeddc0SDimitry Andric 55704eeddc0SDimitry Andric assert((IntNo == Intrinsic::riscv_vsetvli || 55806c3fb27SDimitry Andric IntNo == Intrinsic::riscv_vsetvlimax) && 55904eeddc0SDimitry Andric "Unexpected vsetvli intrinsic"); 56004eeddc0SDimitry Andric 56106c3fb27SDimitry Andric bool VLMax = IntNo == Intrinsic::riscv_vsetvlimax; 56206c3fb27SDimitry Andric unsigned Offset = (VLMax ? 1 : 2); 56304eeddc0SDimitry Andric 56404eeddc0SDimitry Andric assert(Node->getNumOperands() == Offset + 2 && 56504eeddc0SDimitry Andric "Unexpected number of operands"); 56604eeddc0SDimitry Andric 56704eeddc0SDimitry Andric unsigned SEW = 56804eeddc0SDimitry Andric RISCVVType::decodeVSEW(Node->getConstantOperandVal(Offset) & 0x7); 56904eeddc0SDimitry Andric RISCVII::VLMUL VLMul = static_cast<RISCVII::VLMUL>( 57004eeddc0SDimitry Andric Node->getConstantOperandVal(Offset + 1) & 0x7); 57104eeddc0SDimitry Andric 57204eeddc0SDimitry Andric unsigned VTypeI = RISCVVType::encodeVTYPE(VLMul, SEW, /*TailAgnostic*/ true, 57306c3fb27SDimitry Andric /*MaskAgnostic*/ true); 57404eeddc0SDimitry Andric SDValue VTypeIOp = CurDAG->getTargetConstant(VTypeI, DL, XLenVT); 57504eeddc0SDimitry Andric 57604eeddc0SDimitry Andric SDValue VLOperand; 57704eeddc0SDimitry Andric unsigned Opcode = RISCV::PseudoVSETVLI; 5785f757f3fSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Node->getOperand(1))) { 579*0fca6ea1SDimitry Andric if (auto VLEN = Subtarget->getRealVLen()) 580*0fca6ea1SDimitry Andric if (*VLEN / RISCVVType::getSEWLMULRatio(SEW, VLMul) == C->getZExtValue()) 5815f757f3fSDimitry Andric VLMax = true; 5825f757f3fSDimitry Andric } 58306c3fb27SDimitry Andric if (VLMax || isAllOnesConstant(Node->getOperand(1))) { 58404eeddc0SDimitry Andric VLOperand = CurDAG->getRegister(RISCV::X0, XLenVT); 58504eeddc0SDimitry Andric Opcode = RISCV::PseudoVSETVLIX0; 58604eeddc0SDimitry Andric } else { 58706c3fb27SDimitry Andric VLOperand = Node->getOperand(1); 58804eeddc0SDimitry Andric 58904eeddc0SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(VLOperand)) { 59004eeddc0SDimitry Andric uint64_t AVL = C->getZExtValue(); 59104eeddc0SDimitry Andric if (isUInt<5>(AVL)) { 59204eeddc0SDimitry Andric SDValue VLImm = CurDAG->getTargetConstant(AVL, DL, XLenVT); 59306c3fb27SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(RISCV::PseudoVSETIVLI, DL, 59406c3fb27SDimitry Andric XLenVT, VLImm, VTypeIOp)); 59504eeddc0SDimitry Andric return; 59604eeddc0SDimitry Andric } 59704eeddc0SDimitry Andric } 59804eeddc0SDimitry Andric } 59904eeddc0SDimitry Andric 60006c3fb27SDimitry Andric ReplaceNode(Node, 60106c3fb27SDimitry Andric CurDAG->getMachineNode(Opcode, DL, XLenVT, VLOperand, VTypeIOp)); 60204eeddc0SDimitry Andric } 6030b57cec5SDimitry Andric 604bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::tryShrinkShlLogicImm(SDNode *Node) { 605bdd1243dSDimitry Andric MVT VT = Node->getSimpleValueType(0); 606bdd1243dSDimitry Andric unsigned Opcode = Node->getOpcode(); 607bdd1243dSDimitry Andric assert((Opcode == ISD::AND || Opcode == ISD::OR || Opcode == ISD::XOR) && 608bdd1243dSDimitry Andric "Unexpected opcode"); 609bdd1243dSDimitry Andric SDLoc DL(Node); 610bdd1243dSDimitry Andric 611bdd1243dSDimitry Andric // For operations of the form (x << C1) op C2, check if we can use 612bdd1243dSDimitry Andric // ANDI/ORI/XORI by transforming it into (x op (C2>>C1)) << C1. 613bdd1243dSDimitry Andric SDValue N0 = Node->getOperand(0); 614bdd1243dSDimitry Andric SDValue N1 = Node->getOperand(1); 615bdd1243dSDimitry Andric 616bdd1243dSDimitry Andric ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(N1); 617bdd1243dSDimitry Andric if (!Cst) 618bdd1243dSDimitry Andric return false; 619bdd1243dSDimitry Andric 620bdd1243dSDimitry Andric int64_t Val = Cst->getSExtValue(); 621bdd1243dSDimitry Andric 622bdd1243dSDimitry Andric // Check if immediate can already use ANDI/ORI/XORI. 623bdd1243dSDimitry Andric if (isInt<12>(Val)) 624bdd1243dSDimitry Andric return false; 625bdd1243dSDimitry Andric 626bdd1243dSDimitry Andric SDValue Shift = N0; 627bdd1243dSDimitry Andric 628bdd1243dSDimitry Andric // If Val is simm32 and we have a sext_inreg from i32, then the binop 629bdd1243dSDimitry Andric // produces at least 33 sign bits. We can peek through the sext_inreg and use 630bdd1243dSDimitry Andric // a SLLIW at the end. 631bdd1243dSDimitry Andric bool SignExt = false; 632bdd1243dSDimitry Andric if (isInt<32>(Val) && N0.getOpcode() == ISD::SIGN_EXTEND_INREG && 633bdd1243dSDimitry Andric N0.hasOneUse() && cast<VTSDNode>(N0.getOperand(1))->getVT() == MVT::i32) { 634bdd1243dSDimitry Andric SignExt = true; 635bdd1243dSDimitry Andric Shift = N0.getOperand(0); 636bdd1243dSDimitry Andric } 637bdd1243dSDimitry Andric 638bdd1243dSDimitry Andric if (Shift.getOpcode() != ISD::SHL || !Shift.hasOneUse()) 639bdd1243dSDimitry Andric return false; 640bdd1243dSDimitry Andric 641bdd1243dSDimitry Andric ConstantSDNode *ShlCst = dyn_cast<ConstantSDNode>(Shift.getOperand(1)); 642bdd1243dSDimitry Andric if (!ShlCst) 643bdd1243dSDimitry Andric return false; 644bdd1243dSDimitry Andric 645bdd1243dSDimitry Andric uint64_t ShAmt = ShlCst->getZExtValue(); 646bdd1243dSDimitry Andric 647bdd1243dSDimitry Andric // Make sure that we don't change the operation by removing bits. 648bdd1243dSDimitry Andric // This only matters for OR and XOR, AND is unaffected. 649bdd1243dSDimitry Andric uint64_t RemovedBitsMask = maskTrailingOnes<uint64_t>(ShAmt); 650bdd1243dSDimitry Andric if (Opcode != ISD::AND && (Val & RemovedBitsMask) != 0) 651bdd1243dSDimitry Andric return false; 652bdd1243dSDimitry Andric 653bdd1243dSDimitry Andric int64_t ShiftedVal = Val >> ShAmt; 654bdd1243dSDimitry Andric if (!isInt<12>(ShiftedVal)) 655bdd1243dSDimitry Andric return false; 656bdd1243dSDimitry Andric 657bdd1243dSDimitry Andric // If we peeked through a sext_inreg, make sure the shift is valid for SLLIW. 658bdd1243dSDimitry Andric if (SignExt && ShAmt >= 32) 659bdd1243dSDimitry Andric return false; 660bdd1243dSDimitry Andric 661bdd1243dSDimitry Andric // Ok, we can reorder to get a smaller immediate. 662bdd1243dSDimitry Andric unsigned BinOpc; 663bdd1243dSDimitry Andric switch (Opcode) { 664bdd1243dSDimitry Andric default: llvm_unreachable("Unexpected opcode"); 665bdd1243dSDimitry Andric case ISD::AND: BinOpc = RISCV::ANDI; break; 666bdd1243dSDimitry Andric case ISD::OR: BinOpc = RISCV::ORI; break; 667bdd1243dSDimitry Andric case ISD::XOR: BinOpc = RISCV::XORI; break; 668bdd1243dSDimitry Andric } 669bdd1243dSDimitry Andric 670bdd1243dSDimitry Andric unsigned ShOpc = SignExt ? RISCV::SLLIW : RISCV::SLLI; 671bdd1243dSDimitry Andric 672bdd1243dSDimitry Andric SDNode *BinOp = 673bdd1243dSDimitry Andric CurDAG->getMachineNode(BinOpc, DL, VT, Shift.getOperand(0), 674bdd1243dSDimitry Andric CurDAG->getTargetConstant(ShiftedVal, DL, VT)); 675bdd1243dSDimitry Andric SDNode *SLLI = 676bdd1243dSDimitry Andric CurDAG->getMachineNode(ShOpc, DL, VT, SDValue(BinOp, 0), 677bdd1243dSDimitry Andric CurDAG->getTargetConstant(ShAmt, DL, VT)); 678bdd1243dSDimitry Andric ReplaceNode(Node, SLLI); 679bdd1243dSDimitry Andric return true; 680bdd1243dSDimitry Andric } 681bdd1243dSDimitry Andric 68206c3fb27SDimitry Andric bool RISCVDAGToDAGISel::trySignedBitfieldExtract(SDNode *Node) { 68306c3fb27SDimitry Andric // Only supported with XTHeadBb at the moment. 68406c3fb27SDimitry Andric if (!Subtarget->hasVendorXTHeadBb()) 68506c3fb27SDimitry Andric return false; 68606c3fb27SDimitry Andric 68706c3fb27SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 68806c3fb27SDimitry Andric if (!N1C) 68906c3fb27SDimitry Andric return false; 69006c3fb27SDimitry Andric 69106c3fb27SDimitry Andric SDValue N0 = Node->getOperand(0); 69206c3fb27SDimitry Andric if (!N0.hasOneUse()) 69306c3fb27SDimitry Andric return false; 69406c3fb27SDimitry Andric 69506c3fb27SDimitry Andric auto BitfieldExtract = [&](SDValue N0, unsigned Msb, unsigned Lsb, SDLoc DL, 69606c3fb27SDimitry Andric MVT VT) { 69706c3fb27SDimitry Andric return CurDAG->getMachineNode(RISCV::TH_EXT, DL, VT, N0.getOperand(0), 69806c3fb27SDimitry Andric CurDAG->getTargetConstant(Msb, DL, VT), 69906c3fb27SDimitry Andric CurDAG->getTargetConstant(Lsb, DL, VT)); 70006c3fb27SDimitry Andric }; 70106c3fb27SDimitry Andric 70206c3fb27SDimitry Andric SDLoc DL(Node); 70306c3fb27SDimitry Andric MVT VT = Node->getSimpleValueType(0); 70406c3fb27SDimitry Andric const unsigned RightShAmt = N1C->getZExtValue(); 70506c3fb27SDimitry Andric 70606c3fb27SDimitry Andric // Transform (sra (shl X, C1) C2) with C1 < C2 70706c3fb27SDimitry Andric // -> (TH.EXT X, msb, lsb) 70806c3fb27SDimitry Andric if (N0.getOpcode() == ISD::SHL) { 70906c3fb27SDimitry Andric auto *N01C = dyn_cast<ConstantSDNode>(N0->getOperand(1)); 71006c3fb27SDimitry Andric if (!N01C) 71106c3fb27SDimitry Andric return false; 71206c3fb27SDimitry Andric 71306c3fb27SDimitry Andric const unsigned LeftShAmt = N01C->getZExtValue(); 71406c3fb27SDimitry Andric // Make sure that this is a bitfield extraction (i.e., the shift-right 71506c3fb27SDimitry Andric // amount can not be less than the left-shift). 71606c3fb27SDimitry Andric if (LeftShAmt > RightShAmt) 71706c3fb27SDimitry Andric return false; 71806c3fb27SDimitry Andric 71906c3fb27SDimitry Andric const unsigned MsbPlusOne = VT.getSizeInBits() - LeftShAmt; 72006c3fb27SDimitry Andric const unsigned Msb = MsbPlusOne - 1; 72106c3fb27SDimitry Andric const unsigned Lsb = RightShAmt - LeftShAmt; 72206c3fb27SDimitry Andric 72306c3fb27SDimitry Andric SDNode *TH_EXT = BitfieldExtract(N0, Msb, Lsb, DL, VT); 72406c3fb27SDimitry Andric ReplaceNode(Node, TH_EXT); 72506c3fb27SDimitry Andric return true; 72606c3fb27SDimitry Andric } 72706c3fb27SDimitry Andric 72806c3fb27SDimitry Andric // Transform (sra (sext_inreg X, _), C) -> 72906c3fb27SDimitry Andric // (TH.EXT X, msb, lsb) 73006c3fb27SDimitry Andric if (N0.getOpcode() == ISD::SIGN_EXTEND_INREG) { 73106c3fb27SDimitry Andric unsigned ExtSize = 73206c3fb27SDimitry Andric cast<VTSDNode>(N0.getOperand(1))->getVT().getSizeInBits(); 73306c3fb27SDimitry Andric 73406c3fb27SDimitry Andric // ExtSize of 32 should use sraiw via tablegen pattern. 73506c3fb27SDimitry Andric if (ExtSize == 32) 73606c3fb27SDimitry Andric return false; 73706c3fb27SDimitry Andric 73806c3fb27SDimitry Andric const unsigned Msb = ExtSize - 1; 73906c3fb27SDimitry Andric const unsigned Lsb = RightShAmt; 74006c3fb27SDimitry Andric 74106c3fb27SDimitry Andric SDNode *TH_EXT = BitfieldExtract(N0, Msb, Lsb, DL, VT); 74206c3fb27SDimitry Andric ReplaceNode(Node, TH_EXT); 74306c3fb27SDimitry Andric return true; 74406c3fb27SDimitry Andric } 74506c3fb27SDimitry Andric 74606c3fb27SDimitry Andric return false; 74706c3fb27SDimitry Andric } 74806c3fb27SDimitry Andric 74906c3fb27SDimitry Andric bool RISCVDAGToDAGISel::tryIndexedLoad(SDNode *Node) { 75006c3fb27SDimitry Andric // Target does not support indexed loads. 75106c3fb27SDimitry Andric if (!Subtarget->hasVendorXTHeadMemIdx()) 75206c3fb27SDimitry Andric return false; 75306c3fb27SDimitry Andric 75406c3fb27SDimitry Andric LoadSDNode *Ld = cast<LoadSDNode>(Node); 75506c3fb27SDimitry Andric ISD::MemIndexedMode AM = Ld->getAddressingMode(); 75606c3fb27SDimitry Andric if (AM == ISD::UNINDEXED) 75706c3fb27SDimitry Andric return false; 75806c3fb27SDimitry Andric 75906c3fb27SDimitry Andric const ConstantSDNode *C = dyn_cast<ConstantSDNode>(Ld->getOffset()); 76006c3fb27SDimitry Andric if (!C) 76106c3fb27SDimitry Andric return false; 76206c3fb27SDimitry Andric 76306c3fb27SDimitry Andric EVT LoadVT = Ld->getMemoryVT(); 7641db9f3b2SDimitry Andric assert((AM == ISD::PRE_INC || AM == ISD::POST_INC) && 7651db9f3b2SDimitry Andric "Unexpected addressing mode"); 7661db9f3b2SDimitry Andric bool IsPre = AM == ISD::PRE_INC; 7671db9f3b2SDimitry Andric bool IsPost = AM == ISD::POST_INC; 76806c3fb27SDimitry Andric int64_t Offset = C->getSExtValue(); 76906c3fb27SDimitry Andric 77006c3fb27SDimitry Andric // The constants that can be encoded in the THeadMemIdx instructions 77106c3fb27SDimitry Andric // are of the form (sign_extend(imm5) << imm2). 77206c3fb27SDimitry Andric int64_t Shift; 77306c3fb27SDimitry Andric for (Shift = 0; Shift < 4; Shift++) 77406c3fb27SDimitry Andric if (isInt<5>(Offset >> Shift) && ((Offset % (1LL << Shift)) == 0)) 77506c3fb27SDimitry Andric break; 77606c3fb27SDimitry Andric 77706c3fb27SDimitry Andric // Constant cannot be encoded. 77806c3fb27SDimitry Andric if (Shift == 4) 77906c3fb27SDimitry Andric return false; 78006c3fb27SDimitry Andric 78106c3fb27SDimitry Andric bool IsZExt = (Ld->getExtensionType() == ISD::ZEXTLOAD); 78206c3fb27SDimitry Andric unsigned Opcode; 78306c3fb27SDimitry Andric if (LoadVT == MVT::i8 && IsPre) 78406c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LBUIB : RISCV::TH_LBIB; 78506c3fb27SDimitry Andric else if (LoadVT == MVT::i8 && IsPost) 78606c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LBUIA : RISCV::TH_LBIA; 78706c3fb27SDimitry Andric else if (LoadVT == MVT::i16 && IsPre) 78806c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LHUIB : RISCV::TH_LHIB; 78906c3fb27SDimitry Andric else if (LoadVT == MVT::i16 && IsPost) 79006c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LHUIA : RISCV::TH_LHIA; 79106c3fb27SDimitry Andric else if (LoadVT == MVT::i32 && IsPre) 79206c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LWUIB : RISCV::TH_LWIB; 79306c3fb27SDimitry Andric else if (LoadVT == MVT::i32 && IsPost) 79406c3fb27SDimitry Andric Opcode = IsZExt ? RISCV::TH_LWUIA : RISCV::TH_LWIA; 79506c3fb27SDimitry Andric else if (LoadVT == MVT::i64 && IsPre) 79606c3fb27SDimitry Andric Opcode = RISCV::TH_LDIB; 79706c3fb27SDimitry Andric else if (LoadVT == MVT::i64 && IsPost) 79806c3fb27SDimitry Andric Opcode = RISCV::TH_LDIA; 79906c3fb27SDimitry Andric else 80006c3fb27SDimitry Andric return false; 80106c3fb27SDimitry Andric 80206c3fb27SDimitry Andric EVT Ty = Ld->getOffset().getValueType(); 80306c3fb27SDimitry Andric SDValue Ops[] = {Ld->getBasePtr(), 80406c3fb27SDimitry Andric CurDAG->getTargetConstant(Offset >> Shift, SDLoc(Node), Ty), 80506c3fb27SDimitry Andric CurDAG->getTargetConstant(Shift, SDLoc(Node), Ty), 80606c3fb27SDimitry Andric Ld->getChain()}; 80706c3fb27SDimitry Andric SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(Node), Ld->getValueType(0), 80806c3fb27SDimitry Andric Ld->getValueType(1), MVT::Other, Ops); 80906c3fb27SDimitry Andric 81006c3fb27SDimitry Andric MachineMemOperand *MemOp = cast<MemSDNode>(Node)->getMemOperand(); 81106c3fb27SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(New), {MemOp}); 81206c3fb27SDimitry Andric 81306c3fb27SDimitry Andric ReplaceNode(Node, New); 81406c3fb27SDimitry Andric 81506c3fb27SDimitry Andric return true; 81606c3fb27SDimitry Andric } 81706c3fb27SDimitry Andric 818*0fca6ea1SDimitry Andric void RISCVDAGToDAGISel::selectSF_VC_X_SE(SDNode *Node) { 819*0fca6ea1SDimitry Andric if (!Subtarget->hasVInstructions()) 820*0fca6ea1SDimitry Andric return; 821*0fca6ea1SDimitry Andric 822*0fca6ea1SDimitry Andric assert(Node->getOpcode() == ISD::INTRINSIC_VOID && "Unexpected opcode"); 823*0fca6ea1SDimitry Andric 824*0fca6ea1SDimitry Andric SDLoc DL(Node); 825*0fca6ea1SDimitry Andric unsigned IntNo = Node->getConstantOperandVal(1); 826*0fca6ea1SDimitry Andric 827*0fca6ea1SDimitry Andric assert((IntNo == Intrinsic::riscv_sf_vc_x_se || 828*0fca6ea1SDimitry Andric IntNo == Intrinsic::riscv_sf_vc_i_se) && 829*0fca6ea1SDimitry Andric "Unexpected vsetvli intrinsic"); 830*0fca6ea1SDimitry Andric 831*0fca6ea1SDimitry Andric // imm, imm, imm, simm5/scalar, sew, log2lmul, vl 832*0fca6ea1SDimitry Andric unsigned Log2SEW = Log2_32(Node->getConstantOperandVal(6)); 833*0fca6ea1SDimitry Andric SDValue SEWOp = 834*0fca6ea1SDimitry Andric CurDAG->getTargetConstant(Log2SEW, DL, Subtarget->getXLenVT()); 835*0fca6ea1SDimitry Andric SmallVector<SDValue, 8> Operands = {Node->getOperand(2), Node->getOperand(3), 836*0fca6ea1SDimitry Andric Node->getOperand(4), Node->getOperand(5), 837*0fca6ea1SDimitry Andric Node->getOperand(8), SEWOp, 838*0fca6ea1SDimitry Andric Node->getOperand(0)}; 839*0fca6ea1SDimitry Andric 840*0fca6ea1SDimitry Andric unsigned Opcode; 841*0fca6ea1SDimitry Andric auto *LMulSDNode = cast<ConstantSDNode>(Node->getOperand(7)); 842*0fca6ea1SDimitry Andric switch (LMulSDNode->getSExtValue()) { 843*0fca6ea1SDimitry Andric case 5: 844*0fca6ea1SDimitry Andric Opcode = IntNo == Intrinsic::riscv_sf_vc_x_se ? RISCV::PseudoVC_X_SE_MF8 845*0fca6ea1SDimitry Andric : RISCV::PseudoVC_I_SE_MF8; 846*0fca6ea1SDimitry Andric break; 847*0fca6ea1SDimitry Andric case 6: 848*0fca6ea1SDimitry Andric Opcode = IntNo == Intrinsic::riscv_sf_vc_x_se ? RISCV::PseudoVC_X_SE_MF4 849*0fca6ea1SDimitry Andric : RISCV::PseudoVC_I_SE_MF4; 850*0fca6ea1SDimitry Andric break; 851*0fca6ea1SDimitry Andric case 7: 852*0fca6ea1SDimitry Andric Opcode = IntNo == Intrinsic::riscv_sf_vc_x_se ? RISCV::PseudoVC_X_SE_MF2 853*0fca6ea1SDimitry Andric : RISCV::PseudoVC_I_SE_MF2; 854*0fca6ea1SDimitry Andric break; 855*0fca6ea1SDimitry Andric case 0: 856*0fca6ea1SDimitry Andric Opcode = IntNo == Intrinsic::riscv_sf_vc_x_se ? RISCV::PseudoVC_X_SE_M1 857*0fca6ea1SDimitry Andric : RISCV::PseudoVC_I_SE_M1; 858*0fca6ea1SDimitry Andric break; 859*0fca6ea1SDimitry Andric case 1: 860*0fca6ea1SDimitry Andric Opcode = IntNo == Intrinsic::riscv_sf_vc_x_se ? RISCV::PseudoVC_X_SE_M2 861*0fca6ea1SDimitry Andric : RISCV::PseudoVC_I_SE_M2; 862*0fca6ea1SDimitry Andric break; 863*0fca6ea1SDimitry Andric case 2: 864*0fca6ea1SDimitry Andric Opcode = IntNo == Intrinsic::riscv_sf_vc_x_se ? RISCV::PseudoVC_X_SE_M4 865*0fca6ea1SDimitry Andric : RISCV::PseudoVC_I_SE_M4; 866*0fca6ea1SDimitry Andric break; 867*0fca6ea1SDimitry Andric case 3: 868*0fca6ea1SDimitry Andric Opcode = IntNo == Intrinsic::riscv_sf_vc_x_se ? RISCV::PseudoVC_X_SE_M8 869*0fca6ea1SDimitry Andric : RISCV::PseudoVC_I_SE_M8; 870*0fca6ea1SDimitry Andric break; 871*0fca6ea1SDimitry Andric } 872*0fca6ea1SDimitry Andric 873*0fca6ea1SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode( 874*0fca6ea1SDimitry Andric Opcode, DL, Node->getSimpleValueType(0), Operands)); 875*0fca6ea1SDimitry Andric } 876*0fca6ea1SDimitry Andric 8770b57cec5SDimitry Andric void RISCVDAGToDAGISel::Select(SDNode *Node) { 8780b57cec5SDimitry Andric // If we have a custom node, we have already selected. 8790b57cec5SDimitry Andric if (Node->isMachineOpcode()) { 8800b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n"); 8810b57cec5SDimitry Andric Node->setNodeId(-1); 8820b57cec5SDimitry Andric return; 8830b57cec5SDimitry Andric } 8840b57cec5SDimitry Andric 8850b57cec5SDimitry Andric // Instruction Selection not handled by the auto-generated tablegen selection 8860b57cec5SDimitry Andric // should be handled here. 8870b57cec5SDimitry Andric unsigned Opcode = Node->getOpcode(); 8880b57cec5SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 8890b57cec5SDimitry Andric SDLoc DL(Node); 890fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 8910b57cec5SDimitry Andric 89206c3fb27SDimitry Andric bool HasBitTest = Subtarget->hasStdExtZbs() || Subtarget->hasVendorXTHeadBs(); 89306c3fb27SDimitry Andric 8940b57cec5SDimitry Andric switch (Opcode) { 8950b57cec5SDimitry Andric case ISD::Constant: { 8965f757f3fSDimitry Andric assert((VT == Subtarget->getXLenVT() || VT == MVT::i32) && "Unexpected VT"); 897fe6060f1SDimitry Andric auto *ConstNode = cast<ConstantSDNode>(Node); 89806c3fb27SDimitry Andric if (ConstNode->isZero()) { 899e8d8bef9SDimitry Andric SDValue New = 90006c3fb27SDimitry Andric CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, RISCV::X0, VT); 9010b57cec5SDimitry Andric ReplaceNode(Node, New.getNode()); 9020b57cec5SDimitry Andric return; 9030b57cec5SDimitry Andric } 904349cc55cSDimitry Andric int64_t Imm = ConstNode->getSExtValue(); 905*0fca6ea1SDimitry Andric // If only the lower 8 bits are used, try to convert this to a simm6 by 906*0fca6ea1SDimitry Andric // sign-extending bit 7. This is neutral without the C extension, and 907*0fca6ea1SDimitry Andric // allows C.LI to be used if C is present. 908*0fca6ea1SDimitry Andric if (isUInt<8>(Imm) && isInt<6>(SignExtend64<8>(Imm)) && hasAllBUsers(Node)) 909*0fca6ea1SDimitry Andric Imm = SignExtend64<8>(Imm); 910349cc55cSDimitry Andric // If the upper XLen-16 bits are not used, try to convert this to a simm12 911349cc55cSDimitry Andric // by sign extending bit 15. 91281ad6265SDimitry Andric if (isUInt<16>(Imm) && isInt<12>(SignExtend64<16>(Imm)) && 913349cc55cSDimitry Andric hasAllHUsers(Node)) 91481ad6265SDimitry Andric Imm = SignExtend64<16>(Imm); 915349cc55cSDimitry Andric // If the upper 32-bits are not used try to convert this into a simm32 by 916349cc55cSDimitry Andric // sign extending bit 32. 917349cc55cSDimitry Andric if (!isInt<32>(Imm) && isUInt<32>(Imm) && hasAllWUsers(Node)) 91881ad6265SDimitry Andric Imm = SignExtend64<32>(Imm); 919349cc55cSDimitry Andric 92006c3fb27SDimitry Andric ReplaceNode(Node, selectImm(CurDAG, DL, VT, Imm, *Subtarget).getNode()); 92106c3fb27SDimitry Andric return; 92206c3fb27SDimitry Andric } 92306c3fb27SDimitry Andric case ISD::ConstantFP: { 92406c3fb27SDimitry Andric const APFloat &APF = cast<ConstantFPSDNode>(Node)->getValueAPF(); 9255f757f3fSDimitry Andric auto [FPImm, NeedsFNeg] = 9265f757f3fSDimitry Andric static_cast<const RISCVTargetLowering *>(TLI)->getLegalZfaFPImm(APF, 9275f757f3fSDimitry Andric VT); 92806c3fb27SDimitry Andric if (FPImm >= 0) { 92906c3fb27SDimitry Andric unsigned Opc; 9305f757f3fSDimitry Andric unsigned FNegOpc; 93106c3fb27SDimitry Andric switch (VT.SimpleTy) { 93206c3fb27SDimitry Andric default: 93306c3fb27SDimitry Andric llvm_unreachable("Unexpected size"); 93406c3fb27SDimitry Andric case MVT::f16: 93506c3fb27SDimitry Andric Opc = RISCV::FLI_H; 9365f757f3fSDimitry Andric FNegOpc = RISCV::FSGNJN_H; 93706c3fb27SDimitry Andric break; 93806c3fb27SDimitry Andric case MVT::f32: 93906c3fb27SDimitry Andric Opc = RISCV::FLI_S; 9405f757f3fSDimitry Andric FNegOpc = RISCV::FSGNJN_S; 94106c3fb27SDimitry Andric break; 94206c3fb27SDimitry Andric case MVT::f64: 94306c3fb27SDimitry Andric Opc = RISCV::FLI_D; 9445f757f3fSDimitry Andric FNegOpc = RISCV::FSGNJN_D; 94506c3fb27SDimitry Andric break; 94606c3fb27SDimitry Andric } 94706c3fb27SDimitry Andric SDNode *Res = CurDAG->getMachineNode( 94806c3fb27SDimitry Andric Opc, DL, VT, CurDAG->getTargetConstant(FPImm, DL, XLenVT)); 9495f757f3fSDimitry Andric if (NeedsFNeg) 9505f757f3fSDimitry Andric Res = CurDAG->getMachineNode(FNegOpc, DL, VT, SDValue(Res, 0), 9515f757f3fSDimitry Andric SDValue(Res, 0)); 9525f757f3fSDimitry Andric 95306c3fb27SDimitry Andric ReplaceNode(Node, Res); 95406c3fb27SDimitry Andric return; 95506c3fb27SDimitry Andric } 95606c3fb27SDimitry Andric 95706c3fb27SDimitry Andric bool NegZeroF64 = APF.isNegZero() && VT == MVT::f64; 95806c3fb27SDimitry Andric SDValue Imm; 95906c3fb27SDimitry Andric // For +0.0 or f64 -0.0 we need to start from X0. For all others, we will 96006c3fb27SDimitry Andric // create an integer immediate. 96106c3fb27SDimitry Andric if (APF.isPosZero() || NegZeroF64) 96206c3fb27SDimitry Andric Imm = CurDAG->getRegister(RISCV::X0, XLenVT); 96306c3fb27SDimitry Andric else 96406c3fb27SDimitry Andric Imm = selectImm(CurDAG, DL, XLenVT, APF.bitcastToAPInt().getSExtValue(), 96506c3fb27SDimitry Andric *Subtarget); 96606c3fb27SDimitry Andric 9675f757f3fSDimitry Andric bool HasZdinx = Subtarget->hasStdExtZdinx(); 9685f757f3fSDimitry Andric bool Is64Bit = Subtarget->is64Bit(); 96906c3fb27SDimitry Andric unsigned Opc; 97006c3fb27SDimitry Andric switch (VT.SimpleTy) { 97106c3fb27SDimitry Andric default: 97206c3fb27SDimitry Andric llvm_unreachable("Unexpected size"); 9735f757f3fSDimitry Andric case MVT::bf16: 9745f757f3fSDimitry Andric assert(Subtarget->hasStdExtZfbfmin()); 9755f757f3fSDimitry Andric Opc = RISCV::FMV_H_X; 9765f757f3fSDimitry Andric break; 97706c3fb27SDimitry Andric case MVT::f16: 978cb14a3feSDimitry Andric Opc = Subtarget->hasStdExtZhinxmin() ? RISCV::COPY : RISCV::FMV_H_X; 97906c3fb27SDimitry Andric break; 98006c3fb27SDimitry Andric case MVT::f32: 98106c3fb27SDimitry Andric Opc = Subtarget->hasStdExtZfinx() ? RISCV::COPY : RISCV::FMV_W_X; 98206c3fb27SDimitry Andric break; 98306c3fb27SDimitry Andric case MVT::f64: 98406c3fb27SDimitry Andric // For RV32, we can't move from a GPR, we need to convert instead. This 98506c3fb27SDimitry Andric // should only happen for +0.0 and -0.0. 98606c3fb27SDimitry Andric assert((Subtarget->is64Bit() || APF.isZero()) && "Unexpected constant"); 9875f757f3fSDimitry Andric if (Is64Bit) 98806c3fb27SDimitry Andric Opc = HasZdinx ? RISCV::COPY : RISCV::FMV_D_X; 98906c3fb27SDimitry Andric else 99006c3fb27SDimitry Andric Opc = HasZdinx ? RISCV::FCVT_D_W_IN32X : RISCV::FCVT_D_W; 99106c3fb27SDimitry Andric break; 99206c3fb27SDimitry Andric } 99306c3fb27SDimitry Andric 9945f757f3fSDimitry Andric SDNode *Res; 9955f757f3fSDimitry Andric if (Opc == RISCV::FCVT_D_W_IN32X || Opc == RISCV::FCVT_D_W) 9965f757f3fSDimitry Andric Res = CurDAG->getMachineNode( 9975f757f3fSDimitry Andric Opc, DL, VT, Imm, 9985f757f3fSDimitry Andric CurDAG->getTargetConstant(RISCVFPRndMode::RNE, DL, XLenVT)); 9995f757f3fSDimitry Andric else 10005f757f3fSDimitry Andric Res = CurDAG->getMachineNode(Opc, DL, VT, Imm); 100106c3fb27SDimitry Andric 100206c3fb27SDimitry Andric // For f64 -0.0, we need to insert a fneg.d idiom. 10035f757f3fSDimitry Andric if (NegZeroF64) { 10045f757f3fSDimitry Andric Opc = RISCV::FSGNJN_D; 10055f757f3fSDimitry Andric if (HasZdinx) 10065f757f3fSDimitry Andric Opc = Is64Bit ? RISCV::FSGNJN_D_INX : RISCV::FSGNJN_D_IN32X; 10075f757f3fSDimitry Andric Res = 10085f757f3fSDimitry Andric CurDAG->getMachineNode(Opc, DL, VT, SDValue(Res, 0), SDValue(Res, 0)); 10095f757f3fSDimitry Andric } 101006c3fb27SDimitry Andric 101106c3fb27SDimitry Andric ReplaceNode(Node, Res); 101206c3fb27SDimitry Andric return; 101306c3fb27SDimitry Andric } 1014*0fca6ea1SDimitry Andric case RISCVISD::BuildPairF64: { 1015*0fca6ea1SDimitry Andric if (!Subtarget->hasStdExtZdinx()) 1016*0fca6ea1SDimitry Andric break; 1017*0fca6ea1SDimitry Andric 1018*0fca6ea1SDimitry Andric assert(!Subtarget->is64Bit() && "Unexpected subtarget"); 1019*0fca6ea1SDimitry Andric 1020*0fca6ea1SDimitry Andric SDValue Ops[] = { 1021*0fca6ea1SDimitry Andric CurDAG->getTargetConstant(RISCV::GPRPairRegClassID, DL, MVT::i32), 1022*0fca6ea1SDimitry Andric Node->getOperand(0), 1023*0fca6ea1SDimitry Andric CurDAG->getTargetConstant(RISCV::sub_gpr_even, DL, MVT::i32), 1024*0fca6ea1SDimitry Andric Node->getOperand(1), 1025*0fca6ea1SDimitry Andric CurDAG->getTargetConstant(RISCV::sub_gpr_odd, DL, MVT::i32)}; 1026*0fca6ea1SDimitry Andric 1027*0fca6ea1SDimitry Andric SDNode *N = 1028*0fca6ea1SDimitry Andric CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, DL, MVT::f64, Ops); 1029*0fca6ea1SDimitry Andric ReplaceNode(Node, N); 1030*0fca6ea1SDimitry Andric return; 1031*0fca6ea1SDimitry Andric } 103206c3fb27SDimitry Andric case RISCVISD::SplitF64: { 1033*0fca6ea1SDimitry Andric if (Subtarget->hasStdExtZdinx()) { 1034*0fca6ea1SDimitry Andric assert(!Subtarget->is64Bit() && "Unexpected subtarget"); 1035*0fca6ea1SDimitry Andric 1036*0fca6ea1SDimitry Andric if (!SDValue(Node, 0).use_empty()) { 1037*0fca6ea1SDimitry Andric SDValue Lo = CurDAG->getTargetExtractSubreg(RISCV::sub_gpr_even, DL, VT, 1038*0fca6ea1SDimitry Andric Node->getOperand(0)); 1039*0fca6ea1SDimitry Andric ReplaceUses(SDValue(Node, 0), Lo); 1040*0fca6ea1SDimitry Andric } 1041*0fca6ea1SDimitry Andric 1042*0fca6ea1SDimitry Andric if (!SDValue(Node, 1).use_empty()) { 1043*0fca6ea1SDimitry Andric SDValue Hi = CurDAG->getTargetExtractSubreg(RISCV::sub_gpr_odd, DL, VT, 1044*0fca6ea1SDimitry Andric Node->getOperand(0)); 1045*0fca6ea1SDimitry Andric ReplaceUses(SDValue(Node, 1), Hi); 1046*0fca6ea1SDimitry Andric } 1047*0fca6ea1SDimitry Andric 1048*0fca6ea1SDimitry Andric CurDAG->RemoveDeadNode(Node); 1049*0fca6ea1SDimitry Andric return; 1050*0fca6ea1SDimitry Andric } 1051*0fca6ea1SDimitry Andric 105206c3fb27SDimitry Andric if (!Subtarget->hasStdExtZfa()) 105306c3fb27SDimitry Andric break; 105406c3fb27SDimitry Andric assert(Subtarget->hasStdExtD() && !Subtarget->is64Bit() && 105506c3fb27SDimitry Andric "Unexpected subtarget"); 105606c3fb27SDimitry Andric 105706c3fb27SDimitry Andric // With Zfa, lower to fmv.x.w and fmvh.x.d. 105806c3fb27SDimitry Andric if (!SDValue(Node, 0).use_empty()) { 105906c3fb27SDimitry Andric SDNode *Lo = CurDAG->getMachineNode(RISCV::FMV_X_W_FPR64, DL, VT, 106006c3fb27SDimitry Andric Node->getOperand(0)); 106106c3fb27SDimitry Andric ReplaceUses(SDValue(Node, 0), SDValue(Lo, 0)); 106206c3fb27SDimitry Andric } 106306c3fb27SDimitry Andric if (!SDValue(Node, 1).use_empty()) { 106406c3fb27SDimitry Andric SDNode *Hi = CurDAG->getMachineNode(RISCV::FMVH_X_D, DL, VT, 106506c3fb27SDimitry Andric Node->getOperand(0)); 106606c3fb27SDimitry Andric ReplaceUses(SDValue(Node, 1), SDValue(Hi, 0)); 106706c3fb27SDimitry Andric } 106806c3fb27SDimitry Andric 106906c3fb27SDimitry Andric CurDAG->RemoveDeadNode(Node); 10700b57cec5SDimitry Andric return; 10710b57cec5SDimitry Andric } 107281ad6265SDimitry Andric case ISD::SHL: { 1073fe6060f1SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 107404eeddc0SDimitry Andric if (!N1C) 107504eeddc0SDimitry Andric break; 1076fe6060f1SDimitry Andric SDValue N0 = Node->getOperand(0); 107704eeddc0SDimitry Andric if (N0.getOpcode() != ISD::AND || !N0.hasOneUse() || 107804eeddc0SDimitry Andric !isa<ConstantSDNode>(N0.getOperand(1))) 107904eeddc0SDimitry Andric break; 108004eeddc0SDimitry Andric unsigned ShAmt = N1C->getZExtValue(); 1081fe6060f1SDimitry Andric uint64_t Mask = N0.getConstantOperandVal(1); 108281ad6265SDimitry Andric 108381ad6265SDimitry Andric // Optimize (shl (and X, C2), C) -> (slli (srliw X, C3), C3+C) where C2 has 108481ad6265SDimitry Andric // 32 leading zeros and C3 trailing zeros. 108581ad6265SDimitry Andric if (ShAmt <= 32 && isShiftedMask_64(Mask)) { 108681ad6265SDimitry Andric unsigned XLen = Subtarget->getXLen(); 1087bdd1243dSDimitry Andric unsigned LeadingZeros = XLen - llvm::bit_width(Mask); 108806c3fb27SDimitry Andric unsigned TrailingZeros = llvm::countr_zero(Mask); 108981ad6265SDimitry Andric if (TrailingZeros > 0 && LeadingZeros == 32) { 109081ad6265SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 109181ad6265SDimitry Andric RISCV::SRLIW, DL, VT, N0->getOperand(0), 109281ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros, DL, VT)); 109381ad6265SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 109481ad6265SDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 109581ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros + ShAmt, DL, VT)); 109681ad6265SDimitry Andric ReplaceNode(Node, SLLI); 109781ad6265SDimitry Andric return; 109881ad6265SDimitry Andric } 109981ad6265SDimitry Andric } 110081ad6265SDimitry Andric break; 110181ad6265SDimitry Andric } 110281ad6265SDimitry Andric case ISD::SRL: { 110381ad6265SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 110481ad6265SDimitry Andric if (!N1C) 110581ad6265SDimitry Andric break; 110681ad6265SDimitry Andric SDValue N0 = Node->getOperand(0); 1107bdd1243dSDimitry Andric if (N0.getOpcode() != ISD::AND || !isa<ConstantSDNode>(N0.getOperand(1))) 110881ad6265SDimitry Andric break; 110981ad6265SDimitry Andric unsigned ShAmt = N1C->getZExtValue(); 111081ad6265SDimitry Andric uint64_t Mask = N0.getConstantOperandVal(1); 111181ad6265SDimitry Andric 111281ad6265SDimitry Andric // Optimize (srl (and X, C2), C) -> (slli (srliw X, C3), C3-C) where C2 has 111381ad6265SDimitry Andric // 32 leading zeros and C3 trailing zeros. 1114bdd1243dSDimitry Andric if (isShiftedMask_64(Mask) && N0.hasOneUse()) { 111581ad6265SDimitry Andric unsigned XLen = Subtarget->getXLen(); 1116bdd1243dSDimitry Andric unsigned LeadingZeros = XLen - llvm::bit_width(Mask); 111706c3fb27SDimitry Andric unsigned TrailingZeros = llvm::countr_zero(Mask); 111881ad6265SDimitry Andric if (LeadingZeros == 32 && TrailingZeros > ShAmt) { 111981ad6265SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 112081ad6265SDimitry Andric RISCV::SRLIW, DL, VT, N0->getOperand(0), 112181ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros, DL, VT)); 112281ad6265SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 112381ad6265SDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 112481ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros - ShAmt, DL, VT)); 112581ad6265SDimitry Andric ReplaceNode(Node, SLLI); 112681ad6265SDimitry Andric return; 112781ad6265SDimitry Andric } 112881ad6265SDimitry Andric } 112981ad6265SDimitry Andric 113081ad6265SDimitry Andric // Optimize (srl (and X, C2), C) -> 113181ad6265SDimitry Andric // (srli (slli X, (XLen-C3), (XLen-C3) + C) 113281ad6265SDimitry Andric // Where C2 is a mask with C3 trailing ones. 113381ad6265SDimitry Andric // Taking into account that the C2 may have had lower bits unset by 113481ad6265SDimitry Andric // SimplifyDemandedBits. This avoids materializing the C2 immediate. 113581ad6265SDimitry Andric // This pattern occurs when type legalizing right shifts for types with 113681ad6265SDimitry Andric // less than XLen bits. 1137fe6060f1SDimitry Andric Mask |= maskTrailingOnes<uint64_t>(ShAmt); 113804eeddc0SDimitry Andric if (!isMask_64(Mask)) 113904eeddc0SDimitry Andric break; 114006c3fb27SDimitry Andric unsigned TrailingOnes = llvm::countr_one(Mask); 1141bdd1243dSDimitry Andric if (ShAmt >= TrailingOnes) 114204eeddc0SDimitry Andric break; 11435c16e71dSDimitry Andric // If the mask has 32 trailing ones, use SRLI on RV32 or SRLIW on RV64. 1144bdd1243dSDimitry Andric if (TrailingOnes == 32) { 11455c16e71dSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 11465c16e71dSDimitry Andric Subtarget->is64Bit() ? RISCV::SRLIW : RISCV::SRLI, DL, VT, 11475c16e71dSDimitry Andric N0->getOperand(0), CurDAG->getTargetConstant(ShAmt, DL, VT)); 11485c16e71dSDimitry Andric ReplaceNode(Node, SRLI); 1149bdd1243dSDimitry Andric return; 1150bdd1243dSDimitry Andric } 1151bdd1243dSDimitry Andric 115206c3fb27SDimitry Andric // Only do the remaining transforms if the AND has one use. 1153bdd1243dSDimitry Andric if (!N0.hasOneUse()) 1154bdd1243dSDimitry Andric break; 1155bdd1243dSDimitry Andric 115606c3fb27SDimitry Andric // If C2 is (1 << ShAmt) use bexti or th.tst if possible. 115706c3fb27SDimitry Andric if (HasBitTest && ShAmt + 1 == TrailingOnes) { 115806c3fb27SDimitry Andric SDNode *BEXTI = CurDAG->getMachineNode( 115906c3fb27SDimitry Andric Subtarget->hasStdExtZbs() ? RISCV::BEXTI : RISCV::TH_TST, DL, VT, 116006c3fb27SDimitry Andric N0->getOperand(0), CurDAG->getTargetConstant(ShAmt, DL, VT)); 1161fcaf7f86SDimitry Andric ReplaceNode(Node, BEXTI); 1162fcaf7f86SDimitry Andric return; 1163fcaf7f86SDimitry Andric } 116406c3fb27SDimitry Andric 116504eeddc0SDimitry Andric unsigned LShAmt = Subtarget->getXLen() - TrailingOnes; 1166fe6060f1SDimitry Andric SDNode *SLLI = 1167fe6060f1SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0->getOperand(0), 1168fe6060f1SDimitry Andric CurDAG->getTargetConstant(LShAmt, DL, VT)); 1169fe6060f1SDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1170fe6060f1SDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 1171fe6060f1SDimitry Andric CurDAG->getTargetConstant(LShAmt + ShAmt, DL, VT)); 1172fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 1173fe6060f1SDimitry Andric return; 1174fe6060f1SDimitry Andric } 117504eeddc0SDimitry Andric case ISD::SRA: { 117606c3fb27SDimitry Andric if (trySignedBitfieldExtract(Node)) 117706c3fb27SDimitry Andric return; 117806c3fb27SDimitry Andric 117904eeddc0SDimitry Andric // Optimize (sra (sext_inreg X, i16), C) -> 118004eeddc0SDimitry Andric // (srai (slli X, (XLen-16), (XLen-16) + C) 118104eeddc0SDimitry Andric // And (sra (sext_inreg X, i8), C) -> 118204eeddc0SDimitry Andric // (srai (slli X, (XLen-8), (XLen-8) + C) 118304eeddc0SDimitry Andric // This can occur when Zbb is enabled, which makes sext_inreg i16/i8 legal. 118404eeddc0SDimitry Andric // This transform matches the code we get without Zbb. The shifts are more 118504eeddc0SDimitry Andric // compressible, and this can help expose CSE opportunities in the sdiv by 118604eeddc0SDimitry Andric // constant optimization. 118704eeddc0SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 118804eeddc0SDimitry Andric if (!N1C) 1189fe6060f1SDimitry Andric break; 119004eeddc0SDimitry Andric SDValue N0 = Node->getOperand(0); 119104eeddc0SDimitry Andric if (N0.getOpcode() != ISD::SIGN_EXTEND_INREG || !N0.hasOneUse()) 119204eeddc0SDimitry Andric break; 119304eeddc0SDimitry Andric unsigned ShAmt = N1C->getZExtValue(); 119404eeddc0SDimitry Andric unsigned ExtSize = 119504eeddc0SDimitry Andric cast<VTSDNode>(N0.getOperand(1))->getVT().getSizeInBits(); 119604eeddc0SDimitry Andric // ExtSize of 32 should use sraiw via tablegen pattern. 119704eeddc0SDimitry Andric if (ExtSize >= 32 || ShAmt >= ExtSize) 119804eeddc0SDimitry Andric break; 119904eeddc0SDimitry Andric unsigned LShAmt = Subtarget->getXLen() - ExtSize; 120004eeddc0SDimitry Andric SDNode *SLLI = 120104eeddc0SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0->getOperand(0), 120204eeddc0SDimitry Andric CurDAG->getTargetConstant(LShAmt, DL, VT)); 120304eeddc0SDimitry Andric SDNode *SRAI = CurDAG->getMachineNode( 120404eeddc0SDimitry Andric RISCV::SRAI, DL, VT, SDValue(SLLI, 0), 120504eeddc0SDimitry Andric CurDAG->getTargetConstant(LShAmt + ShAmt, DL, VT)); 120604eeddc0SDimitry Andric ReplaceNode(Node, SRAI); 120704eeddc0SDimitry Andric return; 1208fe6060f1SDimitry Andric } 1209bdd1243dSDimitry Andric case ISD::OR: 1210bdd1243dSDimitry Andric case ISD::XOR: 1211bdd1243dSDimitry Andric if (tryShrinkShlLogicImm(Node)) 1212bdd1243dSDimitry Andric return; 1213bdd1243dSDimitry Andric 1214bdd1243dSDimitry Andric break; 1215fe6060f1SDimitry Andric case ISD::AND: { 1216fe6060f1SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 1217fe6060f1SDimitry Andric if (!N1C) 1218fe6060f1SDimitry Andric break; 121906c3fb27SDimitry Andric uint64_t C1 = N1C->getZExtValue(); 122006c3fb27SDimitry Andric const bool isC1Mask = isMask_64(C1); 122106c3fb27SDimitry Andric const bool isC1ANDI = isInt<12>(C1); 1222fe6060f1SDimitry Andric 1223fe6060f1SDimitry Andric SDValue N0 = Node->getOperand(0); 1224fe6060f1SDimitry Andric 122506c3fb27SDimitry Andric auto tryUnsignedBitfieldExtract = [&](SDNode *Node, SDLoc DL, MVT VT, 122606c3fb27SDimitry Andric SDValue X, unsigned Msb, 122706c3fb27SDimitry Andric unsigned Lsb) { 122806c3fb27SDimitry Andric if (!Subtarget->hasVendorXTHeadBb()) 122906c3fb27SDimitry Andric return false; 123006c3fb27SDimitry Andric 123106c3fb27SDimitry Andric SDNode *TH_EXTU = CurDAG->getMachineNode( 123206c3fb27SDimitry Andric RISCV::TH_EXTU, DL, VT, X, CurDAG->getTargetConstant(Msb, DL, VT), 123306c3fb27SDimitry Andric CurDAG->getTargetConstant(Lsb, DL, VT)); 123406c3fb27SDimitry Andric ReplaceNode(Node, TH_EXTU); 123506c3fb27SDimitry Andric return true; 123606c3fb27SDimitry Andric }; 123706c3fb27SDimitry Andric 1238fe6060f1SDimitry Andric bool LeftShift = N0.getOpcode() == ISD::SHL; 1239bdd1243dSDimitry Andric if (LeftShift || N0.getOpcode() == ISD::SRL) { 1240fe6060f1SDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N0.getOperand(1)); 1241fe6060f1SDimitry Andric if (!C) 1242fe6060f1SDimitry Andric break; 1243753f127fSDimitry Andric unsigned C2 = C->getZExtValue(); 1244fe6060f1SDimitry Andric unsigned XLen = Subtarget->getXLen(); 1245753f127fSDimitry Andric assert((C2 > 0 && C2 < XLen) && "Unexpected shift amount!"); 1246fe6060f1SDimitry Andric 124781ad6265SDimitry Andric // Keep track of whether this is a c.andi. If we can't use c.andi, the 124881ad6265SDimitry Andric // shift pair might offer more compression opportunities. 124981ad6265SDimitry Andric // TODO: We could check for C extension here, but we don't have many lit 1250bdd1243dSDimitry Andric // tests with the C extension enabled so not checking gets better 1251bdd1243dSDimitry Andric // coverage. 125281ad6265SDimitry Andric // TODO: What if ANDI faster than shift? 125381ad6265SDimitry Andric bool IsCANDI = isInt<6>(N1C->getSExtValue()); 1254fe6060f1SDimitry Andric 1255fe6060f1SDimitry Andric // Clear irrelevant bits in the mask. 1256fe6060f1SDimitry Andric if (LeftShift) 1257fe6060f1SDimitry Andric C1 &= maskTrailingZeros<uint64_t>(C2); 1258fe6060f1SDimitry Andric else 1259fe6060f1SDimitry Andric C1 &= maskTrailingOnes<uint64_t>(XLen - C2); 1260fe6060f1SDimitry Andric 1261fe6060f1SDimitry Andric // Some transforms should only be done if the shift has a single use or 1262fe6060f1SDimitry Andric // the AND would become (srli (slli X, 32), 32) 1263fe6060f1SDimitry Andric bool OneUseOrZExtW = N0.hasOneUse() || C1 == UINT64_C(0xFFFFFFFF); 1264fe6060f1SDimitry Andric 1265fe6060f1SDimitry Andric SDValue X = N0.getOperand(0); 1266fe6060f1SDimitry Andric 1267fe6060f1SDimitry Andric // Turn (and (srl x, c2) c1) -> (srli (slli x, c3-c2), c3) if c1 is a mask 1268fe6060f1SDimitry Andric // with c3 leading zeros. 126906c3fb27SDimitry Andric if (!LeftShift && isC1Mask) { 1270bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(C1); 1271753f127fSDimitry Andric if (C2 < Leading) { 1272fe6060f1SDimitry Andric // If the number of leading zeros is C2+32 this can be SRLIW. 1273753f127fSDimitry Andric if (C2 + 32 == Leading) { 127481ad6265SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 127581ad6265SDimitry Andric RISCV::SRLIW, DL, VT, X, CurDAG->getTargetConstant(C2, DL, VT)); 1276fe6060f1SDimitry Andric ReplaceNode(Node, SRLIW); 1277fe6060f1SDimitry Andric return; 1278fe6060f1SDimitry Andric } 1279fe6060f1SDimitry Andric 1280bdd1243dSDimitry Andric // (and (srl (sexti32 Y), c2), c1) -> (srliw (sraiw Y, 31), c3 - 32) 1281bdd1243dSDimitry Andric // if c1 is a mask with c3 leading zeros and c2 >= 32 and c3-c2==1. 1282fe6060f1SDimitry Andric // 1283fe6060f1SDimitry Andric // This pattern occurs when (i32 (srl (sra 31), c3 - 32)) is type 1284fe6060f1SDimitry Andric // legalized and goes through DAG combine. 1285753f127fSDimitry Andric if (C2 >= 32 && (Leading - C2) == 1 && N0.hasOneUse() && 128681ad6265SDimitry Andric X.getOpcode() == ISD::SIGN_EXTEND_INREG && 128781ad6265SDimitry Andric cast<VTSDNode>(X.getOperand(1))->getVT() == MVT::i32) { 1288fe6060f1SDimitry Andric SDNode *SRAIW = 128981ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::SRAIW, DL, VT, X.getOperand(0), 129081ad6265SDimitry Andric CurDAG->getTargetConstant(31, DL, VT)); 1291fe6060f1SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 129281ad6265SDimitry Andric RISCV::SRLIW, DL, VT, SDValue(SRAIW, 0), 1293753f127fSDimitry Andric CurDAG->getTargetConstant(Leading - 32, DL, VT)); 1294fe6060f1SDimitry Andric ReplaceNode(Node, SRLIW); 1295fe6060f1SDimitry Andric return; 1296fe6060f1SDimitry Andric } 1297fe6060f1SDimitry Andric 129806c3fb27SDimitry Andric // Try to use an unsigned bitfield extract (e.g., th.extu) if 129906c3fb27SDimitry Andric // available. 130006c3fb27SDimitry Andric // Transform (and (srl x, C2), C1) 130106c3fb27SDimitry Andric // -> (<bfextract> x, msb, lsb) 130206c3fb27SDimitry Andric // 130306c3fb27SDimitry Andric // Make sure to keep this below the SRLIW cases, as we always want to 130406c3fb27SDimitry Andric // prefer the more common instruction. 130506c3fb27SDimitry Andric const unsigned Msb = llvm::bit_width(C1) + C2 - 1; 130606c3fb27SDimitry Andric const unsigned Lsb = C2; 130706c3fb27SDimitry Andric if (tryUnsignedBitfieldExtract(Node, DL, VT, X, Msb, Lsb)) 130806c3fb27SDimitry Andric return; 130906c3fb27SDimitry Andric 1310fe6060f1SDimitry Andric // (srli (slli x, c3-c2), c3). 131181ad6265SDimitry Andric // Skip if we could use (zext.w (sraiw X, C2)). 1312753f127fSDimitry Andric bool Skip = Subtarget->hasStdExtZba() && Leading == 32 && 131381ad6265SDimitry Andric X.getOpcode() == ISD::SIGN_EXTEND_INREG && 131481ad6265SDimitry Andric cast<VTSDNode>(X.getOperand(1))->getVT() == MVT::i32; 131506c3fb27SDimitry Andric // Also Skip if we can use bexti or th.tst. 131606c3fb27SDimitry Andric Skip |= HasBitTest && Leading == XLen - 1; 131781ad6265SDimitry Andric if (OneUseOrZExtW && !Skip) { 1318fe6060f1SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 131981ad6265SDimitry Andric RISCV::SLLI, DL, VT, X, 1320753f127fSDimitry Andric CurDAG->getTargetConstant(Leading - C2, DL, VT)); 1321753f127fSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1322753f127fSDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 1323753f127fSDimitry Andric CurDAG->getTargetConstant(Leading, DL, VT)); 1324fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 1325fe6060f1SDimitry Andric return; 1326fe6060f1SDimitry Andric } 1327fe6060f1SDimitry Andric } 1328fe6060f1SDimitry Andric } 1329fe6060f1SDimitry Andric 1330349cc55cSDimitry Andric // Turn (and (shl x, c2), c1) -> (srli (slli c2+c3), c3) if c1 is a mask 1331fe6060f1SDimitry Andric // shifted by c2 bits with c3 leading zeros. 1332fe6060f1SDimitry Andric if (LeftShift && isShiftedMask_64(C1)) { 1333bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(C1); 1334fe6060f1SDimitry Andric 1335753f127fSDimitry Andric if (C2 + Leading < XLen && 1336753f127fSDimitry Andric C1 == (maskTrailingOnes<uint64_t>(XLen - (C2 + Leading)) << C2)) { 1337fe6060f1SDimitry Andric // Use slli.uw when possible. 1338753f127fSDimitry Andric if ((XLen - (C2 + Leading)) == 32 && Subtarget->hasStdExtZba()) { 1339bdd1243dSDimitry Andric SDNode *SLLI_UW = 1340bdd1243dSDimitry Andric CurDAG->getMachineNode(RISCV::SLLI_UW, DL, VT, X, 1341bdd1243dSDimitry Andric CurDAG->getTargetConstant(C2, DL, VT)); 13421fd87a68SDimitry Andric ReplaceNode(Node, SLLI_UW); 1343fe6060f1SDimitry Andric return; 1344fe6060f1SDimitry Andric } 1345fe6060f1SDimitry Andric 1346fe6060f1SDimitry Andric // (srli (slli c2+c3), c3) 134781ad6265SDimitry Andric if (OneUseOrZExtW && !IsCANDI) { 1348fe6060f1SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 134981ad6265SDimitry Andric RISCV::SLLI, DL, VT, X, 1350753f127fSDimitry Andric CurDAG->getTargetConstant(C2 + Leading, DL, VT)); 1351753f127fSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1352753f127fSDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 1353753f127fSDimitry Andric CurDAG->getTargetConstant(Leading, DL, VT)); 1354fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 1355fe6060f1SDimitry Andric return; 1356fe6060f1SDimitry Andric } 1357fe6060f1SDimitry Andric } 1358fe6060f1SDimitry Andric } 1359fe6060f1SDimitry Andric 1360349cc55cSDimitry Andric // Turn (and (shr x, c2), c1) -> (slli (srli x, c2+c3), c3) if c1 is a 1361349cc55cSDimitry Andric // shifted mask with c2 leading zeros and c3 trailing zeros. 1362349cc55cSDimitry Andric if (!LeftShift && isShiftedMask_64(C1)) { 1363bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(C1); 136406c3fb27SDimitry Andric unsigned Trailing = llvm::countr_zero(C1); 1365bdd1243dSDimitry Andric if (Leading == C2 && C2 + Trailing < XLen && OneUseOrZExtW && 1366bdd1243dSDimitry Andric !IsCANDI) { 136781ad6265SDimitry Andric unsigned SrliOpc = RISCV::SRLI; 136881ad6265SDimitry Andric // If the input is zexti32 we should use SRLIW. 1369bdd1243dSDimitry Andric if (X.getOpcode() == ISD::AND && 1370bdd1243dSDimitry Andric isa<ConstantSDNode>(X.getOperand(1)) && 137181ad6265SDimitry Andric X.getConstantOperandVal(1) == UINT64_C(0xFFFFFFFF)) { 137281ad6265SDimitry Andric SrliOpc = RISCV::SRLIW; 137381ad6265SDimitry Andric X = X.getOperand(0); 137481ad6265SDimitry Andric } 1375349cc55cSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1376753f127fSDimitry Andric SrliOpc, DL, VT, X, 1377753f127fSDimitry Andric CurDAG->getTargetConstant(C2 + Trailing, DL, VT)); 1378bdd1243dSDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 1379bdd1243dSDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLI, 0), 1380753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 1381349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 1382349cc55cSDimitry Andric return; 1383349cc55cSDimitry Andric } 1384349cc55cSDimitry Andric // If the leading zero count is C2+32, we can use SRLIW instead of SRLI. 1385753f127fSDimitry Andric if (Leading > 32 && (Leading - 32) == C2 && C2 + Trailing < 32 && 138681ad6265SDimitry Andric OneUseOrZExtW && !IsCANDI) { 1387753f127fSDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 1388753f127fSDimitry Andric RISCV::SRLIW, DL, VT, X, 1389753f127fSDimitry Andric CurDAG->getTargetConstant(C2 + Trailing, DL, VT)); 1390bdd1243dSDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 1391bdd1243dSDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 1392753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 1393349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 1394349cc55cSDimitry Andric return; 1395349cc55cSDimitry Andric } 1396349cc55cSDimitry Andric } 1397349cc55cSDimitry Andric 1398349cc55cSDimitry Andric // Turn (and (shl x, c2), c1) -> (slli (srli x, c3-c2), c3) if c1 is a 1399349cc55cSDimitry Andric // shifted mask with no leading zeros and c3 trailing zeros. 1400349cc55cSDimitry Andric if (LeftShift && isShiftedMask_64(C1)) { 1401bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(C1); 140206c3fb27SDimitry Andric unsigned Trailing = llvm::countr_zero(C1); 1403753f127fSDimitry Andric if (Leading == 0 && C2 < Trailing && OneUseOrZExtW && !IsCANDI) { 1404349cc55cSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1405753f127fSDimitry Andric RISCV::SRLI, DL, VT, X, 1406753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)); 1407bdd1243dSDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 1408bdd1243dSDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLI, 0), 1409753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 1410349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 1411349cc55cSDimitry Andric return; 1412349cc55cSDimitry Andric } 1413349cc55cSDimitry Andric // If we have (32-C2) leading zeros, we can use SRLIW instead of SRLI. 1414753f127fSDimitry Andric if (C2 < Trailing && Leading + C2 == 32 && OneUseOrZExtW && !IsCANDI) { 1415753f127fSDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 1416753f127fSDimitry Andric RISCV::SRLIW, DL, VT, X, 1417753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)); 1418bdd1243dSDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 1419bdd1243dSDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 1420753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 1421349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 1422349cc55cSDimitry Andric return; 1423349cc55cSDimitry Andric } 1424*0fca6ea1SDimitry Andric 1425*0fca6ea1SDimitry Andric // If we have 32 bits in the mask, we can use SLLI_UW instead of SLLI. 1426*0fca6ea1SDimitry Andric if (C2 < Trailing && Leading + Trailing == 32 && OneUseOrZExtW && 1427*0fca6ea1SDimitry Andric Subtarget->hasStdExtZba()) { 1428*0fca6ea1SDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 1429*0fca6ea1SDimitry Andric RISCV::SRLI, DL, VT, X, 1430*0fca6ea1SDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)); 1431*0fca6ea1SDimitry Andric SDNode *SLLI_UW = CurDAG->getMachineNode( 1432*0fca6ea1SDimitry Andric RISCV::SLLI_UW, DL, VT, SDValue(SRLI, 0), 1433*0fca6ea1SDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 1434*0fca6ea1SDimitry Andric ReplaceNode(Node, SLLI_UW); 1435*0fca6ea1SDimitry Andric return; 1436*0fca6ea1SDimitry Andric } 1437349cc55cSDimitry Andric } 1438bdd1243dSDimitry Andric } 1439bdd1243dSDimitry Andric 144006c3fb27SDimitry Andric // If C1 masks off the upper bits only (but can't be formed as an 144106c3fb27SDimitry Andric // ANDI), use an unsigned bitfield extract (e.g., th.extu), if 144206c3fb27SDimitry Andric // available. 144306c3fb27SDimitry Andric // Transform (and x, C1) 144406c3fb27SDimitry Andric // -> (<bfextract> x, msb, lsb) 144506c3fb27SDimitry Andric if (isC1Mask && !isC1ANDI) { 144606c3fb27SDimitry Andric const unsigned Msb = llvm::bit_width(C1) - 1; 144706c3fb27SDimitry Andric if (tryUnsignedBitfieldExtract(Node, DL, VT, N0, Msb, 0)) 144806c3fb27SDimitry Andric return; 144906c3fb27SDimitry Andric } 145006c3fb27SDimitry Andric 1451bdd1243dSDimitry Andric if (tryShrinkShlLogicImm(Node)) 1452bdd1243dSDimitry Andric return; 1453349cc55cSDimitry Andric 1454fe6060f1SDimitry Andric break; 1455fe6060f1SDimitry Andric } 14560eae32dcSDimitry Andric case ISD::MUL: { 14570eae32dcSDimitry Andric // Special case for calculating (mul (and X, C2), C1) where the full product 14580eae32dcSDimitry Andric // fits in XLen bits. We can shift X left by the number of leading zeros in 14590eae32dcSDimitry Andric // C2 and shift C1 left by XLen-lzcnt(C2). This will ensure the final 14600eae32dcSDimitry Andric // product has XLen trailing zeros, putting it in the output of MULHU. This 14610eae32dcSDimitry Andric // can avoid materializing a constant in a register for C2. 14620eae32dcSDimitry Andric 14630eae32dcSDimitry Andric // RHS should be a constant. 14640eae32dcSDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 14650eae32dcSDimitry Andric if (!N1C || !N1C->hasOneUse()) 14660eae32dcSDimitry Andric break; 14670eae32dcSDimitry Andric 14680eae32dcSDimitry Andric // LHS should be an AND with constant. 14690eae32dcSDimitry Andric SDValue N0 = Node->getOperand(0); 14700eae32dcSDimitry Andric if (N0.getOpcode() != ISD::AND || !isa<ConstantSDNode>(N0.getOperand(1))) 14710eae32dcSDimitry Andric break; 14720eae32dcSDimitry Andric 1473647cbc5dSDimitry Andric uint64_t C2 = N0.getConstantOperandVal(1); 14740eae32dcSDimitry Andric 14750eae32dcSDimitry Andric // Constant should be a mask. 14760eae32dcSDimitry Andric if (!isMask_64(C2)) 14770eae32dcSDimitry Andric break; 14780eae32dcSDimitry Andric 147906c3fb27SDimitry Andric // If this can be an ANDI or ZEXT.H, don't do this if the ANDI/ZEXT has 148006c3fb27SDimitry Andric // multiple users or the constant is a simm12. This prevents inserting a 148106c3fb27SDimitry Andric // shift and still have uses of the AND/ZEXT. Shifting a simm12 will likely 148206c3fb27SDimitry Andric // make it more costly to materialize. Otherwise, using a SLLI might allow 148306c3fb27SDimitry Andric // it to be compressed. 1484fcaf7f86SDimitry Andric bool IsANDIOrZExt = 1485fcaf7f86SDimitry Andric isInt<12>(C2) || 148606c3fb27SDimitry Andric (C2 == UINT64_C(0xFFFF) && Subtarget->hasStdExtZbb()); 148706c3fb27SDimitry Andric // With XTHeadBb, we can use TH.EXTU. 148806c3fb27SDimitry Andric IsANDIOrZExt |= C2 == UINT64_C(0xFFFF) && Subtarget->hasVendorXTHeadBb(); 1489fcaf7f86SDimitry Andric if (IsANDIOrZExt && (isInt<12>(N1C->getSExtValue()) || !N0.hasOneUse())) 14900eae32dcSDimitry Andric break; 149106c3fb27SDimitry Andric // If this can be a ZEXT.w, don't do this if the ZEXT has multiple users or 149206c3fb27SDimitry Andric // the constant is a simm32. 149306c3fb27SDimitry Andric bool IsZExtW = C2 == UINT64_C(0xFFFFFFFF) && Subtarget->hasStdExtZba(); 149406c3fb27SDimitry Andric // With XTHeadBb, we can use TH.EXTU. 149506c3fb27SDimitry Andric IsZExtW |= C2 == UINT64_C(0xFFFFFFFF) && Subtarget->hasVendorXTHeadBb(); 149606c3fb27SDimitry Andric if (IsZExtW && (isInt<32>(N1C->getSExtValue()) || !N0.hasOneUse())) 149706c3fb27SDimitry Andric break; 14980eae32dcSDimitry Andric 14990eae32dcSDimitry Andric // We need to shift left the AND input and C1 by a total of XLen bits. 15000eae32dcSDimitry Andric 15010eae32dcSDimitry Andric // How far left do we need to shift the AND input? 15020eae32dcSDimitry Andric unsigned XLen = Subtarget->getXLen(); 1503bdd1243dSDimitry Andric unsigned LeadingZeros = XLen - llvm::bit_width(C2); 15040eae32dcSDimitry Andric 15050eae32dcSDimitry Andric // The constant gets shifted by the remaining amount unless that would 15060eae32dcSDimitry Andric // shift bits out. 15070eae32dcSDimitry Andric uint64_t C1 = N1C->getZExtValue(); 15080eae32dcSDimitry Andric unsigned ConstantShift = XLen - LeadingZeros; 1509bdd1243dSDimitry Andric if (ConstantShift > (XLen - llvm::bit_width(C1))) 15100eae32dcSDimitry Andric break; 15110eae32dcSDimitry Andric 15120eae32dcSDimitry Andric uint64_t ShiftedC1 = C1 << ConstantShift; 15130eae32dcSDimitry Andric // If this RV32, we need to sign extend the constant. 15140eae32dcSDimitry Andric if (XLen == 32) 151581ad6265SDimitry Andric ShiftedC1 = SignExtend64<32>(ShiftedC1); 15160eae32dcSDimitry Andric 15170eae32dcSDimitry Andric // Create (mulhu (slli X, lzcnt(C2)), C1 << (XLen - lzcnt(C2))). 151806c3fb27SDimitry Andric SDNode *Imm = selectImm(CurDAG, DL, VT, ShiftedC1, *Subtarget).getNode(); 15190eae32dcSDimitry Andric SDNode *SLLI = 15200eae32dcSDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0.getOperand(0), 15210eae32dcSDimitry Andric CurDAG->getTargetConstant(LeadingZeros, DL, VT)); 15220eae32dcSDimitry Andric SDNode *MULHU = CurDAG->getMachineNode(RISCV::MULHU, DL, VT, 15230eae32dcSDimitry Andric SDValue(SLLI, 0), SDValue(Imm, 0)); 15240eae32dcSDimitry Andric ReplaceNode(Node, MULHU); 15250eae32dcSDimitry Andric return; 15260eae32dcSDimitry Andric } 152706c3fb27SDimitry Andric case ISD::LOAD: { 152806c3fb27SDimitry Andric if (tryIndexedLoad(Node)) 152906c3fb27SDimitry Andric return; 1530*0fca6ea1SDimitry Andric 1531*0fca6ea1SDimitry Andric if (Subtarget->hasVendorXCVmem()) { 1532*0fca6ea1SDimitry Andric // We match post-incrementing load here 1533*0fca6ea1SDimitry Andric LoadSDNode *Load = cast<LoadSDNode>(Node); 1534*0fca6ea1SDimitry Andric if (Load->getAddressingMode() != ISD::POST_INC) 1535*0fca6ea1SDimitry Andric break; 1536*0fca6ea1SDimitry Andric 1537*0fca6ea1SDimitry Andric SDValue Chain = Node->getOperand(0); 1538*0fca6ea1SDimitry Andric SDValue Base = Node->getOperand(1); 1539*0fca6ea1SDimitry Andric SDValue Offset = Node->getOperand(2); 1540*0fca6ea1SDimitry Andric 1541*0fca6ea1SDimitry Andric bool Simm12 = false; 1542*0fca6ea1SDimitry Andric bool SignExtend = Load->getExtensionType() == ISD::SEXTLOAD; 1543*0fca6ea1SDimitry Andric 1544*0fca6ea1SDimitry Andric if (auto ConstantOffset = dyn_cast<ConstantSDNode>(Offset)) { 1545*0fca6ea1SDimitry Andric int ConstantVal = ConstantOffset->getSExtValue(); 1546*0fca6ea1SDimitry Andric Simm12 = isInt<12>(ConstantVal); 1547*0fca6ea1SDimitry Andric if (Simm12) 1548*0fca6ea1SDimitry Andric Offset = CurDAG->getTargetConstant(ConstantVal, SDLoc(Offset), 1549*0fca6ea1SDimitry Andric Offset.getValueType()); 1550*0fca6ea1SDimitry Andric } 1551*0fca6ea1SDimitry Andric 1552*0fca6ea1SDimitry Andric unsigned Opcode = 0; 1553*0fca6ea1SDimitry Andric switch (Load->getMemoryVT().getSimpleVT().SimpleTy) { 1554*0fca6ea1SDimitry Andric case MVT::i8: 1555*0fca6ea1SDimitry Andric if (Simm12 && SignExtend) 1556*0fca6ea1SDimitry Andric Opcode = RISCV::CV_LB_ri_inc; 1557*0fca6ea1SDimitry Andric else if (Simm12 && !SignExtend) 1558*0fca6ea1SDimitry Andric Opcode = RISCV::CV_LBU_ri_inc; 1559*0fca6ea1SDimitry Andric else if (!Simm12 && SignExtend) 1560*0fca6ea1SDimitry Andric Opcode = RISCV::CV_LB_rr_inc; 1561*0fca6ea1SDimitry Andric else 1562*0fca6ea1SDimitry Andric Opcode = RISCV::CV_LBU_rr_inc; 1563*0fca6ea1SDimitry Andric break; 1564*0fca6ea1SDimitry Andric case MVT::i16: 1565*0fca6ea1SDimitry Andric if (Simm12 && SignExtend) 1566*0fca6ea1SDimitry Andric Opcode = RISCV::CV_LH_ri_inc; 1567*0fca6ea1SDimitry Andric else if (Simm12 && !SignExtend) 1568*0fca6ea1SDimitry Andric Opcode = RISCV::CV_LHU_ri_inc; 1569*0fca6ea1SDimitry Andric else if (!Simm12 && SignExtend) 1570*0fca6ea1SDimitry Andric Opcode = RISCV::CV_LH_rr_inc; 1571*0fca6ea1SDimitry Andric else 1572*0fca6ea1SDimitry Andric Opcode = RISCV::CV_LHU_rr_inc; 1573*0fca6ea1SDimitry Andric break; 1574*0fca6ea1SDimitry Andric case MVT::i32: 1575*0fca6ea1SDimitry Andric if (Simm12) 1576*0fca6ea1SDimitry Andric Opcode = RISCV::CV_LW_ri_inc; 1577*0fca6ea1SDimitry Andric else 1578*0fca6ea1SDimitry Andric Opcode = RISCV::CV_LW_rr_inc; 1579*0fca6ea1SDimitry Andric break; 1580*0fca6ea1SDimitry Andric default: 1581*0fca6ea1SDimitry Andric break; 1582*0fca6ea1SDimitry Andric } 1583*0fca6ea1SDimitry Andric if (!Opcode) 1584*0fca6ea1SDimitry Andric break; 1585*0fca6ea1SDimitry Andric 1586*0fca6ea1SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(Opcode, DL, XLenVT, XLenVT, 1587*0fca6ea1SDimitry Andric Chain.getSimpleValueType(), Base, 1588*0fca6ea1SDimitry Andric Offset, Chain)); 1589*0fca6ea1SDimitry Andric return; 1590*0fca6ea1SDimitry Andric } 159106c3fb27SDimitry Andric break; 159206c3fb27SDimitry Andric } 1593fe6060f1SDimitry Andric case ISD::INTRINSIC_WO_CHAIN: { 1594fe6060f1SDimitry Andric unsigned IntNo = Node->getConstantOperandVal(0); 1595fe6060f1SDimitry Andric switch (IntNo) { 1596fe6060f1SDimitry Andric // By default we do not custom select any intrinsic. 1597fe6060f1SDimitry Andric default: 1598fe6060f1SDimitry Andric break; 1599fe6060f1SDimitry Andric case Intrinsic::riscv_vmsgeu: 1600fe6060f1SDimitry Andric case Intrinsic::riscv_vmsge: { 1601fe6060f1SDimitry Andric SDValue Src1 = Node->getOperand(1); 1602fe6060f1SDimitry Andric SDValue Src2 = Node->getOperand(2); 160304eeddc0SDimitry Andric bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu; 160404eeddc0SDimitry Andric bool IsCmpUnsignedZero = false; 1605fe6060f1SDimitry Andric // Only custom select scalar second operand. 1606fe6060f1SDimitry Andric if (Src2.getValueType() != XLenVT) 1607fe6060f1SDimitry Andric break; 1608fe6060f1SDimitry Andric // Small constants are handled with patterns. 1609fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Src2)) { 1610fe6060f1SDimitry Andric int64_t CVal = C->getSExtValue(); 161104eeddc0SDimitry Andric if (CVal >= -15 && CVal <= 16) { 161204eeddc0SDimitry Andric if (!IsUnsigned || CVal != 0) 1613fe6060f1SDimitry Andric break; 161404eeddc0SDimitry Andric IsCmpUnsignedZero = true; 1615fe6060f1SDimitry Andric } 161604eeddc0SDimitry Andric } 1617fe6060f1SDimitry Andric MVT Src1VT = Src1.getSimpleValueType(); 161804eeddc0SDimitry Andric unsigned VMSLTOpcode, VMNANDOpcode, VMSetOpcode; 1619fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(Src1VT)) { 1620fe6060f1SDimitry Andric default: 1621fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 162204eeddc0SDimitry Andric #define CASE_VMSLT_VMNAND_VMSET_OPCODES(lmulenum, suffix, suffix_b) \ 162304eeddc0SDimitry Andric case RISCVII::VLMUL::lmulenum: \ 162404eeddc0SDimitry Andric VMSLTOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix \ 162504eeddc0SDimitry Andric : RISCV::PseudoVMSLT_VX_##suffix; \ 162604eeddc0SDimitry Andric VMNANDOpcode = RISCV::PseudoVMNAND_MM_##suffix; \ 162704eeddc0SDimitry Andric VMSetOpcode = RISCV::PseudoVMSET_M_##suffix_b; \ 1628fe6060f1SDimitry Andric break; 162904eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F8, MF8, B1) 163004eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F4, MF4, B2) 163104eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F2, MF2, B4) 163204eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_1, M1, B8) 163304eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_2, M2, B16) 163404eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_4, M4, B32) 163504eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_8, M8, B64) 163604eeddc0SDimitry Andric #undef CASE_VMSLT_VMNAND_VMSET_OPCODES 1637fe6060f1SDimitry Andric } 1638fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant( 1639fe6060f1SDimitry Andric Log2_32(Src1VT.getScalarSizeInBits()), DL, XLenVT); 1640fe6060f1SDimitry Andric SDValue VL; 1641fe6060f1SDimitry Andric selectVLOp(Node->getOperand(3), VL); 1642fe6060f1SDimitry Andric 164304eeddc0SDimitry Andric // If vmsgeu with 0 immediate, expand it to vmset. 164404eeddc0SDimitry Andric if (IsCmpUnsignedZero) { 164504eeddc0SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMSetOpcode, DL, VT, VL, SEW)); 164604eeddc0SDimitry Andric return; 164704eeddc0SDimitry Andric } 164804eeddc0SDimitry Andric 1649fe6060f1SDimitry Andric // Expand to 1650fe6060f1SDimitry Andric // vmslt{u}.vx vd, va, x; vmnand.mm vd, vd, vd 1651fe6060f1SDimitry Andric SDValue Cmp = SDValue( 1652fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTOpcode, DL, VT, {Src1, Src2, VL, SEW}), 1653fe6060f1SDimitry Andric 0); 1654fe6060f1SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMNANDOpcode, DL, VT, 1655fe6060f1SDimitry Andric {Cmp, Cmp, VL, SEW})); 1656fe6060f1SDimitry Andric return; 1657fe6060f1SDimitry Andric } 1658fe6060f1SDimitry Andric case Intrinsic::riscv_vmsgeu_mask: 1659fe6060f1SDimitry Andric case Intrinsic::riscv_vmsge_mask: { 1660fe6060f1SDimitry Andric SDValue Src1 = Node->getOperand(2); 1661fe6060f1SDimitry Andric SDValue Src2 = Node->getOperand(3); 166204eeddc0SDimitry Andric bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu_mask; 166304eeddc0SDimitry Andric bool IsCmpUnsignedZero = false; 1664fe6060f1SDimitry Andric // Only custom select scalar second operand. 1665fe6060f1SDimitry Andric if (Src2.getValueType() != XLenVT) 1666fe6060f1SDimitry Andric break; 1667fe6060f1SDimitry Andric // Small constants are handled with patterns. 1668fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Src2)) { 1669fe6060f1SDimitry Andric int64_t CVal = C->getSExtValue(); 167004eeddc0SDimitry Andric if (CVal >= -15 && CVal <= 16) { 167104eeddc0SDimitry Andric if (!IsUnsigned || CVal != 0) 1672fe6060f1SDimitry Andric break; 167304eeddc0SDimitry Andric IsCmpUnsignedZero = true; 1674fe6060f1SDimitry Andric } 167504eeddc0SDimitry Andric } 1676fe6060f1SDimitry Andric MVT Src1VT = Src1.getSimpleValueType(); 167704eeddc0SDimitry Andric unsigned VMSLTOpcode, VMSLTMaskOpcode, VMXOROpcode, VMANDNOpcode, 167881ad6265SDimitry Andric VMOROpcode; 1679fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(Src1VT)) { 1680fe6060f1SDimitry Andric default: 1681fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 168281ad6265SDimitry Andric #define CASE_VMSLT_OPCODES(lmulenum, suffix, suffix_b) \ 168304eeddc0SDimitry Andric case RISCVII::VLMUL::lmulenum: \ 168404eeddc0SDimitry Andric VMSLTOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix \ 168504eeddc0SDimitry Andric : RISCV::PseudoVMSLT_VX_##suffix; \ 168604eeddc0SDimitry Andric VMSLTMaskOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix##_MASK \ 168704eeddc0SDimitry Andric : RISCV::PseudoVMSLT_VX_##suffix##_MASK; \ 1688fe6060f1SDimitry Andric break; 168981ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_F8, MF8, B1) 169081ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_F4, MF4, B2) 169181ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_F2, MF2, B4) 169281ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_1, M1, B8) 169381ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_2, M2, B16) 169481ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_4, M4, B32) 169581ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_8, M8, B64) 169681ad6265SDimitry Andric #undef CASE_VMSLT_OPCODES 1697fe6060f1SDimitry Andric } 1698fe6060f1SDimitry Andric // Mask operations use the LMUL from the mask type. 1699fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(VT)) { 1700fe6060f1SDimitry Andric default: 1701fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 170281ad6265SDimitry Andric #define CASE_VMXOR_VMANDN_VMOR_OPCODES(lmulenum, suffix) \ 170304eeddc0SDimitry Andric case RISCVII::VLMUL::lmulenum: \ 170404eeddc0SDimitry Andric VMXOROpcode = RISCV::PseudoVMXOR_MM_##suffix; \ 170504eeddc0SDimitry Andric VMANDNOpcode = RISCV::PseudoVMANDN_MM_##suffix; \ 170681ad6265SDimitry Andric VMOROpcode = RISCV::PseudoVMOR_MM_##suffix; \ 1707fe6060f1SDimitry Andric break; 170881ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_F8, MF8) 170981ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_F4, MF4) 171081ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_F2, MF2) 171181ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_1, M1) 171281ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_2, M2) 171381ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_4, M4) 171481ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_8, M8) 171581ad6265SDimitry Andric #undef CASE_VMXOR_VMANDN_VMOR_OPCODES 1716fe6060f1SDimitry Andric } 1717fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant( 1718fe6060f1SDimitry Andric Log2_32(Src1VT.getScalarSizeInBits()), DL, XLenVT); 1719fe6060f1SDimitry Andric SDValue MaskSEW = CurDAG->getTargetConstant(0, DL, XLenVT); 1720fe6060f1SDimitry Andric SDValue VL; 1721fe6060f1SDimitry Andric selectVLOp(Node->getOperand(5), VL); 1722fe6060f1SDimitry Andric SDValue MaskedOff = Node->getOperand(1); 1723fe6060f1SDimitry Andric SDValue Mask = Node->getOperand(4); 172404eeddc0SDimitry Andric 172581ad6265SDimitry Andric // If vmsgeu_mask with 0 immediate, expand it to vmor mask, maskedoff. 172604eeddc0SDimitry Andric if (IsCmpUnsignedZero) { 172781ad6265SDimitry Andric // We don't need vmor if the MaskedOff and the Mask are the same 172881ad6265SDimitry Andric // value. 172981ad6265SDimitry Andric if (Mask == MaskedOff) { 173081ad6265SDimitry Andric ReplaceUses(Node, Mask.getNode()); 173181ad6265SDimitry Andric return; 173281ad6265SDimitry Andric } 173381ad6265SDimitry Andric ReplaceNode(Node, 173481ad6265SDimitry Andric CurDAG->getMachineNode(VMOROpcode, DL, VT, 173581ad6265SDimitry Andric {Mask, MaskedOff, VL, MaskSEW})); 173604eeddc0SDimitry Andric return; 173704eeddc0SDimitry Andric } 173804eeddc0SDimitry Andric 1739fe6060f1SDimitry Andric // If the MaskedOff value and the Mask are the same value use 1740349cc55cSDimitry Andric // vmslt{u}.vx vt, va, x; vmandn.mm vd, vd, vt 1741fe6060f1SDimitry Andric // This avoids needing to copy v0 to vd before starting the next sequence. 1742fe6060f1SDimitry Andric if (Mask == MaskedOff) { 1743fe6060f1SDimitry Andric SDValue Cmp = SDValue( 1744fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTOpcode, DL, VT, {Src1, Src2, VL, SEW}), 1745fe6060f1SDimitry Andric 0); 1746349cc55cSDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMANDNOpcode, DL, VT, 1747fe6060f1SDimitry Andric {Mask, Cmp, VL, MaskSEW})); 1748fe6060f1SDimitry Andric return; 1749fe6060f1SDimitry Andric } 1750fe6060f1SDimitry Andric 1751fe6060f1SDimitry Andric // Mask needs to be copied to V0. 1752fe6060f1SDimitry Andric SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, 1753fe6060f1SDimitry Andric RISCV::V0, Mask, SDValue()); 1754fe6060f1SDimitry Andric SDValue Glue = Chain.getValue(1); 1755fe6060f1SDimitry Andric SDValue V0 = CurDAG->getRegister(RISCV::V0, VT); 1756fe6060f1SDimitry Andric 1757fe6060f1SDimitry Andric // Otherwise use 1758fe6060f1SDimitry Andric // vmslt{u}.vx vd, va, x, v0.t; vmxor.mm vd, vd, v0 175981ad6265SDimitry Andric // The result is mask undisturbed. 176081ad6265SDimitry Andric // We use the same instructions to emulate mask agnostic behavior, because 176181ad6265SDimitry Andric // the agnostic result can be either undisturbed or all 1. 1762fe6060f1SDimitry Andric SDValue Cmp = SDValue( 1763fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTMaskOpcode, DL, VT, 1764fe6060f1SDimitry Andric {MaskedOff, Src1, Src2, V0, VL, SEW, Glue}), 1765fe6060f1SDimitry Andric 0); 176681ad6265SDimitry Andric // vmxor.mm vd, vd, v0 is used to update active value. 1767fe6060f1SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMXOROpcode, DL, VT, 1768fe6060f1SDimitry Andric {Cmp, Mask, VL, MaskSEW})); 1769fe6060f1SDimitry Andric return; 1770fe6060f1SDimitry Andric } 177106c3fb27SDimitry Andric case Intrinsic::riscv_vsetvli: 177206c3fb27SDimitry Andric case Intrinsic::riscv_vsetvlimax: 177304eeddc0SDimitry Andric return selectVSETVLI(Node); 1774fe6060f1SDimitry Andric } 1775fe6060f1SDimitry Andric break; 1776fe6060f1SDimitry Andric } 1777e8d8bef9SDimitry Andric case ISD::INTRINSIC_W_CHAIN: { 1778647cbc5dSDimitry Andric unsigned IntNo = Node->getConstantOperandVal(1); 1779e8d8bef9SDimitry Andric switch (IntNo) { 1780e8d8bef9SDimitry Andric // By default we do not custom select any intrinsic. 1781e8d8bef9SDimitry Andric default: 17820b57cec5SDimitry Andric break; 1783e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg2: 1784e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg3: 1785e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg4: 1786e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg5: 1787e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg6: 1788e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg7: 1789e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg8: { 1790fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ false, /*IsStrided*/ false); 1791e8d8bef9SDimitry Andric return; 1792e8d8bef9SDimitry Andric } 1793e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg2_mask: 1794e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg3_mask: 1795e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg4_mask: 1796e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg5_mask: 1797e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg6_mask: 1798e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg7_mask: 1799e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg8_mask: { 1800fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ true, /*IsStrided*/ false); 1801e8d8bef9SDimitry Andric return; 1802e8d8bef9SDimitry Andric } 1803e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg2: 1804e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg3: 1805e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg4: 1806e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg5: 1807e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg6: 1808e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg7: 1809e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg8: { 1810fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ false, /*IsStrided*/ true); 1811e8d8bef9SDimitry Andric return; 1812e8d8bef9SDimitry Andric } 1813e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg2_mask: 1814e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg3_mask: 1815e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg4_mask: 1816e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg5_mask: 1817e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg6_mask: 1818e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg7_mask: 1819e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg8_mask: { 1820fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ true, /*IsStrided*/ true); 1821e8d8bef9SDimitry Andric return; 1822e8d8bef9SDimitry Andric } 1823e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg2: 1824e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg3: 1825e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg4: 1826e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg5: 1827e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg6: 1828e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg7: 1829e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg8: 1830fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ true); 1831fe6060f1SDimitry Andric return; 1832e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg2: 1833e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg3: 1834e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg4: 1835e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg5: 1836e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg6: 1837e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg7: 1838fe6060f1SDimitry Andric case Intrinsic::riscv_vluxseg8: 1839fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ false); 1840e8d8bef9SDimitry Andric return; 1841e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg2_mask: 1842e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg3_mask: 1843e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg4_mask: 1844e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg5_mask: 1845e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg6_mask: 1846e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg7_mask: 1847e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg8_mask: 1848fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ true); 1849fe6060f1SDimitry Andric return; 1850e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg2_mask: 1851e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg3_mask: 1852e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg4_mask: 1853e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg5_mask: 1854e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg6_mask: 1855e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg7_mask: 1856fe6060f1SDimitry Andric case Intrinsic::riscv_vluxseg8_mask: 1857fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ false); 1858fe6060f1SDimitry Andric return; 1859fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg8ff: 1860fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg7ff: 1861fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg6ff: 1862fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg5ff: 1863fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg4ff: 1864fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg3ff: 1865fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg2ff: { 1866fe6060f1SDimitry Andric selectVLSEGFF(Node, /*IsMasked*/ false); 1867fe6060f1SDimitry Andric return; 1868fe6060f1SDimitry Andric } 1869fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg8ff_mask: 1870fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg7ff_mask: 1871fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg6ff_mask: 1872fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg5ff_mask: 1873fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg4ff_mask: 1874fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg3ff_mask: 1875fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg2ff_mask: { 1876fe6060f1SDimitry Andric selectVLSEGFF(Node, /*IsMasked*/ true); 1877fe6060f1SDimitry Andric return; 1878fe6060f1SDimitry Andric } 1879fe6060f1SDimitry Andric case Intrinsic::riscv_vloxei: 1880fe6060f1SDimitry Andric case Intrinsic::riscv_vloxei_mask: 1881fe6060f1SDimitry Andric case Intrinsic::riscv_vluxei: 1882fe6060f1SDimitry Andric case Intrinsic::riscv_vluxei_mask: { 1883fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vloxei_mask || 1884fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vluxei_mask; 1885fe6060f1SDimitry Andric bool IsOrdered = IntNo == Intrinsic::riscv_vloxei || 1886fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vloxei_mask; 1887fe6060f1SDimitry Andric 1888fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1889fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1890fe6060f1SDimitry Andric 1891fe6060f1SDimitry Andric unsigned CurOp = 2; 1892fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 1893fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 1894fe6060f1SDimitry Andric 1895fe6060f1SDimitry Andric MVT IndexVT; 1896fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1897fe6060f1SDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 1898349cc55cSDimitry Andric /*IsLoad=*/true, &IndexVT); 1899fe6060f1SDimitry Andric 1900fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 1901fe6060f1SDimitry Andric "Element count mismatch"); 1902fe6060f1SDimitry Andric 1903fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1904fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 1905fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 190604eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 190704eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 190804eeddc0SDimitry Andric "values when XLEN=32"); 190904eeddc0SDimitry Andric } 1910fe6060f1SDimitry Andric const RISCV::VLX_VSXPseudo *P = RISCV::getVLXPseudo( 191106c3fb27SDimitry Andric IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 1912fe6060f1SDimitry Andric static_cast<unsigned>(IndexLMUL)); 1913fe6060f1SDimitry Andric MachineSDNode *Load = 1914fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1915fe6060f1SDimitry Andric 1916fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1917fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1918fe6060f1SDimitry Andric 1919fe6060f1SDimitry Andric ReplaceNode(Node, Load); 1920fe6060f1SDimitry Andric return; 1921fe6060f1SDimitry Andric } 1922349cc55cSDimitry Andric case Intrinsic::riscv_vlm: 1923fe6060f1SDimitry Andric case Intrinsic::riscv_vle: 1924fe6060f1SDimitry Andric case Intrinsic::riscv_vle_mask: 1925fe6060f1SDimitry Andric case Intrinsic::riscv_vlse: 1926fe6060f1SDimitry Andric case Intrinsic::riscv_vlse_mask: { 1927fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vle_mask || 1928fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vlse_mask; 1929fe6060f1SDimitry Andric bool IsStrided = 1930fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vlse || IntNo == Intrinsic::riscv_vlse_mask; 1931fe6060f1SDimitry Andric 1932fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1933fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1934fe6060f1SDimitry Andric 193506c3fb27SDimitry Andric // The riscv_vlm intrinsic are always tail agnostic and no passthru 193606c3fb27SDimitry Andric // operand at the IR level. In pseudos, they have both policy and 193706c3fb27SDimitry Andric // passthru operand. The passthru operand is needed to track the 193806c3fb27SDimitry Andric // "tail undefined" state, and the policy is there just for 193906c3fb27SDimitry Andric // for consistency - it will always be "don't care" for the 194006c3fb27SDimitry Andric // unmasked form. 194104eeddc0SDimitry Andric bool HasPassthruOperand = IntNo != Intrinsic::riscv_vlm; 194206c3fb27SDimitry Andric unsigned CurOp = 2; 1943fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 194406c3fb27SDimitry Andric if (HasPassthruOperand) 1945fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 194606c3fb27SDimitry Andric else { 194706c3fb27SDimitry Andric // We eagerly lower to implicit_def (instead of undef), as we 194806c3fb27SDimitry Andric // otherwise fail to select nodes such as: nxv1i1 = undef 194906c3fb27SDimitry Andric SDNode *Passthru = 195006c3fb27SDimitry Andric CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, VT); 195106c3fb27SDimitry Andric Operands.push_back(SDValue(Passthru, 0)); 195206c3fb27SDimitry Andric } 1953fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 1954349cc55cSDimitry Andric Operands, /*IsLoad=*/true); 1955fe6060f1SDimitry Andric 1956fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1957fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = 195806c3fb27SDimitry Andric RISCV::getVLEPseudo(IsMasked, IsStrided, /*FF*/ false, Log2SEW, 1959fe6060f1SDimitry Andric static_cast<unsigned>(LMUL)); 1960fe6060f1SDimitry Andric MachineSDNode *Load = 1961fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1962fe6060f1SDimitry Andric 1963fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1964fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1965fe6060f1SDimitry Andric 1966fe6060f1SDimitry Andric ReplaceNode(Node, Load); 1967fe6060f1SDimitry Andric return; 1968fe6060f1SDimitry Andric } 1969fe6060f1SDimitry Andric case Intrinsic::riscv_vleff: 1970fe6060f1SDimitry Andric case Intrinsic::riscv_vleff_mask: { 1971fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vleff_mask; 1972fe6060f1SDimitry Andric 1973fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1974fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1975fe6060f1SDimitry Andric 1976fe6060f1SDimitry Andric unsigned CurOp = 2; 1977fe6060f1SDimitry Andric SmallVector<SDValue, 7> Operands; 1978fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 1979fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1980349cc55cSDimitry Andric /*IsStridedOrIndexed*/ false, Operands, 1981349cc55cSDimitry Andric /*IsLoad=*/true); 1982fe6060f1SDimitry Andric 1983fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1984fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = 198506c3fb27SDimitry Andric RISCV::getVLEPseudo(IsMasked, /*Strided*/ false, /*FF*/ true, 198604eeddc0SDimitry Andric Log2SEW, static_cast<unsigned>(LMUL)); 198781ad6265SDimitry Andric MachineSDNode *Load = CurDAG->getMachineNode( 198881ad6265SDimitry Andric P->Pseudo, DL, Node->getVTList(), Operands); 1989fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1990fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1991fe6060f1SDimitry Andric 199281ad6265SDimitry Andric ReplaceNode(Node, Load); 19930b57cec5SDimitry Andric return; 19940b57cec5SDimitry Andric } 19950b57cec5SDimitry Andric } 19960b57cec5SDimitry Andric break; 19970b57cec5SDimitry Andric } 1998e8d8bef9SDimitry Andric case ISD::INTRINSIC_VOID: { 1999647cbc5dSDimitry Andric unsigned IntNo = Node->getConstantOperandVal(1); 2000e8d8bef9SDimitry Andric switch (IntNo) { 2001e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg2: 2002e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg3: 2003e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg4: 2004e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg5: 2005e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg6: 2006e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg7: 2007e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg8: { 2008fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ false, /*IsStrided*/ false); 20090b57cec5SDimitry Andric return; 20100b57cec5SDimitry Andric } 2011e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg2_mask: 2012e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg3_mask: 2013e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg4_mask: 2014e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg5_mask: 2015e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg6_mask: 2016e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg7_mask: 2017e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg8_mask: { 2018fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ true, /*IsStrided*/ false); 2019e8d8bef9SDimitry Andric return; 2020e8d8bef9SDimitry Andric } 2021e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg2: 2022e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg3: 2023e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg4: 2024e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg5: 2025e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg6: 2026e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg7: 2027e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg8: { 2028fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ false, /*IsStrided*/ true); 2029e8d8bef9SDimitry Andric return; 2030e8d8bef9SDimitry Andric } 2031e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg2_mask: 2032e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg3_mask: 2033e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg4_mask: 2034e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg5_mask: 2035e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg6_mask: 2036e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg7_mask: 2037e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg8_mask: { 2038fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ true, /*IsStrided*/ true); 2039e8d8bef9SDimitry Andric return; 2040e8d8bef9SDimitry Andric } 2041e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg2: 2042e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg3: 2043e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg4: 2044e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg5: 2045e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg6: 2046e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg7: 2047e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg8: 2048fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ true); 2049fe6060f1SDimitry Andric return; 2050e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg2: 2051e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg3: 2052e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg4: 2053e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg5: 2054e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg6: 2055e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg7: 2056fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxseg8: 2057fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ false); 2058e8d8bef9SDimitry Andric return; 2059e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg2_mask: 2060e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg3_mask: 2061e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg4_mask: 2062e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg5_mask: 2063e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg6_mask: 2064e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg7_mask: 2065e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg8_mask: 2066fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ true); 2067fe6060f1SDimitry Andric return; 2068e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg2_mask: 2069e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg3_mask: 2070e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg4_mask: 2071e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg5_mask: 2072e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg6_mask: 2073e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg7_mask: 2074fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxseg8_mask: 2075fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ false); 2076fe6060f1SDimitry Andric return; 2077fe6060f1SDimitry Andric case Intrinsic::riscv_vsoxei: 2078fe6060f1SDimitry Andric case Intrinsic::riscv_vsoxei_mask: 2079fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxei: 2080fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxei_mask: { 2081fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vsoxei_mask || 2082fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsuxei_mask; 2083fe6060f1SDimitry Andric bool IsOrdered = IntNo == Intrinsic::riscv_vsoxei || 2084fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsoxei_mask; 2085fe6060f1SDimitry Andric 2086fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 2087fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 2088fe6060f1SDimitry Andric 2089fe6060f1SDimitry Andric unsigned CurOp = 2; 2090fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 2091fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Store value. 2092fe6060f1SDimitry Andric 2093fe6060f1SDimitry Andric MVT IndexVT; 2094fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 2095fe6060f1SDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 2096349cc55cSDimitry Andric /*IsLoad=*/false, &IndexVT); 2097fe6060f1SDimitry Andric 2098fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 2099fe6060f1SDimitry Andric "Element count mismatch"); 2100fe6060f1SDimitry Andric 2101fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 2102fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 2103fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 210404eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 210504eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 210604eeddc0SDimitry Andric "values when XLEN=32"); 210704eeddc0SDimitry Andric } 2108fe6060f1SDimitry Andric const RISCV::VLX_VSXPseudo *P = RISCV::getVSXPseudo( 210906c3fb27SDimitry Andric IsMasked, IsOrdered, IndexLog2EEW, 211004eeddc0SDimitry Andric static_cast<unsigned>(LMUL), static_cast<unsigned>(IndexLMUL)); 2111fe6060f1SDimitry Andric MachineSDNode *Store = 2112fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 2113fe6060f1SDimitry Andric 2114fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 2115fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 2116fe6060f1SDimitry Andric 2117fe6060f1SDimitry Andric ReplaceNode(Node, Store); 2118fe6060f1SDimitry Andric return; 2119fe6060f1SDimitry Andric } 2120349cc55cSDimitry Andric case Intrinsic::riscv_vsm: 2121fe6060f1SDimitry Andric case Intrinsic::riscv_vse: 2122fe6060f1SDimitry Andric case Intrinsic::riscv_vse_mask: 2123fe6060f1SDimitry Andric case Intrinsic::riscv_vsse: 2124fe6060f1SDimitry Andric case Intrinsic::riscv_vsse_mask: { 2125fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vse_mask || 2126fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsse_mask; 2127fe6060f1SDimitry Andric bool IsStrided = 2128fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsse || IntNo == Intrinsic::riscv_vsse_mask; 2129fe6060f1SDimitry Andric 2130fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 2131fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 2132fe6060f1SDimitry Andric 2133fe6060f1SDimitry Andric unsigned CurOp = 2; 2134fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 2135fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Store value. 2136fe6060f1SDimitry Andric 2137fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 2138fe6060f1SDimitry Andric Operands); 2139fe6060f1SDimitry Andric 2140fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 2141fe6060f1SDimitry Andric const RISCV::VSEPseudo *P = RISCV::getVSEPseudo( 2142fe6060f1SDimitry Andric IsMasked, IsStrided, Log2SEW, static_cast<unsigned>(LMUL)); 2143fe6060f1SDimitry Andric MachineSDNode *Store = 2144fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 2145fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 2146fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 2147fe6060f1SDimitry Andric 2148fe6060f1SDimitry Andric ReplaceNode(Node, Store); 2149e8d8bef9SDimitry Andric return; 2150e8d8bef9SDimitry Andric } 2151*0fca6ea1SDimitry Andric case Intrinsic::riscv_sf_vc_x_se: 2152*0fca6ea1SDimitry Andric case Intrinsic::riscv_sf_vc_i_se: 2153*0fca6ea1SDimitry Andric selectSF_VC_X_SE(Node); 2154*0fca6ea1SDimitry Andric return; 2155e8d8bef9SDimitry Andric } 2156e8d8bef9SDimitry Andric break; 2157e8d8bef9SDimitry Andric } 2158fe6060f1SDimitry Andric case ISD::BITCAST: { 2159fe6060f1SDimitry Andric MVT SrcVT = Node->getOperand(0).getSimpleValueType(); 2160fe6060f1SDimitry Andric // Just drop bitcasts between vectors if both are fixed or both are 2161fe6060f1SDimitry Andric // scalable. 2162fe6060f1SDimitry Andric if ((VT.isScalableVector() && SrcVT.isScalableVector()) || 2163fe6060f1SDimitry Andric (VT.isFixedLengthVector() && SrcVT.isFixedLengthVector())) { 2164fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, 0), Node->getOperand(0)); 2165fe6060f1SDimitry Andric CurDAG->RemoveDeadNode(Node); 2166e8d8bef9SDimitry Andric return; 2167e8d8bef9SDimitry Andric } 2168fe6060f1SDimitry Andric break; 2169fe6060f1SDimitry Andric } 2170fe6060f1SDimitry Andric case ISD::INSERT_SUBVECTOR: { 2171fe6060f1SDimitry Andric SDValue V = Node->getOperand(0); 2172fe6060f1SDimitry Andric SDValue SubV = Node->getOperand(1); 2173fe6060f1SDimitry Andric SDLoc DL(SubV); 2174fe6060f1SDimitry Andric auto Idx = Node->getConstantOperandVal(2); 2175fe6060f1SDimitry Andric MVT SubVecVT = SubV.getSimpleValueType(); 2176fe6060f1SDimitry Andric 2177fe6060f1SDimitry Andric const RISCVTargetLowering &TLI = *Subtarget->getTargetLowering(); 2178fe6060f1SDimitry Andric MVT SubVecContainerVT = SubVecVT; 2179fe6060f1SDimitry Andric // Establish the correct scalable-vector types for any fixed-length type. 2180*0fca6ea1SDimitry Andric if (SubVecVT.isFixedLengthVector()) { 2181fe6060f1SDimitry Andric SubVecContainerVT = TLI.getContainerForFixedLengthVector(SubVecVT); 2182*0fca6ea1SDimitry Andric TypeSize VecRegSize = TypeSize::getScalable(RISCV::RVVBitsPerBlock); 2183*0fca6ea1SDimitry Andric [[maybe_unused]] bool ExactlyVecRegSized = 2184*0fca6ea1SDimitry Andric Subtarget->expandVScale(SubVecVT.getSizeInBits()) 2185*0fca6ea1SDimitry Andric .isKnownMultipleOf(Subtarget->expandVScale(VecRegSize)); 2186*0fca6ea1SDimitry Andric assert(isPowerOf2_64(Subtarget->expandVScale(SubVecVT.getSizeInBits()) 2187*0fca6ea1SDimitry Andric .getKnownMinValue())); 2188*0fca6ea1SDimitry Andric assert(Idx == 0 && (ExactlyVecRegSized || V.isUndef())); 2189*0fca6ea1SDimitry Andric } 2190*0fca6ea1SDimitry Andric MVT ContainerVT = VT; 2191fe6060f1SDimitry Andric if (VT.isFixedLengthVector()) 2192*0fca6ea1SDimitry Andric ContainerVT = TLI.getContainerForFixedLengthVector(VT); 2193fe6060f1SDimitry Andric 2194fe6060f1SDimitry Andric const auto *TRI = Subtarget->getRegisterInfo(); 2195fe6060f1SDimitry Andric unsigned SubRegIdx; 2196fe6060f1SDimitry Andric std::tie(SubRegIdx, Idx) = 2197fe6060f1SDimitry Andric RISCVTargetLowering::decomposeSubvectorInsertExtractToSubRegs( 2198*0fca6ea1SDimitry Andric ContainerVT, SubVecContainerVT, Idx, TRI); 2199fe6060f1SDimitry Andric 2200fe6060f1SDimitry Andric // If the Idx hasn't been completely eliminated then this is a subvector 2201fe6060f1SDimitry Andric // insert which doesn't naturally align to a vector register. These must 2202fe6060f1SDimitry Andric // be handled using instructions to manipulate the vector registers. 2203fe6060f1SDimitry Andric if (Idx != 0) 2204fe6060f1SDimitry Andric break; 2205fe6060f1SDimitry Andric 2206fe6060f1SDimitry Andric RISCVII::VLMUL SubVecLMUL = RISCVTargetLowering::getLMUL(SubVecContainerVT); 2207*0fca6ea1SDimitry Andric [[maybe_unused]] bool IsSubVecPartReg = 2208*0fca6ea1SDimitry Andric SubVecLMUL == RISCVII::VLMUL::LMUL_F2 || 2209fe6060f1SDimitry Andric SubVecLMUL == RISCVII::VLMUL::LMUL_F4 || 2210fe6060f1SDimitry Andric SubVecLMUL == RISCVII::VLMUL::LMUL_F8; 2211fe6060f1SDimitry Andric assert((!IsSubVecPartReg || V.isUndef()) && 2212fe6060f1SDimitry Andric "Expecting lowering to have created legal INSERT_SUBVECTORs when " 2213fe6060f1SDimitry Andric "the subvector is smaller than a full-sized register"); 2214fe6060f1SDimitry Andric 2215fe6060f1SDimitry Andric // If we haven't set a SubRegIdx, then we must be going between 2216fe6060f1SDimitry Andric // equally-sized LMUL groups (e.g. VR -> VR). This can be done as a copy. 2217fe6060f1SDimitry Andric if (SubRegIdx == RISCV::NoSubRegister) { 2218*0fca6ea1SDimitry Andric unsigned InRegClassID = 2219*0fca6ea1SDimitry Andric RISCVTargetLowering::getRegClassIDForVecVT(ContainerVT); 2220fe6060f1SDimitry Andric assert(RISCVTargetLowering::getRegClassIDForVecVT(SubVecContainerVT) == 2221fe6060f1SDimitry Andric InRegClassID && 2222fe6060f1SDimitry Andric "Unexpected subvector extraction"); 2223fe6060f1SDimitry Andric SDValue RC = CurDAG->getTargetConstant(InRegClassID, DL, XLenVT); 2224fe6060f1SDimitry Andric SDNode *NewNode = CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, 2225fe6060f1SDimitry Andric DL, VT, SubV, RC); 2226fe6060f1SDimitry Andric ReplaceNode(Node, NewNode); 2227fe6060f1SDimitry Andric return; 2228fe6060f1SDimitry Andric } 2229fe6060f1SDimitry Andric 2230fe6060f1SDimitry Andric SDValue Insert = CurDAG->getTargetInsertSubreg(SubRegIdx, DL, VT, V, SubV); 2231fe6060f1SDimitry Andric ReplaceNode(Node, Insert.getNode()); 2232fe6060f1SDimitry Andric return; 2233fe6060f1SDimitry Andric } 2234fe6060f1SDimitry Andric case ISD::EXTRACT_SUBVECTOR: { 2235fe6060f1SDimitry Andric SDValue V = Node->getOperand(0); 2236fe6060f1SDimitry Andric auto Idx = Node->getConstantOperandVal(1); 2237fe6060f1SDimitry Andric MVT InVT = V.getSimpleValueType(); 2238fe6060f1SDimitry Andric SDLoc DL(V); 2239fe6060f1SDimitry Andric 2240fe6060f1SDimitry Andric const RISCVTargetLowering &TLI = *Subtarget->getTargetLowering(); 2241fe6060f1SDimitry Andric MVT SubVecContainerVT = VT; 2242fe6060f1SDimitry Andric // Establish the correct scalable-vector types for any fixed-length type. 2243*0fca6ea1SDimitry Andric if (VT.isFixedLengthVector()) { 2244*0fca6ea1SDimitry Andric assert(Idx == 0); 2245fe6060f1SDimitry Andric SubVecContainerVT = TLI.getContainerForFixedLengthVector(VT); 2246*0fca6ea1SDimitry Andric } 2247fe6060f1SDimitry Andric if (InVT.isFixedLengthVector()) 2248fe6060f1SDimitry Andric InVT = TLI.getContainerForFixedLengthVector(InVT); 2249fe6060f1SDimitry Andric 2250fe6060f1SDimitry Andric const auto *TRI = Subtarget->getRegisterInfo(); 2251fe6060f1SDimitry Andric unsigned SubRegIdx; 2252fe6060f1SDimitry Andric std::tie(SubRegIdx, Idx) = 2253fe6060f1SDimitry Andric RISCVTargetLowering::decomposeSubvectorInsertExtractToSubRegs( 2254fe6060f1SDimitry Andric InVT, SubVecContainerVT, Idx, TRI); 2255fe6060f1SDimitry Andric 2256fe6060f1SDimitry Andric // If the Idx hasn't been completely eliminated then this is a subvector 2257fe6060f1SDimitry Andric // extract which doesn't naturally align to a vector register. These must 2258fe6060f1SDimitry Andric // be handled using instructions to manipulate the vector registers. 2259fe6060f1SDimitry Andric if (Idx != 0) 2260fe6060f1SDimitry Andric break; 2261fe6060f1SDimitry Andric 2262fe6060f1SDimitry Andric // If we haven't set a SubRegIdx, then we must be going between 2263fe6060f1SDimitry Andric // equally-sized LMUL types (e.g. VR -> VR). This can be done as a copy. 2264fe6060f1SDimitry Andric if (SubRegIdx == RISCV::NoSubRegister) { 2265fe6060f1SDimitry Andric unsigned InRegClassID = RISCVTargetLowering::getRegClassIDForVecVT(InVT); 2266fe6060f1SDimitry Andric assert(RISCVTargetLowering::getRegClassIDForVecVT(SubVecContainerVT) == 2267fe6060f1SDimitry Andric InRegClassID && 2268fe6060f1SDimitry Andric "Unexpected subvector extraction"); 2269fe6060f1SDimitry Andric SDValue RC = CurDAG->getTargetConstant(InRegClassID, DL, XLenVT); 2270fe6060f1SDimitry Andric SDNode *NewNode = 2271fe6060f1SDimitry Andric CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, VT, V, RC); 2272fe6060f1SDimitry Andric ReplaceNode(Node, NewNode); 2273fe6060f1SDimitry Andric return; 2274fe6060f1SDimitry Andric } 2275fe6060f1SDimitry Andric 2276fe6060f1SDimitry Andric SDValue Extract = CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, V); 2277fe6060f1SDimitry Andric ReplaceNode(Node, Extract.getNode()); 2278fe6060f1SDimitry Andric return; 2279fe6060f1SDimitry Andric } 228004eeddc0SDimitry Andric case RISCVISD::VMV_S_X_VL: 228104eeddc0SDimitry Andric case RISCVISD::VFMV_S_F_VL: 2282fe6060f1SDimitry Andric case RISCVISD::VMV_V_X_VL: 2283fe6060f1SDimitry Andric case RISCVISD::VFMV_V_F_VL: { 2284fe6060f1SDimitry Andric // Try to match splat of a scalar load to a strided load with stride of x0. 228504eeddc0SDimitry Andric bool IsScalarMove = Node->getOpcode() == RISCVISD::VMV_S_X_VL || 228604eeddc0SDimitry Andric Node->getOpcode() == RISCVISD::VFMV_S_F_VL; 2287bdd1243dSDimitry Andric if (!Node->getOperand(0).isUndef()) 228804eeddc0SDimitry Andric break; 2289bdd1243dSDimitry Andric SDValue Src = Node->getOperand(1); 2290fe6060f1SDimitry Andric auto *Ld = dyn_cast<LoadSDNode>(Src); 229106c3fb27SDimitry Andric // Can't fold load update node because the second 229206c3fb27SDimitry Andric // output is used so that load update node can't be removed. 229306c3fb27SDimitry Andric if (!Ld || Ld->isIndexed()) 2294fe6060f1SDimitry Andric break; 2295fe6060f1SDimitry Andric EVT MemVT = Ld->getMemoryVT(); 2296fe6060f1SDimitry Andric // The memory VT should be the same size as the element type. 2297fe6060f1SDimitry Andric if (MemVT.getStoreSize() != VT.getVectorElementType().getStoreSize()) 2298fe6060f1SDimitry Andric break; 2299fe6060f1SDimitry Andric if (!IsProfitableToFold(Src, Node, Node) || 2300fe6060f1SDimitry Andric !IsLegalToFold(Src, Node, Node, TM.getOptLevel())) 2301fe6060f1SDimitry Andric break; 2302fe6060f1SDimitry Andric 2303fe6060f1SDimitry Andric SDValue VL; 2304bdd1243dSDimitry Andric if (IsScalarMove) { 230504eeddc0SDimitry Andric // We could deal with more VL if we update the VSETVLI insert pass to 230604eeddc0SDimitry Andric // avoid introducing more VSETVLI. 230704eeddc0SDimitry Andric if (!isOneConstant(Node->getOperand(2))) 230804eeddc0SDimitry Andric break; 230904eeddc0SDimitry Andric selectVLOp(Node->getOperand(2), VL); 231004eeddc0SDimitry Andric } else 231181ad6265SDimitry Andric selectVLOp(Node->getOperand(2), VL); 2312fe6060f1SDimitry Andric 2313fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 2314fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(Log2SEW, DL, XLenVT); 2315fe6060f1SDimitry Andric 231606c3fb27SDimitry Andric // If VL=1, then we don't need to do a strided load and can just do a 231706c3fb27SDimitry Andric // regular load. 231806c3fb27SDimitry Andric bool IsStrided = !isOneConstant(VL); 231906c3fb27SDimitry Andric 232006c3fb27SDimitry Andric // Only do a strided load if we have optimized zero-stride vector load. 232106c3fb27SDimitry Andric if (IsStrided && !Subtarget->hasOptimizedZeroStrideLoad()) 232206c3fb27SDimitry Andric break; 232306c3fb27SDimitry Andric 23245f757f3fSDimitry Andric SmallVector<SDValue> Operands = { 23255f757f3fSDimitry Andric SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, VT), 0), 23265f757f3fSDimitry Andric Ld->getBasePtr()}; 232706c3fb27SDimitry Andric if (IsStrided) 232806c3fb27SDimitry Andric Operands.push_back(CurDAG->getRegister(RISCV::X0, XLenVT)); 232906c3fb27SDimitry Andric uint64_t Policy = RISCVII::MASK_AGNOSTIC | RISCVII::TAIL_AGNOSTIC; 233006c3fb27SDimitry Andric SDValue PolicyOp = CurDAG->getTargetConstant(Policy, DL, XLenVT); 233106c3fb27SDimitry Andric Operands.append({VL, SEW, PolicyOp, Ld->getChain()}); 2332fe6060f1SDimitry Andric 2333fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 2334fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = RISCV::getVLEPseudo( 233506c3fb27SDimitry Andric /*IsMasked*/ false, IsStrided, /*FF*/ false, 233604eeddc0SDimitry Andric Log2SEW, static_cast<unsigned>(LMUL)); 2337fe6060f1SDimitry Andric MachineSDNode *Load = 2338bdd1243dSDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, {VT, MVT::Other}, Operands); 2339bdd1243dSDimitry Andric // Update the chain. 2340bdd1243dSDimitry Andric ReplaceUses(Src.getValue(1), SDValue(Load, 1)); 2341bdd1243dSDimitry Andric // Record the mem-refs 234281ad6265SDimitry Andric CurDAG->setNodeMemRefs(Load, {Ld->getMemOperand()}); 2343bdd1243dSDimitry Andric // Replace the splat with the vlse. 2344fe6060f1SDimitry Andric ReplaceNode(Node, Load); 2345e8d8bef9SDimitry Andric return; 2346e8d8bef9SDimitry Andric } 234706c3fb27SDimitry Andric case ISD::PREFETCH: 234806c3fb27SDimitry Andric unsigned Locality = Node->getConstantOperandVal(3); 234906c3fb27SDimitry Andric if (Locality > 2) 235006c3fb27SDimitry Andric break; 235106c3fb27SDimitry Andric 235206c3fb27SDimitry Andric if (auto *LoadStoreMem = dyn_cast<MemSDNode>(Node)) { 235306c3fb27SDimitry Andric MachineMemOperand *MMO = LoadStoreMem->getMemOperand(); 235406c3fb27SDimitry Andric MMO->setFlags(MachineMemOperand::MONonTemporal); 235506c3fb27SDimitry Andric 235606c3fb27SDimitry Andric int NontemporalLevel = 0; 235706c3fb27SDimitry Andric switch (Locality) { 235806c3fb27SDimitry Andric case 0: 235906c3fb27SDimitry Andric NontemporalLevel = 3; // NTL.ALL 236006c3fb27SDimitry Andric break; 236106c3fb27SDimitry Andric case 1: 236206c3fb27SDimitry Andric NontemporalLevel = 1; // NTL.PALL 236306c3fb27SDimitry Andric break; 236406c3fb27SDimitry Andric case 2: 236506c3fb27SDimitry Andric NontemporalLevel = 0; // NTL.P1 236606c3fb27SDimitry Andric break; 236706c3fb27SDimitry Andric default: 236806c3fb27SDimitry Andric llvm_unreachable("unexpected locality value."); 236906c3fb27SDimitry Andric } 237006c3fb27SDimitry Andric 237106c3fb27SDimitry Andric if (NontemporalLevel & 0b1) 237206c3fb27SDimitry Andric MMO->setFlags(MONontemporalBit0); 237306c3fb27SDimitry Andric if (NontemporalLevel & 0b10) 237406c3fb27SDimitry Andric MMO->setFlags(MONontemporalBit1); 237506c3fb27SDimitry Andric } 237606c3fb27SDimitry Andric break; 2377e8d8bef9SDimitry Andric } 23780b57cec5SDimitry Andric 23790b57cec5SDimitry Andric // Select the default instruction. 23800b57cec5SDimitry Andric SelectCode(Node); 23810b57cec5SDimitry Andric } 23820b57cec5SDimitry Andric 23830b57cec5SDimitry Andric bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand( 23845f757f3fSDimitry Andric const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, 23855f757f3fSDimitry Andric std::vector<SDValue> &OutOps) { 238606c3fb27SDimitry Andric // Always produce a register and immediate operand, as expected by 238706c3fb27SDimitry Andric // RISCVAsmPrinter::PrintAsmMemoryOperand. 23880b57cec5SDimitry Andric switch (ConstraintID) { 23895f757f3fSDimitry Andric case InlineAsm::ConstraintCode::o: 23905f757f3fSDimitry Andric case InlineAsm::ConstraintCode::m: { 239106c3fb27SDimitry Andric SDValue Op0, Op1; 2392*0fca6ea1SDimitry Andric [[maybe_unused]] bool Found = SelectAddrRegImm(Op, Op0, Op1); 239306c3fb27SDimitry Andric assert(Found && "SelectAddrRegImm should always succeed"); 239406c3fb27SDimitry Andric OutOps.push_back(Op0); 239506c3fb27SDimitry Andric OutOps.push_back(Op1); 23960b57cec5SDimitry Andric return false; 239706c3fb27SDimitry Andric } 23985f757f3fSDimitry Andric case InlineAsm::ConstraintCode::A: 23990b57cec5SDimitry Andric OutOps.push_back(Op); 240006c3fb27SDimitry Andric OutOps.push_back( 240106c3fb27SDimitry Andric CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getXLenVT())); 24020b57cec5SDimitry Andric return false; 24030b57cec5SDimitry Andric default: 240406c3fb27SDimitry Andric report_fatal_error("Unexpected asm memory constraint " + 240506c3fb27SDimitry Andric InlineAsm::getMemConstraintName(ConstraintID)); 24060b57cec5SDimitry Andric } 24070b57cec5SDimitry Andric 24080b57cec5SDimitry Andric return true; 24090b57cec5SDimitry Andric } 24100b57cec5SDimitry Andric 241181ad6265SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrFrameIndex(SDValue Addr, SDValue &Base, 241281ad6265SDimitry Andric SDValue &Offset) { 2413fe6060f1SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 24140b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT()); 241581ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), Subtarget->getXLenVT()); 24160b57cec5SDimitry Andric return true; 24170b57cec5SDimitry Andric } 241881ad6265SDimitry Andric 241981ad6265SDimitry Andric return false; 242081ad6265SDimitry Andric } 242181ad6265SDimitry Andric 242281ad6265SDimitry Andric // Select a frame index and an optional immediate offset from an ADD or OR. 242381ad6265SDimitry Andric bool RISCVDAGToDAGISel::SelectFrameAddrRegImm(SDValue Addr, SDValue &Base, 242481ad6265SDimitry Andric SDValue &Offset) { 242581ad6265SDimitry Andric if (SelectAddrFrameIndex(Addr, Base, Offset)) 242681ad6265SDimitry Andric return true; 242781ad6265SDimitry Andric 242881ad6265SDimitry Andric if (!CurDAG->isBaseWithConstantOffset(Addr)) 242981ad6265SDimitry Andric return false; 243081ad6265SDimitry Andric 243181ad6265SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) { 243281ad6265SDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 243381ad6265SDimitry Andric if (isInt<12>(CVal)) { 243481ad6265SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), 243581ad6265SDimitry Andric Subtarget->getXLenVT()); 243681ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(CVal, SDLoc(Addr), 243781ad6265SDimitry Andric Subtarget->getXLenVT()); 243881ad6265SDimitry Andric return true; 243981ad6265SDimitry Andric } 244081ad6265SDimitry Andric } 244181ad6265SDimitry Andric 24420b57cec5SDimitry Andric return false; 24430b57cec5SDimitry Andric } 24440b57cec5SDimitry Andric 2445753f127fSDimitry Andric // Fold constant addresses. 2446753f127fSDimitry Andric static bool selectConstantAddr(SelectionDAG *CurDAG, const SDLoc &DL, 2447753f127fSDimitry Andric const MVT VT, const RISCVSubtarget *Subtarget, 24485f757f3fSDimitry Andric SDValue Addr, SDValue &Base, SDValue &Offset, 24495f757f3fSDimitry Andric bool IsPrefetch = false) { 2450753f127fSDimitry Andric if (!isa<ConstantSDNode>(Addr)) 2451753f127fSDimitry Andric return false; 2452753f127fSDimitry Andric 2453753f127fSDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr)->getSExtValue(); 2454753f127fSDimitry Andric 2455753f127fSDimitry Andric // If the constant is a simm12, we can fold the whole constant and use X0 as 2456753f127fSDimitry Andric // the base. If the constant can be materialized with LUI+simm12, use LUI as 2457753f127fSDimitry Andric // the base. We can't use generateInstSeq because it favors LUI+ADDIW. 2458753f127fSDimitry Andric int64_t Lo12 = SignExtend64<12>(CVal); 2459753f127fSDimitry Andric int64_t Hi = (uint64_t)CVal - (uint64_t)Lo12; 2460753f127fSDimitry Andric if (!Subtarget->is64Bit() || isInt<32>(Hi)) { 24615f757f3fSDimitry Andric if (IsPrefetch && (Lo12 & 0b11111) != 0) 24625f757f3fSDimitry Andric return false; 24635f757f3fSDimitry Andric 2464753f127fSDimitry Andric if (Hi) { 2465753f127fSDimitry Andric int64_t Hi20 = (Hi >> 12) & 0xfffff; 2466753f127fSDimitry Andric Base = SDValue( 2467753f127fSDimitry Andric CurDAG->getMachineNode(RISCV::LUI, DL, VT, 2468753f127fSDimitry Andric CurDAG->getTargetConstant(Hi20, DL, VT)), 2469753f127fSDimitry Andric 0); 2470753f127fSDimitry Andric } else { 2471753f127fSDimitry Andric Base = CurDAG->getRegister(RISCV::X0, VT); 2472753f127fSDimitry Andric } 2473753f127fSDimitry Andric Offset = CurDAG->getTargetConstant(Lo12, DL, VT); 2474753f127fSDimitry Andric return true; 2475753f127fSDimitry Andric } 2476753f127fSDimitry Andric 2477753f127fSDimitry Andric // Ask how constant materialization would handle this constant. 24785f757f3fSDimitry Andric RISCVMatInt::InstSeq Seq = RISCVMatInt::generateInstSeq(CVal, *Subtarget); 2479753f127fSDimitry Andric 2480753f127fSDimitry Andric // If the last instruction would be an ADDI, we can fold its immediate and 2481753f127fSDimitry Andric // emit the rest of the sequence as the base. 2482bdd1243dSDimitry Andric if (Seq.back().getOpcode() != RISCV::ADDI) 2483753f127fSDimitry Andric return false; 2484bdd1243dSDimitry Andric Lo12 = Seq.back().getImm(); 24855f757f3fSDimitry Andric if (IsPrefetch && (Lo12 & 0b11111) != 0) 24865f757f3fSDimitry Andric return false; 2487753f127fSDimitry Andric 2488753f127fSDimitry Andric // Drop the last instruction. 2489753f127fSDimitry Andric Seq.pop_back(); 2490753f127fSDimitry Andric assert(!Seq.empty() && "Expected more instructions in sequence"); 2491753f127fSDimitry Andric 249206c3fb27SDimitry Andric Base = selectImmSeq(CurDAG, DL, VT, Seq); 2493753f127fSDimitry Andric Offset = CurDAG->getTargetConstant(Lo12, DL, VT); 2494753f127fSDimitry Andric return true; 2495753f127fSDimitry Andric } 2496753f127fSDimitry Andric 2497753f127fSDimitry Andric // Is this ADD instruction only used as the base pointer of scalar loads and 2498753f127fSDimitry Andric // stores? 2499753f127fSDimitry Andric static bool isWorthFoldingAdd(SDValue Add) { 2500bdd1243dSDimitry Andric for (auto *Use : Add->uses()) { 2501753f127fSDimitry Andric if (Use->getOpcode() != ISD::LOAD && Use->getOpcode() != ISD::STORE && 2502753f127fSDimitry Andric Use->getOpcode() != ISD::ATOMIC_LOAD && 2503753f127fSDimitry Andric Use->getOpcode() != ISD::ATOMIC_STORE) 2504753f127fSDimitry Andric return false; 2505753f127fSDimitry Andric EVT VT = cast<MemSDNode>(Use)->getMemoryVT(); 2506753f127fSDimitry Andric if (!VT.isScalarInteger() && VT != MVT::f16 && VT != MVT::f32 && 2507753f127fSDimitry Andric VT != MVT::f64) 2508753f127fSDimitry Andric return false; 2509753f127fSDimitry Andric // Don't allow stores of the value. It must be used as the address. 2510753f127fSDimitry Andric if (Use->getOpcode() == ISD::STORE && 2511753f127fSDimitry Andric cast<StoreSDNode>(Use)->getValue() == Add) 2512753f127fSDimitry Andric return false; 2513753f127fSDimitry Andric if (Use->getOpcode() == ISD::ATOMIC_STORE && 2514753f127fSDimitry Andric cast<AtomicSDNode>(Use)->getVal() == Add) 2515753f127fSDimitry Andric return false; 2516753f127fSDimitry Andric } 2517753f127fSDimitry Andric 2518fe6060f1SDimitry Andric return true; 2519e8d8bef9SDimitry Andric } 2520e8d8bef9SDimitry Andric 252106c3fb27SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrRegRegScale(SDValue Addr, 252206c3fb27SDimitry Andric unsigned MaxShiftAmount, 252306c3fb27SDimitry Andric SDValue &Base, SDValue &Index, 252406c3fb27SDimitry Andric SDValue &Scale) { 252506c3fb27SDimitry Andric EVT VT = Addr.getSimpleValueType(); 252606c3fb27SDimitry Andric auto UnwrapShl = [this, VT, MaxShiftAmount](SDValue N, SDValue &Index, 252706c3fb27SDimitry Andric SDValue &Shift) { 252806c3fb27SDimitry Andric uint64_t ShiftAmt = 0; 252906c3fb27SDimitry Andric Index = N; 253006c3fb27SDimitry Andric 253106c3fb27SDimitry Andric if (N.getOpcode() == ISD::SHL && isa<ConstantSDNode>(N.getOperand(1))) { 253206c3fb27SDimitry Andric // Only match shifts by a value in range [0, MaxShiftAmount]. 253306c3fb27SDimitry Andric if (N.getConstantOperandVal(1) <= MaxShiftAmount) { 253406c3fb27SDimitry Andric Index = N.getOperand(0); 253506c3fb27SDimitry Andric ShiftAmt = N.getConstantOperandVal(1); 253606c3fb27SDimitry Andric } 253706c3fb27SDimitry Andric } 253806c3fb27SDimitry Andric 253906c3fb27SDimitry Andric Shift = CurDAG->getTargetConstant(ShiftAmt, SDLoc(N), VT); 254006c3fb27SDimitry Andric return ShiftAmt != 0; 254106c3fb27SDimitry Andric }; 254206c3fb27SDimitry Andric 254306c3fb27SDimitry Andric if (Addr.getOpcode() == ISD::ADD) { 254406c3fb27SDimitry Andric if (auto *C1 = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { 254506c3fb27SDimitry Andric SDValue AddrB = Addr.getOperand(0); 254606c3fb27SDimitry Andric if (AddrB.getOpcode() == ISD::ADD && 254706c3fb27SDimitry Andric UnwrapShl(AddrB.getOperand(0), Index, Scale) && 254806c3fb27SDimitry Andric !isa<ConstantSDNode>(AddrB.getOperand(1)) && 254906c3fb27SDimitry Andric isInt<12>(C1->getSExtValue())) { 255006c3fb27SDimitry Andric // (add (add (shl A C2) B) C1) -> (add (add B C1) (shl A C2)) 255106c3fb27SDimitry Andric SDValue C1Val = 255206c3fb27SDimitry Andric CurDAG->getTargetConstant(C1->getZExtValue(), SDLoc(Addr), VT); 255306c3fb27SDimitry Andric Base = SDValue(CurDAG->getMachineNode(RISCV::ADDI, SDLoc(Addr), VT, 255406c3fb27SDimitry Andric AddrB.getOperand(1), C1Val), 255506c3fb27SDimitry Andric 0); 255606c3fb27SDimitry Andric return true; 255706c3fb27SDimitry Andric } 255806c3fb27SDimitry Andric } else if (UnwrapShl(Addr.getOperand(0), Index, Scale)) { 255906c3fb27SDimitry Andric Base = Addr.getOperand(1); 256006c3fb27SDimitry Andric return true; 256106c3fb27SDimitry Andric } else { 256206c3fb27SDimitry Andric UnwrapShl(Addr.getOperand(1), Index, Scale); 256306c3fb27SDimitry Andric Base = Addr.getOperand(0); 256406c3fb27SDimitry Andric return true; 256506c3fb27SDimitry Andric } 256606c3fb27SDimitry Andric } else if (UnwrapShl(Addr, Index, Scale)) { 256706c3fb27SDimitry Andric EVT VT = Addr.getValueType(); 256806c3fb27SDimitry Andric Base = CurDAG->getRegister(RISCV::X0, VT); 256906c3fb27SDimitry Andric return true; 257006c3fb27SDimitry Andric } 257106c3fb27SDimitry Andric 257206c3fb27SDimitry Andric return false; 257306c3fb27SDimitry Andric } 257406c3fb27SDimitry Andric 257581ad6265SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrRegImm(SDValue Addr, SDValue &Base, 257606c3fb27SDimitry Andric SDValue &Offset, bool IsINX) { 257781ad6265SDimitry Andric if (SelectAddrFrameIndex(Addr, Base, Offset)) 257881ad6265SDimitry Andric return true; 257981ad6265SDimitry Andric 258081ad6265SDimitry Andric SDLoc DL(Addr); 258181ad6265SDimitry Andric MVT VT = Addr.getSimpleValueType(); 258281ad6265SDimitry Andric 258381ad6265SDimitry Andric if (Addr.getOpcode() == RISCVISD::ADD_LO) { 258481ad6265SDimitry Andric Base = Addr.getOperand(0); 258581ad6265SDimitry Andric Offset = Addr.getOperand(1); 258681ad6265SDimitry Andric return true; 258781ad6265SDimitry Andric } 258881ad6265SDimitry Andric 258906c3fb27SDimitry Andric int64_t RV32ZdinxRange = IsINX ? 4 : 0; 259081ad6265SDimitry Andric if (CurDAG->isBaseWithConstantOffset(Addr)) { 259181ad6265SDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 259206c3fb27SDimitry Andric if (isInt<12>(CVal) && isInt<12>(CVal + RV32ZdinxRange)) { 259381ad6265SDimitry Andric Base = Addr.getOperand(0); 259481ad6265SDimitry Andric if (Base.getOpcode() == RISCVISD::ADD_LO) { 259581ad6265SDimitry Andric SDValue LoOperand = Base.getOperand(1); 259681ad6265SDimitry Andric if (auto *GA = dyn_cast<GlobalAddressSDNode>(LoOperand)) { 259781ad6265SDimitry Andric // If the Lo in (ADD_LO hi, lo) is a global variable's address 259881ad6265SDimitry Andric // (its low part, really), then we can rely on the alignment of that 259981ad6265SDimitry Andric // variable to provide a margin of safety before low part can overflow 260081ad6265SDimitry Andric // the 12 bits of the load/store offset. Check if CVal falls within 260181ad6265SDimitry Andric // that margin; if so (low part + CVal) can't overflow. 260281ad6265SDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 260381ad6265SDimitry Andric Align Alignment = commonAlignment( 260481ad6265SDimitry Andric GA->getGlobal()->getPointerAlignment(DL), GA->getOffset()); 260581ad6265SDimitry Andric if (CVal == 0 || Alignment > CVal) { 260681ad6265SDimitry Andric int64_t CombinedOffset = CVal + GA->getOffset(); 260781ad6265SDimitry Andric Base = Base.getOperand(0); 260881ad6265SDimitry Andric Offset = CurDAG->getTargetGlobalAddress( 260981ad6265SDimitry Andric GA->getGlobal(), SDLoc(LoOperand), LoOperand.getValueType(), 261081ad6265SDimitry Andric CombinedOffset, GA->getTargetFlags()); 261181ad6265SDimitry Andric return true; 261281ad6265SDimitry Andric } 261381ad6265SDimitry Andric } 261481ad6265SDimitry Andric } 261581ad6265SDimitry Andric 261681ad6265SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Base)) 261781ad6265SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), VT); 261881ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(CVal, DL, VT); 261981ad6265SDimitry Andric return true; 262081ad6265SDimitry Andric } 262181ad6265SDimitry Andric } 262281ad6265SDimitry Andric 262381ad6265SDimitry Andric // Handle ADD with large immediates. 262481ad6265SDimitry Andric if (Addr.getOpcode() == ISD::ADD && isa<ConstantSDNode>(Addr.getOperand(1))) { 262581ad6265SDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 262606c3fb27SDimitry Andric assert(!(isInt<12>(CVal) && isInt<12>(CVal + RV32ZdinxRange)) && 262706c3fb27SDimitry Andric "simm12 not already handled?"); 262881ad6265SDimitry Andric 2629753f127fSDimitry Andric // Handle immediates in the range [-4096,-2049] or [2048, 4094]. We can use 2630753f127fSDimitry Andric // an ADDI for part of the offset and fold the rest into the load/store. 2631753f127fSDimitry Andric // This mirrors the AddiPair PatFrag in RISCVInstrInfo.td. 263281ad6265SDimitry Andric if (isInt<12>(CVal / 2) && isInt<12>(CVal - CVal / 2)) { 263381ad6265SDimitry Andric int64_t Adj = CVal < 0 ? -2048 : 2047; 263481ad6265SDimitry Andric Base = SDValue( 263581ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::ADDI, DL, VT, Addr.getOperand(0), 263681ad6265SDimitry Andric CurDAG->getTargetConstant(Adj, DL, VT)), 263781ad6265SDimitry Andric 0); 263881ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(CVal - Adj, DL, VT); 263981ad6265SDimitry Andric return true; 264081ad6265SDimitry Andric } 2641753f127fSDimitry Andric 2642753f127fSDimitry Andric // For larger immediates, we might be able to save one instruction from 2643753f127fSDimitry Andric // constant materialization by folding the Lo12 bits of the immediate into 2644753f127fSDimitry Andric // the address. We should only do this if the ADD is only used by loads and 2645753f127fSDimitry Andric // stores that can fold the lo12 bits. Otherwise, the ADD will get iseled 2646753f127fSDimitry Andric // separately with the full materialized immediate creating extra 2647753f127fSDimitry Andric // instructions. 2648753f127fSDimitry Andric if (isWorthFoldingAdd(Addr) && 2649753f127fSDimitry Andric selectConstantAddr(CurDAG, DL, VT, Subtarget, Addr.getOperand(1), Base, 2650753f127fSDimitry Andric Offset)) { 2651753f127fSDimitry Andric // Insert an ADD instruction with the materialized Hi52 bits. 2652753f127fSDimitry Andric Base = SDValue( 2653753f127fSDimitry Andric CurDAG->getMachineNode(RISCV::ADD, DL, VT, Addr.getOperand(0), Base), 2654753f127fSDimitry Andric 0); 2655753f127fSDimitry Andric return true; 265681ad6265SDimitry Andric } 2657753f127fSDimitry Andric } 2658753f127fSDimitry Andric 2659753f127fSDimitry Andric if (selectConstantAddr(CurDAG, DL, VT, Subtarget, Addr, Base, Offset)) 2660753f127fSDimitry Andric return true; 266181ad6265SDimitry Andric 266281ad6265SDimitry Andric Base = Addr; 266381ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(0, DL, VT); 266481ad6265SDimitry Andric return true; 266581ad6265SDimitry Andric } 266681ad6265SDimitry Andric 26675f757f3fSDimitry Andric /// Similar to SelectAddrRegImm, except that the least significant 5 bits of 26685f757f3fSDimitry Andric /// Offset shoule be all zeros. 26695f757f3fSDimitry Andric bool RISCVDAGToDAGISel::SelectAddrRegImmLsb00000(SDValue Addr, SDValue &Base, 26705f757f3fSDimitry Andric SDValue &Offset) { 26715f757f3fSDimitry Andric if (SelectAddrFrameIndex(Addr, Base, Offset)) 26725f757f3fSDimitry Andric return true; 26735f757f3fSDimitry Andric 26745f757f3fSDimitry Andric SDLoc DL(Addr); 26755f757f3fSDimitry Andric MVT VT = Addr.getSimpleValueType(); 26765f757f3fSDimitry Andric 26775f757f3fSDimitry Andric if (CurDAG->isBaseWithConstantOffset(Addr)) { 26785f757f3fSDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 26795f757f3fSDimitry Andric if (isInt<12>(CVal)) { 26805f757f3fSDimitry Andric Base = Addr.getOperand(0); 26815f757f3fSDimitry Andric 26825f757f3fSDimitry Andric // Early-out if not a valid offset. 26835f757f3fSDimitry Andric if ((CVal & 0b11111) != 0) { 26845f757f3fSDimitry Andric Base = Addr; 26855f757f3fSDimitry Andric Offset = CurDAG->getTargetConstant(0, DL, VT); 26865f757f3fSDimitry Andric return true; 26875f757f3fSDimitry Andric } 26885f757f3fSDimitry Andric 26895f757f3fSDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Base)) 26905f757f3fSDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), VT); 26915f757f3fSDimitry Andric Offset = CurDAG->getTargetConstant(CVal, DL, VT); 26925f757f3fSDimitry Andric return true; 26935f757f3fSDimitry Andric } 26945f757f3fSDimitry Andric } 26955f757f3fSDimitry Andric 26965f757f3fSDimitry Andric // Handle ADD with large immediates. 26975f757f3fSDimitry Andric if (Addr.getOpcode() == ISD::ADD && isa<ConstantSDNode>(Addr.getOperand(1))) { 26985f757f3fSDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 26995f757f3fSDimitry Andric assert(!(isInt<12>(CVal) && isInt<12>(CVal)) && 27005f757f3fSDimitry Andric "simm12 not already handled?"); 27015f757f3fSDimitry Andric 27025f757f3fSDimitry Andric // Handle immediates in the range [-4096,-2049] or [2017, 4065]. We can save 27035f757f3fSDimitry Andric // one instruction by folding adjustment (-2048 or 2016) into the address. 27045f757f3fSDimitry Andric if ((-2049 >= CVal && CVal >= -4096) || (4065 >= CVal && CVal >= 2017)) { 27055f757f3fSDimitry Andric int64_t Adj = CVal < 0 ? -2048 : 2016; 27065f757f3fSDimitry Andric int64_t AdjustedOffset = CVal - Adj; 27075f757f3fSDimitry Andric Base = SDValue(CurDAG->getMachineNode( 27085f757f3fSDimitry Andric RISCV::ADDI, DL, VT, Addr.getOperand(0), 27095f757f3fSDimitry Andric CurDAG->getTargetConstant(AdjustedOffset, DL, VT)), 27105f757f3fSDimitry Andric 0); 27115f757f3fSDimitry Andric Offset = CurDAG->getTargetConstant(Adj, DL, VT); 27125f757f3fSDimitry Andric return true; 27135f757f3fSDimitry Andric } 27145f757f3fSDimitry Andric 27155f757f3fSDimitry Andric if (selectConstantAddr(CurDAG, DL, VT, Subtarget, Addr.getOperand(1), Base, 27165f757f3fSDimitry Andric Offset, true)) { 27175f757f3fSDimitry Andric // Insert an ADD instruction with the materialized Hi52 bits. 27185f757f3fSDimitry Andric Base = SDValue( 27195f757f3fSDimitry Andric CurDAG->getMachineNode(RISCV::ADD, DL, VT, Addr.getOperand(0), Base), 27205f757f3fSDimitry Andric 0); 27215f757f3fSDimitry Andric return true; 27225f757f3fSDimitry Andric } 27235f757f3fSDimitry Andric } 27245f757f3fSDimitry Andric 27255f757f3fSDimitry Andric if (selectConstantAddr(CurDAG, DL, VT, Subtarget, Addr, Base, Offset, true)) 27265f757f3fSDimitry Andric return true; 27275f757f3fSDimitry Andric 27285f757f3fSDimitry Andric Base = Addr; 27295f757f3fSDimitry Andric Offset = CurDAG->getTargetConstant(0, DL, VT); 27305f757f3fSDimitry Andric return true; 27315f757f3fSDimitry Andric } 27325f757f3fSDimitry Andric 2733*0fca6ea1SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrRegReg(SDValue Addr, SDValue &Base, 2734*0fca6ea1SDimitry Andric SDValue &Offset) { 2735*0fca6ea1SDimitry Andric if (Addr.getOpcode() != ISD::ADD) 2736*0fca6ea1SDimitry Andric return false; 2737*0fca6ea1SDimitry Andric 2738*0fca6ea1SDimitry Andric if (isa<ConstantSDNode>(Addr.getOperand(1))) 2739*0fca6ea1SDimitry Andric return false; 2740*0fca6ea1SDimitry Andric 2741*0fca6ea1SDimitry Andric Base = Addr.getOperand(1); 2742*0fca6ea1SDimitry Andric Offset = Addr.getOperand(0); 2743*0fca6ea1SDimitry Andric return true; 2744*0fca6ea1SDimitry Andric } 2745*0fca6ea1SDimitry Andric 2746fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth, 2747fe6060f1SDimitry Andric SDValue &ShAmt) { 2748bdd1243dSDimitry Andric ShAmt = N; 2749bdd1243dSDimitry Andric 27505f757f3fSDimitry Andric // Peek through zext. 27515f757f3fSDimitry Andric if (ShAmt->getOpcode() == ISD::ZERO_EXTEND) 27525f757f3fSDimitry Andric ShAmt = ShAmt.getOperand(0); 27535f757f3fSDimitry Andric 275406c3fb27SDimitry Andric // Shift instructions on RISC-V only read the lower 5 or 6 bits of the shift 2755fe6060f1SDimitry Andric // amount. If there is an AND on the shift amount, we can bypass it if it 2756fe6060f1SDimitry Andric // doesn't affect any of those bits. 27575f757f3fSDimitry Andric if (ShAmt.getOpcode() == ISD::AND && 27585f757f3fSDimitry Andric isa<ConstantSDNode>(ShAmt.getOperand(1))) { 2759bdd1243dSDimitry Andric const APInt &AndMask = ShAmt.getConstantOperandAPInt(1); 2760979e22ffSDimitry Andric 2761fe6060f1SDimitry Andric // Since the max shift amount is a power of 2 we can subtract 1 to make a 2762fe6060f1SDimitry Andric // mask that covers the bits needed to represent all shift amounts. 2763fe6060f1SDimitry Andric assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!"); 2764fe6060f1SDimitry Andric APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1); 2765e8d8bef9SDimitry Andric 2766fe6060f1SDimitry Andric if (ShMask.isSubsetOf(AndMask)) { 2767bdd1243dSDimitry Andric ShAmt = ShAmt.getOperand(0); 2768bdd1243dSDimitry Andric } else { 2769fe6060f1SDimitry Andric // SimplifyDemandedBits may have optimized the mask so try restoring any 2770fe6060f1SDimitry Andric // bits that are known zero. 2771bdd1243dSDimitry Andric KnownBits Known = CurDAG->computeKnownBits(ShAmt.getOperand(0)); 2772bdd1243dSDimitry Andric if (!ShMask.isSubsetOf(AndMask | Known.Zero)) 2773bdd1243dSDimitry Andric return true; 2774bdd1243dSDimitry Andric ShAmt = ShAmt.getOperand(0); 2775bdd1243dSDimitry Andric } 2776bdd1243dSDimitry Andric } 2777bdd1243dSDimitry Andric 2778bdd1243dSDimitry Andric if (ShAmt.getOpcode() == ISD::ADD && 2779bdd1243dSDimitry Andric isa<ConstantSDNode>(ShAmt.getOperand(1))) { 2780bdd1243dSDimitry Andric uint64_t Imm = ShAmt.getConstantOperandVal(1); 2781bdd1243dSDimitry Andric // If we are shifting by X+N where N == 0 mod Size, then just shift by X 2782bdd1243dSDimitry Andric // to avoid the ADD. 2783bdd1243dSDimitry Andric if (Imm != 0 && Imm % ShiftWidth == 0) { 2784bdd1243dSDimitry Andric ShAmt = ShAmt.getOperand(0); 2785fe6060f1SDimitry Andric return true; 2786fe6060f1SDimitry Andric } 2787bdd1243dSDimitry Andric } else if (ShAmt.getOpcode() == ISD::SUB && 2788bdd1243dSDimitry Andric isa<ConstantSDNode>(ShAmt.getOperand(0))) { 2789bdd1243dSDimitry Andric uint64_t Imm = ShAmt.getConstantOperandVal(0); 279081ad6265SDimitry Andric // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to 279181ad6265SDimitry Andric // generate a NEG instead of a SUB of a constant. 279281ad6265SDimitry Andric if (Imm != 0 && Imm % ShiftWidth == 0) { 2793bdd1243dSDimitry Andric SDLoc DL(ShAmt); 2794bdd1243dSDimitry Andric EVT VT = ShAmt.getValueType(); 279581ad6265SDimitry Andric SDValue Zero = CurDAG->getRegister(RISCV::X0, VT); 279681ad6265SDimitry Andric unsigned NegOpc = VT == MVT::i64 ? RISCV::SUBW : RISCV::SUB; 279781ad6265SDimitry Andric MachineSDNode *Neg = CurDAG->getMachineNode(NegOpc, DL, VT, Zero, 2798bdd1243dSDimitry Andric ShAmt.getOperand(1)); 279981ad6265SDimitry Andric ShAmt = SDValue(Neg, 0); 280081ad6265SDimitry Andric return true; 280181ad6265SDimitry Andric } 2802bdd1243dSDimitry Andric // If we are shifting by N-X where N == -1 mod Size, then just shift by ~X 2803bdd1243dSDimitry Andric // to generate a NOT instead of a SUB of a constant. 2804bdd1243dSDimitry Andric if (Imm % ShiftWidth == ShiftWidth - 1) { 2805bdd1243dSDimitry Andric SDLoc DL(ShAmt); 2806bdd1243dSDimitry Andric EVT VT = ShAmt.getValueType(); 2807bdd1243dSDimitry Andric MachineSDNode *Not = 2808bdd1243dSDimitry Andric CurDAG->getMachineNode(RISCV::XORI, DL, VT, ShAmt.getOperand(1), 2809bdd1243dSDimitry Andric CurDAG->getTargetConstant(-1, DL, VT)); 2810bdd1243dSDimitry Andric ShAmt = SDValue(Not, 0); 2811bdd1243dSDimitry Andric return true; 2812bdd1243dSDimitry Andric } 2813fe6060f1SDimitry Andric } 2814fe6060f1SDimitry Andric 2815fe6060f1SDimitry Andric return true; 2816fe6060f1SDimitry Andric } 2817fe6060f1SDimitry Andric 281806c3fb27SDimitry Andric /// RISC-V doesn't have general instructions for integer setne/seteq, but we can 281906c3fb27SDimitry Andric /// check for equality with 0. This function emits instructions that convert the 282006c3fb27SDimitry Andric /// seteq/setne into something that can be compared with 0. 282106c3fb27SDimitry Andric /// \p ExpectedCCVal indicates the condition code to attempt to match (e.g. 282206c3fb27SDimitry Andric /// ISD::SETNE). 282306c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectSETCC(SDValue N, ISD::CondCode ExpectedCCVal, 282406c3fb27SDimitry Andric SDValue &Val) { 282506c3fb27SDimitry Andric assert(ISD::isIntEqualitySetCC(ExpectedCCVal) && 282606c3fb27SDimitry Andric "Unexpected condition code!"); 282706c3fb27SDimitry Andric 282806c3fb27SDimitry Andric // We're looking for a setcc. 282906c3fb27SDimitry Andric if (N->getOpcode() != ISD::SETCC) 283006c3fb27SDimitry Andric return false; 283106c3fb27SDimitry Andric 283206c3fb27SDimitry Andric // Must be an equality comparison. 283306c3fb27SDimitry Andric ISD::CondCode CCVal = cast<CondCodeSDNode>(N->getOperand(2))->get(); 283406c3fb27SDimitry Andric if (CCVal != ExpectedCCVal) 283506c3fb27SDimitry Andric return false; 283606c3fb27SDimitry Andric 283706c3fb27SDimitry Andric SDValue LHS = N->getOperand(0); 283806c3fb27SDimitry Andric SDValue RHS = N->getOperand(1); 283906c3fb27SDimitry Andric 284006c3fb27SDimitry Andric if (!LHS.getValueType().isScalarInteger()) 284106c3fb27SDimitry Andric return false; 284206c3fb27SDimitry Andric 284306c3fb27SDimitry Andric // If the RHS side is 0, we don't need any extra instructions, return the LHS. 284406c3fb27SDimitry Andric if (isNullConstant(RHS)) { 284506c3fb27SDimitry Andric Val = LHS; 284606c3fb27SDimitry Andric return true; 284706c3fb27SDimitry Andric } 284806c3fb27SDimitry Andric 284906c3fb27SDimitry Andric SDLoc DL(N); 285006c3fb27SDimitry Andric 285106c3fb27SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(RHS)) { 285206c3fb27SDimitry Andric int64_t CVal = C->getSExtValue(); 285306c3fb27SDimitry Andric // If the RHS is -2048, we can use xori to produce 0 if the LHS is -2048 and 285406c3fb27SDimitry Andric // non-zero otherwise. 285506c3fb27SDimitry Andric if (CVal == -2048) { 285606c3fb27SDimitry Andric Val = 285706c3fb27SDimitry Andric SDValue(CurDAG->getMachineNode( 285806c3fb27SDimitry Andric RISCV::XORI, DL, N->getValueType(0), LHS, 285906c3fb27SDimitry Andric CurDAG->getTargetConstant(CVal, DL, N->getValueType(0))), 286006c3fb27SDimitry Andric 0); 286106c3fb27SDimitry Andric return true; 286206c3fb27SDimitry Andric } 286306c3fb27SDimitry Andric // If the RHS is [-2047,2048], we can use addi with -RHS to produce 0 if the 286406c3fb27SDimitry Andric // LHS is equal to the RHS and non-zero otherwise. 286506c3fb27SDimitry Andric if (isInt<12>(CVal) || CVal == 2048) { 286606c3fb27SDimitry Andric Val = 286706c3fb27SDimitry Andric SDValue(CurDAG->getMachineNode( 286806c3fb27SDimitry Andric RISCV::ADDI, DL, N->getValueType(0), LHS, 286906c3fb27SDimitry Andric CurDAG->getTargetConstant(-CVal, DL, N->getValueType(0))), 287006c3fb27SDimitry Andric 0); 287106c3fb27SDimitry Andric return true; 287206c3fb27SDimitry Andric } 287306c3fb27SDimitry Andric } 287406c3fb27SDimitry Andric 287506c3fb27SDimitry Andric // If nothing else we can XOR the LHS and RHS to produce zero if they are 287606c3fb27SDimitry Andric // equal and a non-zero value if they aren't. 287706c3fb27SDimitry Andric Val = SDValue( 287806c3fb27SDimitry Andric CurDAG->getMachineNode(RISCV::XOR, DL, N->getValueType(0), LHS, RHS), 0); 287906c3fb27SDimitry Andric return true; 288006c3fb27SDimitry Andric } 288106c3fb27SDimitry Andric 288206c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectSExtBits(SDValue N, unsigned Bits, SDValue &Val) { 2883fe6060f1SDimitry Andric if (N.getOpcode() == ISD::SIGN_EXTEND_INREG && 288406c3fb27SDimitry Andric cast<VTSDNode>(N.getOperand(1))->getVT().getSizeInBits() == Bits) { 2885fe6060f1SDimitry Andric Val = N.getOperand(0); 2886fe6060f1SDimitry Andric return true; 2887fe6060f1SDimitry Andric } 288806c3fb27SDimitry Andric 288906c3fb27SDimitry Andric auto UnwrapShlSra = [](SDValue N, unsigned ShiftAmt) { 289006c3fb27SDimitry Andric if (N.getOpcode() != ISD::SRA || !isa<ConstantSDNode>(N.getOperand(1))) 289106c3fb27SDimitry Andric return N; 289206c3fb27SDimitry Andric 289306c3fb27SDimitry Andric SDValue N0 = N.getOperand(0); 289406c3fb27SDimitry Andric if (N0.getOpcode() == ISD::SHL && isa<ConstantSDNode>(N0.getOperand(1)) && 289506c3fb27SDimitry Andric N.getConstantOperandVal(1) == ShiftAmt && 289606c3fb27SDimitry Andric N0.getConstantOperandVal(1) == ShiftAmt) 289706c3fb27SDimitry Andric return N0.getOperand(0); 289806c3fb27SDimitry Andric 289906c3fb27SDimitry Andric return N; 290006c3fb27SDimitry Andric }; 290106c3fb27SDimitry Andric 2902fe6060f1SDimitry Andric MVT VT = N.getSimpleValueType(); 290306c3fb27SDimitry Andric if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - Bits)) { 290406c3fb27SDimitry Andric Val = UnwrapShlSra(N, VT.getSizeInBits() - Bits); 2905fe6060f1SDimitry Andric return true; 2906fe6060f1SDimitry Andric } 2907fe6060f1SDimitry Andric 2908fe6060f1SDimitry Andric return false; 2909fe6060f1SDimitry Andric } 2910fe6060f1SDimitry Andric 2911bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::selectZExtBits(SDValue N, unsigned Bits, SDValue &Val) { 2912fe6060f1SDimitry Andric if (N.getOpcode() == ISD::AND) { 2913fe6060f1SDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1)); 2914bdd1243dSDimitry Andric if (C && C->getZExtValue() == maskTrailingOnes<uint64_t>(Bits)) { 2915fe6060f1SDimitry Andric Val = N.getOperand(0); 2916fe6060f1SDimitry Andric return true; 2917fe6060f1SDimitry Andric } 2918fe6060f1SDimitry Andric } 2919fe6060f1SDimitry Andric MVT VT = N.getSimpleValueType(); 2920bdd1243dSDimitry Andric APInt Mask = APInt::getBitsSetFrom(VT.getSizeInBits(), Bits); 2921fe6060f1SDimitry Andric if (CurDAG->MaskedValueIsZero(N, Mask)) { 2922fe6060f1SDimitry Andric Val = N; 2923fe6060f1SDimitry Andric return true; 2924fe6060f1SDimitry Andric } 2925fe6060f1SDimitry Andric 2926fe6060f1SDimitry Andric return false; 2927fe6060f1SDimitry Andric } 2928fe6060f1SDimitry Andric 2929753f127fSDimitry Andric /// Look for various patterns that can be done with a SHL that can be folded 2930753f127fSDimitry Andric /// into a SHXADD. \p ShAmt contains 1, 2, or 3 and is set based on which 2931753f127fSDimitry Andric /// SHXADD we are trying to match. 2932753f127fSDimitry Andric bool RISCVDAGToDAGISel::selectSHXADDOp(SDValue N, unsigned ShAmt, 2933753f127fSDimitry Andric SDValue &Val) { 2934753f127fSDimitry Andric if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) { 2935753f127fSDimitry Andric SDValue N0 = N.getOperand(0); 2936753f127fSDimitry Andric 2937753f127fSDimitry Andric bool LeftShift = N0.getOpcode() == ISD::SHL; 2938753f127fSDimitry Andric if ((LeftShift || N0.getOpcode() == ISD::SRL) && 2939753f127fSDimitry Andric isa<ConstantSDNode>(N0.getOperand(1))) { 2940753f127fSDimitry Andric uint64_t Mask = N.getConstantOperandVal(1); 2941753f127fSDimitry Andric unsigned C2 = N0.getConstantOperandVal(1); 2942753f127fSDimitry Andric 2943753f127fSDimitry Andric unsigned XLen = Subtarget->getXLen(); 2944753f127fSDimitry Andric if (LeftShift) 2945753f127fSDimitry Andric Mask &= maskTrailingZeros<uint64_t>(C2); 2946753f127fSDimitry Andric else 2947753f127fSDimitry Andric Mask &= maskTrailingOnes<uint64_t>(XLen - C2); 2948753f127fSDimitry Andric 2949753f127fSDimitry Andric // Look for (and (shl y, c2), c1) where c1 is a shifted mask with no 2950753f127fSDimitry Andric // leading zeros and c3 trailing zeros. We can use an SRLI by c2+c3 2951753f127fSDimitry Andric // followed by a SHXADD with c3 for the X amount. 2952753f127fSDimitry Andric if (isShiftedMask_64(Mask)) { 2953bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(Mask); 295406c3fb27SDimitry Andric unsigned Trailing = llvm::countr_zero(Mask); 2955753f127fSDimitry Andric if (LeftShift && Leading == 0 && C2 < Trailing && Trailing == ShAmt) { 2956753f127fSDimitry Andric SDLoc DL(N); 2957753f127fSDimitry Andric EVT VT = N.getValueType(); 2958753f127fSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 2959753f127fSDimitry Andric RISCV::SRLI, DL, VT, N0.getOperand(0), 2960753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)), 2961753f127fSDimitry Andric 0); 2962753f127fSDimitry Andric return true; 2963753f127fSDimitry Andric } 2964753f127fSDimitry Andric // Look for (and (shr y, c2), c1) where c1 is a shifted mask with c2 2965753f127fSDimitry Andric // leading zeros and c3 trailing zeros. We can use an SRLI by C3 2966753f127fSDimitry Andric // followed by a SHXADD using c3 for the X amount. 2967753f127fSDimitry Andric if (!LeftShift && Leading == C2 && Trailing == ShAmt) { 2968753f127fSDimitry Andric SDLoc DL(N); 2969753f127fSDimitry Andric EVT VT = N.getValueType(); 2970753f127fSDimitry Andric Val = SDValue( 2971753f127fSDimitry Andric CurDAG->getMachineNode( 2972753f127fSDimitry Andric RISCV::SRLI, DL, VT, N0.getOperand(0), 2973753f127fSDimitry Andric CurDAG->getTargetConstant(Leading + Trailing, DL, VT)), 2974753f127fSDimitry Andric 0); 2975753f127fSDimitry Andric return true; 2976753f127fSDimitry Andric } 2977753f127fSDimitry Andric } 2978753f127fSDimitry Andric } 2979753f127fSDimitry Andric } 2980753f127fSDimitry Andric 2981753f127fSDimitry Andric bool LeftShift = N.getOpcode() == ISD::SHL; 2982753f127fSDimitry Andric if ((LeftShift || N.getOpcode() == ISD::SRL) && 2983753f127fSDimitry Andric isa<ConstantSDNode>(N.getOperand(1))) { 2984753f127fSDimitry Andric SDValue N0 = N.getOperand(0); 2985753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && N0.hasOneUse() && 2986753f127fSDimitry Andric isa<ConstantSDNode>(N0.getOperand(1))) { 2987753f127fSDimitry Andric uint64_t Mask = N0.getConstantOperandVal(1); 2988753f127fSDimitry Andric if (isShiftedMask_64(Mask)) { 2989753f127fSDimitry Andric unsigned C1 = N.getConstantOperandVal(1); 2990753f127fSDimitry Andric unsigned XLen = Subtarget->getXLen(); 2991bdd1243dSDimitry Andric unsigned Leading = XLen - llvm::bit_width(Mask); 299206c3fb27SDimitry Andric unsigned Trailing = llvm::countr_zero(Mask); 2993753f127fSDimitry Andric // Look for (shl (and X, Mask), C1) where Mask has 32 leading zeros and 2994753f127fSDimitry Andric // C3 trailing zeros. If C1+C3==ShAmt we can use SRLIW+SHXADD. 2995753f127fSDimitry Andric if (LeftShift && Leading == 32 && Trailing > 0 && 2996753f127fSDimitry Andric (Trailing + C1) == ShAmt) { 2997753f127fSDimitry Andric SDLoc DL(N); 2998753f127fSDimitry Andric EVT VT = N.getValueType(); 2999753f127fSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 3000753f127fSDimitry Andric RISCV::SRLIW, DL, VT, N0.getOperand(0), 3001753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)), 3002753f127fSDimitry Andric 0); 3003753f127fSDimitry Andric return true; 3004753f127fSDimitry Andric } 3005753f127fSDimitry Andric // Look for (srl (and X, Mask), C1) where Mask has 32 leading zeros and 3006753f127fSDimitry Andric // C3 trailing zeros. If C3-C1==ShAmt we can use SRLIW+SHXADD. 3007753f127fSDimitry Andric if (!LeftShift && Leading == 32 && Trailing > C1 && 3008753f127fSDimitry Andric (Trailing - C1) == ShAmt) { 3009753f127fSDimitry Andric SDLoc DL(N); 3010753f127fSDimitry Andric EVT VT = N.getValueType(); 3011753f127fSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 3012753f127fSDimitry Andric RISCV::SRLIW, DL, VT, N0.getOperand(0), 3013753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)), 3014753f127fSDimitry Andric 0); 3015753f127fSDimitry Andric return true; 3016753f127fSDimitry Andric } 3017753f127fSDimitry Andric } 3018753f127fSDimitry Andric } 3019753f127fSDimitry Andric } 3020753f127fSDimitry Andric 3021753f127fSDimitry Andric return false; 3022753f127fSDimitry Andric } 3023753f127fSDimitry Andric 3024bdd1243dSDimitry Andric /// Look for various patterns that can be done with a SHL that can be folded 3025bdd1243dSDimitry Andric /// into a SHXADD_UW. \p ShAmt contains 1, 2, or 3 and is set based on which 3026bdd1243dSDimitry Andric /// SHXADD_UW we are trying to match. 3027bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::selectSHXADD_UWOp(SDValue N, unsigned ShAmt, 3028bdd1243dSDimitry Andric SDValue &Val) { 3029bdd1243dSDimitry Andric if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1)) && 3030bdd1243dSDimitry Andric N.hasOneUse()) { 3031bdd1243dSDimitry Andric SDValue N0 = N.getOperand(0); 3032bdd1243dSDimitry Andric if (N0.getOpcode() == ISD::SHL && isa<ConstantSDNode>(N0.getOperand(1)) && 3033bdd1243dSDimitry Andric N0.hasOneUse()) { 3034bdd1243dSDimitry Andric uint64_t Mask = N.getConstantOperandVal(1); 3035bdd1243dSDimitry Andric unsigned C2 = N0.getConstantOperandVal(1); 3036bdd1243dSDimitry Andric 3037bdd1243dSDimitry Andric Mask &= maskTrailingZeros<uint64_t>(C2); 3038bdd1243dSDimitry Andric 3039bdd1243dSDimitry Andric // Look for (and (shl y, c2), c1) where c1 is a shifted mask with 3040bdd1243dSDimitry Andric // 32-ShAmt leading zeros and c2 trailing zeros. We can use SLLI by 3041bdd1243dSDimitry Andric // c2-ShAmt followed by SHXADD_UW with ShAmt for the X amount. 3042bdd1243dSDimitry Andric if (isShiftedMask_64(Mask)) { 304306c3fb27SDimitry Andric unsigned Leading = llvm::countl_zero(Mask); 304406c3fb27SDimitry Andric unsigned Trailing = llvm::countr_zero(Mask); 3045bdd1243dSDimitry Andric if (Leading == 32 - ShAmt && Trailing == C2 && Trailing > ShAmt) { 3046bdd1243dSDimitry Andric SDLoc DL(N); 3047bdd1243dSDimitry Andric EVT VT = N.getValueType(); 3048bdd1243dSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 3049bdd1243dSDimitry Andric RISCV::SLLI, DL, VT, N0.getOperand(0), 3050bdd1243dSDimitry Andric CurDAG->getTargetConstant(C2 - ShAmt, DL, VT)), 3051bdd1243dSDimitry Andric 0); 3052bdd1243dSDimitry Andric return true; 3053bdd1243dSDimitry Andric } 3054bdd1243dSDimitry Andric } 3055bdd1243dSDimitry Andric } 3056bdd1243dSDimitry Andric } 3057bdd1243dSDimitry Andric 3058bdd1243dSDimitry Andric return false; 3059bdd1243dSDimitry Andric } 3060bdd1243dSDimitry Andric 30615f757f3fSDimitry Andric static bool vectorPseudoHasAllNBitUsers(SDNode *User, unsigned UserOpNo, 30625f757f3fSDimitry Andric unsigned Bits, 30635f757f3fSDimitry Andric const TargetInstrInfo *TII) { 30645f757f3fSDimitry Andric unsigned MCOpcode = RISCV::getRVVMCOpcode(User->getMachineOpcode()); 30655f757f3fSDimitry Andric 30665f757f3fSDimitry Andric if (!MCOpcode) 30675f757f3fSDimitry Andric return false; 30685f757f3fSDimitry Andric 30695f757f3fSDimitry Andric const MCInstrDesc &MCID = TII->get(User->getMachineOpcode()); 30705f757f3fSDimitry Andric const uint64_t TSFlags = MCID.TSFlags; 30715f757f3fSDimitry Andric if (!RISCVII::hasSEWOp(TSFlags)) 30725f757f3fSDimitry Andric return false; 30735f757f3fSDimitry Andric assert(RISCVII::hasVLOp(TSFlags)); 30745f757f3fSDimitry Andric 30755f757f3fSDimitry Andric bool HasGlueOp = User->getGluedNode() != nullptr; 30765f757f3fSDimitry Andric unsigned ChainOpIdx = User->getNumOperands() - HasGlueOp - 1; 30775f757f3fSDimitry Andric bool HasChainOp = User->getOperand(ChainOpIdx).getValueType() == MVT::Other; 30785f757f3fSDimitry Andric bool HasVecPolicyOp = RISCVII::hasVecPolicyOp(TSFlags); 30795f757f3fSDimitry Andric unsigned VLIdx = 30805f757f3fSDimitry Andric User->getNumOperands() - HasVecPolicyOp - HasChainOp - HasGlueOp - 2; 30815f757f3fSDimitry Andric const unsigned Log2SEW = User->getConstantOperandVal(VLIdx + 1); 30825f757f3fSDimitry Andric 30835f757f3fSDimitry Andric if (UserOpNo == VLIdx) 30845f757f3fSDimitry Andric return false; 30855f757f3fSDimitry Andric 30865f757f3fSDimitry Andric auto NumDemandedBits = 30875f757f3fSDimitry Andric RISCV::getVectorLowDemandedScalarBits(MCOpcode, Log2SEW); 30885f757f3fSDimitry Andric return NumDemandedBits && Bits >= *NumDemandedBits; 30895f757f3fSDimitry Andric } 30905f757f3fSDimitry Andric 3091349cc55cSDimitry Andric // Return true if all users of this SDNode* only consume the lower \p Bits. 3092349cc55cSDimitry Andric // This can be used to form W instructions for add/sub/mul/shl even when the 3093349cc55cSDimitry Andric // root isn't a sext_inreg. This can allow the ADDW/SUBW/MULW/SLLIW to CSE if 3094349cc55cSDimitry Andric // SimplifyDemandedBits has made it so some users see a sext_inreg and some 3095349cc55cSDimitry Andric // don't. The sext_inreg+add/sub/mul/shl will get selected, but still leave 3096349cc55cSDimitry Andric // the add/sub/mul/shl to become non-W instructions. By checking the users we 3097349cc55cSDimitry Andric // may be able to use a W instruction and CSE with the other instruction if 3098349cc55cSDimitry Andric // this has happened. We could try to detect that the CSE opportunity exists 3099349cc55cSDimitry Andric // before doing this, but that would be more complicated. 3100bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::hasAllNBitUsers(SDNode *Node, unsigned Bits, 3101bdd1243dSDimitry Andric const unsigned Depth) const { 3102349cc55cSDimitry Andric assert((Node->getOpcode() == ISD::ADD || Node->getOpcode() == ISD::SUB || 3103349cc55cSDimitry Andric Node->getOpcode() == ISD::MUL || Node->getOpcode() == ISD::SHL || 3104bdd1243dSDimitry Andric Node->getOpcode() == ISD::SRL || Node->getOpcode() == ISD::AND || 3105bdd1243dSDimitry Andric Node->getOpcode() == ISD::OR || Node->getOpcode() == ISD::XOR || 3106349cc55cSDimitry Andric Node->getOpcode() == ISD::SIGN_EXTEND_INREG || 3107bdd1243dSDimitry Andric isa<ConstantSDNode>(Node) || Depth != 0) && 3108349cc55cSDimitry Andric "Unexpected opcode"); 3109349cc55cSDimitry Andric 3110bdd1243dSDimitry Andric if (Depth >= SelectionDAG::MaxRecursionDepth) 3111bdd1243dSDimitry Andric return false; 3112bdd1243dSDimitry Andric 31135f757f3fSDimitry Andric // The PatFrags that call this may run before RISCVGenDAGISel.inc has checked 31145f757f3fSDimitry Andric // the VT. Ensure the type is scalar to avoid wasting time on vectors. 31155f757f3fSDimitry Andric if (Depth == 0 && !Node->getValueType(0).isScalarInteger()) 31165f757f3fSDimitry Andric return false; 31175f757f3fSDimitry Andric 3118349cc55cSDimitry Andric for (auto UI = Node->use_begin(), UE = Node->use_end(); UI != UE; ++UI) { 3119349cc55cSDimitry Andric SDNode *User = *UI; 3120349cc55cSDimitry Andric // Users of this node should have already been instruction selected 3121349cc55cSDimitry Andric if (!User->isMachineOpcode()) 3122349cc55cSDimitry Andric return false; 3123349cc55cSDimitry Andric 3124349cc55cSDimitry Andric // TODO: Add more opcodes? 3125349cc55cSDimitry Andric switch (User->getMachineOpcode()) { 3126349cc55cSDimitry Andric default: 31275f757f3fSDimitry Andric if (vectorPseudoHasAllNBitUsers(User, UI.getOperandNo(), Bits, TII)) 31285f757f3fSDimitry Andric break; 3129349cc55cSDimitry Andric return false; 3130349cc55cSDimitry Andric case RISCV::ADDW: 3131349cc55cSDimitry Andric case RISCV::ADDIW: 3132349cc55cSDimitry Andric case RISCV::SUBW: 3133349cc55cSDimitry Andric case RISCV::MULW: 3134349cc55cSDimitry Andric case RISCV::SLLW: 3135349cc55cSDimitry Andric case RISCV::SLLIW: 3136349cc55cSDimitry Andric case RISCV::SRAW: 3137349cc55cSDimitry Andric case RISCV::SRAIW: 3138349cc55cSDimitry Andric case RISCV::SRLW: 3139349cc55cSDimitry Andric case RISCV::SRLIW: 3140349cc55cSDimitry Andric case RISCV::DIVW: 3141349cc55cSDimitry Andric case RISCV::DIVUW: 3142349cc55cSDimitry Andric case RISCV::REMW: 3143349cc55cSDimitry Andric case RISCV::REMUW: 3144349cc55cSDimitry Andric case RISCV::ROLW: 3145349cc55cSDimitry Andric case RISCV::RORW: 3146349cc55cSDimitry Andric case RISCV::RORIW: 3147349cc55cSDimitry Andric case RISCV::CLZW: 3148349cc55cSDimitry Andric case RISCV::CTZW: 3149349cc55cSDimitry Andric case RISCV::CPOPW: 31501fd87a68SDimitry Andric case RISCV::SLLI_UW: 315181ad6265SDimitry Andric case RISCV::FMV_W_X: 3152349cc55cSDimitry Andric case RISCV::FCVT_H_W: 3153349cc55cSDimitry Andric case RISCV::FCVT_H_WU: 3154349cc55cSDimitry Andric case RISCV::FCVT_S_W: 3155349cc55cSDimitry Andric case RISCV::FCVT_S_WU: 3156349cc55cSDimitry Andric case RISCV::FCVT_D_W: 3157349cc55cSDimitry Andric case RISCV::FCVT_D_WU: 315806c3fb27SDimitry Andric case RISCV::TH_REVW: 315906c3fb27SDimitry Andric case RISCV::TH_SRRIW: 3160349cc55cSDimitry Andric if (Bits < 32) 3161349cc55cSDimitry Andric return false; 3162349cc55cSDimitry Andric break; 3163bdd1243dSDimitry Andric case RISCV::SLL: 3164bdd1243dSDimitry Andric case RISCV::SRA: 3165bdd1243dSDimitry Andric case RISCV::SRL: 3166bdd1243dSDimitry Andric case RISCV::ROL: 3167bdd1243dSDimitry Andric case RISCV::ROR: 3168bdd1243dSDimitry Andric case RISCV::BSET: 3169bdd1243dSDimitry Andric case RISCV::BCLR: 3170bdd1243dSDimitry Andric case RISCV::BINV: 3171bdd1243dSDimitry Andric // Shift amount operands only use log2(Xlen) bits. 3172bdd1243dSDimitry Andric if (UI.getOperandNo() != 1 || Bits < Log2_32(Subtarget->getXLen())) 3173bdd1243dSDimitry Andric return false; 3174bdd1243dSDimitry Andric break; 3175349cc55cSDimitry Andric case RISCV::SLLI: 3176349cc55cSDimitry Andric // SLLI only uses the lower (XLen - ShAmt) bits. 3177349cc55cSDimitry Andric if (Bits < Subtarget->getXLen() - User->getConstantOperandVal(1)) 3178349cc55cSDimitry Andric return false; 3179349cc55cSDimitry Andric break; 318004eeddc0SDimitry Andric case RISCV::ANDI: 3181bdd1243dSDimitry Andric if (Bits >= (unsigned)llvm::bit_width(User->getConstantOperandVal(1))) 318204eeddc0SDimitry Andric break; 3183bdd1243dSDimitry Andric goto RecCheck; 3184bdd1243dSDimitry Andric case RISCV::ORI: { 3185bdd1243dSDimitry Andric uint64_t Imm = cast<ConstantSDNode>(User->getOperand(1))->getSExtValue(); 3186bdd1243dSDimitry Andric if (Bits >= (unsigned)llvm::bit_width<uint64_t>(~Imm)) 3187bdd1243dSDimitry Andric break; 3188bdd1243dSDimitry Andric [[fallthrough]]; 3189bdd1243dSDimitry Andric } 3190bdd1243dSDimitry Andric case RISCV::AND: 3191bdd1243dSDimitry Andric case RISCV::OR: 3192bdd1243dSDimitry Andric case RISCV::XOR: 3193bdd1243dSDimitry Andric case RISCV::XORI: 3194bdd1243dSDimitry Andric case RISCV::ANDN: 3195bdd1243dSDimitry Andric case RISCV::ORN: 3196bdd1243dSDimitry Andric case RISCV::XNOR: 3197bdd1243dSDimitry Andric case RISCV::SH1ADD: 3198bdd1243dSDimitry Andric case RISCV::SH2ADD: 3199bdd1243dSDimitry Andric case RISCV::SH3ADD: 3200bdd1243dSDimitry Andric RecCheck: 3201bdd1243dSDimitry Andric if (hasAllNBitUsers(User, Bits, Depth + 1)) 3202bdd1243dSDimitry Andric break; 3203bdd1243dSDimitry Andric return false; 3204bdd1243dSDimitry Andric case RISCV::SRLI: { 3205bdd1243dSDimitry Andric unsigned ShAmt = User->getConstantOperandVal(1); 3206bdd1243dSDimitry Andric // If we are shifting right by less than Bits, and users don't demand any 3207bdd1243dSDimitry Andric // bits that were shifted into [Bits-1:0], then we can consider this as an 3208bdd1243dSDimitry Andric // N-Bit user. 3209bdd1243dSDimitry Andric if (Bits > ShAmt && hasAllNBitUsers(User, Bits - ShAmt, Depth + 1)) 3210bdd1243dSDimitry Andric break; 3211bdd1243dSDimitry Andric return false; 3212bdd1243dSDimitry Andric } 32131fd87a68SDimitry Andric case RISCV::SEXT_B: 3214bdd1243dSDimitry Andric case RISCV::PACKH: 321504eeddc0SDimitry Andric if (Bits < 8) 321604eeddc0SDimitry Andric return false; 321704eeddc0SDimitry Andric break; 32181fd87a68SDimitry Andric case RISCV::SEXT_H: 321981ad6265SDimitry Andric case RISCV::FMV_H_X: 32201fd87a68SDimitry Andric case RISCV::ZEXT_H_RV32: 32211fd87a68SDimitry Andric case RISCV::ZEXT_H_RV64: 3222bdd1243dSDimitry Andric case RISCV::PACKW: 322304eeddc0SDimitry Andric if (Bits < 16) 322404eeddc0SDimitry Andric return false; 322504eeddc0SDimitry Andric break; 3226bdd1243dSDimitry Andric case RISCV::PACK: 3227bdd1243dSDimitry Andric if (Bits < (Subtarget->getXLen() / 2)) 3228bdd1243dSDimitry Andric return false; 3229bdd1243dSDimitry Andric break; 32301fd87a68SDimitry Andric case RISCV::ADD_UW: 32311fd87a68SDimitry Andric case RISCV::SH1ADD_UW: 32321fd87a68SDimitry Andric case RISCV::SH2ADD_UW: 32331fd87a68SDimitry Andric case RISCV::SH3ADD_UW: 3234349cc55cSDimitry Andric // The first operand to add.uw/shXadd.uw is implicitly zero extended from 3235349cc55cSDimitry Andric // 32 bits. 3236349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 32) 3237349cc55cSDimitry Andric return false; 3238349cc55cSDimitry Andric break; 3239349cc55cSDimitry Andric case RISCV::SB: 3240349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 8) 3241349cc55cSDimitry Andric return false; 3242349cc55cSDimitry Andric break; 3243349cc55cSDimitry Andric case RISCV::SH: 3244349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 16) 3245349cc55cSDimitry Andric return false; 3246349cc55cSDimitry Andric break; 3247349cc55cSDimitry Andric case RISCV::SW: 3248349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 32) 3249349cc55cSDimitry Andric return false; 3250349cc55cSDimitry Andric break; 3251349cc55cSDimitry Andric } 3252349cc55cSDimitry Andric } 3253349cc55cSDimitry Andric 3254349cc55cSDimitry Andric return true; 3255349cc55cSDimitry Andric } 3256349cc55cSDimitry Andric 325706c3fb27SDimitry Andric // Select a constant that can be represented as (sign_extend(imm5) << imm2). 325806c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectSimm5Shl2(SDValue N, SDValue &Simm5, 325906c3fb27SDimitry Andric SDValue &Shl2) { 326006c3fb27SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(N)) { 326106c3fb27SDimitry Andric int64_t Offset = C->getSExtValue(); 326206c3fb27SDimitry Andric int64_t Shift; 326306c3fb27SDimitry Andric for (Shift = 0; Shift < 4; Shift++) 326406c3fb27SDimitry Andric if (isInt<5>(Offset >> Shift) && ((Offset % (1LL << Shift)) == 0)) 326506c3fb27SDimitry Andric break; 326606c3fb27SDimitry Andric 326706c3fb27SDimitry Andric // Constant cannot be encoded. 326806c3fb27SDimitry Andric if (Shift == 4) 326906c3fb27SDimitry Andric return false; 327006c3fb27SDimitry Andric 327106c3fb27SDimitry Andric EVT Ty = N->getValueType(0); 327206c3fb27SDimitry Andric Simm5 = CurDAG->getTargetConstant(Offset >> Shift, SDLoc(N), Ty); 327306c3fb27SDimitry Andric Shl2 = CurDAG->getTargetConstant(Shift, SDLoc(N), Ty); 327406c3fb27SDimitry Andric return true; 327506c3fb27SDimitry Andric } 327606c3fb27SDimitry Andric 327706c3fb27SDimitry Andric return false; 327806c3fb27SDimitry Andric } 327906c3fb27SDimitry Andric 3280fe6060f1SDimitry Andric // Select VL as a 5 bit immediate or a value that will become a register. This 3281fe6060f1SDimitry Andric // allows us to choose betwen VSETIVLI or VSETVLI later. 3282d409305fSDimitry Andric bool RISCVDAGToDAGISel::selectVLOp(SDValue N, SDValue &VL) { 3283d409305fSDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N); 328481ad6265SDimitry Andric if (C && isUInt<5>(C->getZExtValue())) { 3285fe6060f1SDimitry Andric VL = CurDAG->getTargetConstant(C->getZExtValue(), SDLoc(N), 3286fe6060f1SDimitry Andric N->getValueType(0)); 328706c3fb27SDimitry Andric } else if (C && C->isAllOnes()) { 328881ad6265SDimitry Andric // Treat all ones as VLMax. 328981ad6265SDimitry Andric VL = CurDAG->getTargetConstant(RISCV::VLMaxSentinel, SDLoc(N), 329081ad6265SDimitry Andric N->getValueType(0)); 329181ad6265SDimitry Andric } else if (isa<RegisterSDNode>(N) && 329281ad6265SDimitry Andric cast<RegisterSDNode>(N)->getReg() == RISCV::X0) { 329381ad6265SDimitry Andric // All our VL operands use an operand that allows GPRNoX0 or an immediate 329481ad6265SDimitry Andric // as the register class. Convert X0 to a special immediate to pass the 329581ad6265SDimitry Andric // MachineVerifier. This is recognized specially by the vsetvli insertion 329681ad6265SDimitry Andric // pass. 329781ad6265SDimitry Andric VL = CurDAG->getTargetConstant(RISCV::VLMaxSentinel, SDLoc(N), 329881ad6265SDimitry Andric N->getValueType(0)); 329981ad6265SDimitry Andric } else { 3300d409305fSDimitry Andric VL = N; 330181ad6265SDimitry Andric } 3302d409305fSDimitry Andric 3303d409305fSDimitry Andric return true; 3304d409305fSDimitry Andric } 3305d409305fSDimitry Andric 33065f757f3fSDimitry Andric static SDValue findVSplat(SDValue N) { 33075f757f3fSDimitry Andric if (N.getOpcode() == ISD::INSERT_SUBVECTOR) { 33085f757f3fSDimitry Andric if (!N.getOperand(0).isUndef()) 33095f757f3fSDimitry Andric return SDValue(); 33105f757f3fSDimitry Andric N = N.getOperand(1); 33115f757f3fSDimitry Andric } 33125f757f3fSDimitry Andric SDValue Splat = N; 33135f757f3fSDimitry Andric if ((Splat.getOpcode() != RISCVISD::VMV_V_X_VL && 33145f757f3fSDimitry Andric Splat.getOpcode() != RISCVISD::VMV_S_X_VL) || 33155f757f3fSDimitry Andric !Splat.getOperand(0).isUndef()) 33165f757f3fSDimitry Andric return SDValue(); 33175f757f3fSDimitry Andric assert(Splat.getNumOperands() == 3 && "Unexpected number of operands"); 33185f757f3fSDimitry Andric return Splat; 33195f757f3fSDimitry Andric } 33205f757f3fSDimitry Andric 3321e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::selectVSplat(SDValue N, SDValue &SplatVal) { 33225f757f3fSDimitry Andric SDValue Splat = findVSplat(N); 33235f757f3fSDimitry Andric if (!Splat) 3324e8d8bef9SDimitry Andric return false; 33255f757f3fSDimitry Andric 33265f757f3fSDimitry Andric SplatVal = Splat.getOperand(1); 3327979e22ffSDimitry Andric return true; 3328979e22ffSDimitry Andric } 3329e8d8bef9SDimitry Andric 33305f757f3fSDimitry Andric static bool selectVSplatImmHelper(SDValue N, SDValue &SplatVal, 3331fe6060f1SDimitry Andric SelectionDAG &DAG, 3332fe6060f1SDimitry Andric const RISCVSubtarget &Subtarget, 33335f757f3fSDimitry Andric std::function<bool(int64_t)> ValidateImm) { 33345f757f3fSDimitry Andric SDValue Splat = findVSplat(N); 33355f757f3fSDimitry Andric if (!Splat || !isa<ConstantSDNode>(Splat.getOperand(1))) 3336979e22ffSDimitry Andric return false; 3337e8d8bef9SDimitry Andric 33385f757f3fSDimitry Andric const unsigned SplatEltSize = Splat.getScalarValueSizeInBits(); 33395f757f3fSDimitry Andric assert(Subtarget.getXLenVT() == Splat.getOperand(1).getSimpleValueType() && 33405f757f3fSDimitry Andric "Unexpected splat operand type"); 3341e8d8bef9SDimitry Andric 334281ad6265SDimitry Andric // The semantics of RISCVISD::VMV_V_X_VL is that when the operand 334381ad6265SDimitry Andric // type is wider than the resulting vector element type: an implicit 334481ad6265SDimitry Andric // truncation first takes place. Therefore, perform a manual 334581ad6265SDimitry Andric // truncation/sign-extension in order to ignore any truncated bits and catch 334681ad6265SDimitry Andric // any zero-extended immediate. 3347e8d8bef9SDimitry Andric // For example, we wish to match (i8 -1) -> (XLenVT 255) as a simm5 by first 3348e8d8bef9SDimitry Andric // sign-extending to (XLenVT -1). 33495f757f3fSDimitry Andric APInt SplatConst = Splat.getConstantOperandAPInt(1).sextOrTrunc(SplatEltSize); 33505f757f3fSDimitry Andric 33515f757f3fSDimitry Andric int64_t SplatImm = SplatConst.getSExtValue(); 3352979e22ffSDimitry Andric 3353fe6060f1SDimitry Andric if (!ValidateImm(SplatImm)) 3354e8d8bef9SDimitry Andric return false; 3355979e22ffSDimitry Andric 33565f757f3fSDimitry Andric SplatVal = DAG.getTargetConstant(SplatImm, SDLoc(N), Subtarget.getXLenVT()); 3357979e22ffSDimitry Andric return true; 3358979e22ffSDimitry Andric } 3359e8d8bef9SDimitry Andric 3360fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5(SDValue N, SDValue &SplatVal) { 33615f757f3fSDimitry Andric return selectVSplatImmHelper(N, SplatVal, *CurDAG, *Subtarget, 3362fe6060f1SDimitry Andric [](int64_t Imm) { return isInt<5>(Imm); }); 3363fe6060f1SDimitry Andric } 3364fe6060f1SDimitry Andric 3365fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5Plus1(SDValue N, SDValue &SplatVal) { 33665f757f3fSDimitry Andric return selectVSplatImmHelper( 3367fe6060f1SDimitry Andric N, SplatVal, *CurDAG, *Subtarget, 3368fe6060f1SDimitry Andric [](int64_t Imm) { return (isInt<5>(Imm) && Imm != -16) || Imm == 16; }); 3369fe6060f1SDimitry Andric } 3370fe6060f1SDimitry Andric 3371fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5Plus1NonZero(SDValue N, 3372fe6060f1SDimitry Andric SDValue &SplatVal) { 33735f757f3fSDimitry Andric return selectVSplatImmHelper( 3374fe6060f1SDimitry Andric N, SplatVal, *CurDAG, *Subtarget, [](int64_t Imm) { 3375fe6060f1SDimitry Andric return Imm != 0 && ((isInt<5>(Imm) && Imm != -16) || Imm == 16); 3376fe6060f1SDimitry Andric }); 3377fe6060f1SDimitry Andric } 3378fe6060f1SDimitry Andric 337906c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatUimm(SDValue N, unsigned Bits, 338006c3fb27SDimitry Andric SDValue &SplatVal) { 33815f757f3fSDimitry Andric return selectVSplatImmHelper( 33825f757f3fSDimitry Andric N, SplatVal, *CurDAG, *Subtarget, 33835f757f3fSDimitry Andric [Bits](int64_t Imm) { return isUIntN(Bits, Imm); }); 3384979e22ffSDimitry Andric } 3385979e22ffSDimitry Andric 33865f757f3fSDimitry Andric bool RISCVDAGToDAGISel::selectLow8BitsVSplat(SDValue N, SDValue &SplatVal) { 3387*0fca6ea1SDimitry Andric auto IsExtOrTrunc = [](SDValue N) { 3388*0fca6ea1SDimitry Andric switch (N->getOpcode()) { 3389*0fca6ea1SDimitry Andric case ISD::SIGN_EXTEND: 3390*0fca6ea1SDimitry Andric case ISD::ZERO_EXTEND: 3391*0fca6ea1SDimitry Andric // There's no passthru on these _VL nodes so any VL/mask is ok, since any 3392*0fca6ea1SDimitry Andric // inactive elements will be undef. 3393*0fca6ea1SDimitry Andric case RISCVISD::TRUNCATE_VECTOR_VL: 3394*0fca6ea1SDimitry Andric case RISCVISD::VSEXT_VL: 3395*0fca6ea1SDimitry Andric case RISCVISD::VZEXT_VL: 3396*0fca6ea1SDimitry Andric return true; 3397*0fca6ea1SDimitry Andric default: 33985f757f3fSDimitry Andric return false; 3399*0fca6ea1SDimitry Andric } 34005f757f3fSDimitry Andric }; 34015f757f3fSDimitry Andric 3402*0fca6ea1SDimitry Andric // We can have multiple nested nodes, so unravel them all if needed. 3403*0fca6ea1SDimitry Andric while (IsExtOrTrunc(N)) { 3404*0fca6ea1SDimitry Andric if (!N.hasOneUse() || N.getScalarValueSizeInBits() < 8) 340506c3fb27SDimitry Andric return false; 340606c3fb27SDimitry Andric N = N->getOperand(0); 340706c3fb27SDimitry Andric } 34085f757f3fSDimitry Andric 340906c3fb27SDimitry Andric return selectVSplat(N, SplatVal); 341006c3fb27SDimitry Andric } 341106c3fb27SDimitry Andric 341206c3fb27SDimitry Andric bool RISCVDAGToDAGISel::selectFPImm(SDValue N, SDValue &Imm) { 341306c3fb27SDimitry Andric ConstantFPSDNode *CFP = dyn_cast<ConstantFPSDNode>(N.getNode()); 341406c3fb27SDimitry Andric if (!CFP) 341506c3fb27SDimitry Andric return false; 341606c3fb27SDimitry Andric const APFloat &APF = CFP->getValueAPF(); 341706c3fb27SDimitry Andric // td can handle +0.0 already. 341806c3fb27SDimitry Andric if (APF.isPosZero()) 341906c3fb27SDimitry Andric return false; 342006c3fb27SDimitry Andric 342106c3fb27SDimitry Andric MVT VT = CFP->getSimpleValueType(0); 342206c3fb27SDimitry Andric 34235f757f3fSDimitry Andric // Even if this FPImm requires an additional FNEG (i.e. the second element of 34245f757f3fSDimitry Andric // the returned pair is true) we still prefer FLI + FNEG over immediate 34255f757f3fSDimitry Andric // materialization as the latter might generate a longer instruction sequence. 34265f757f3fSDimitry Andric if (static_cast<const RISCVTargetLowering *>(TLI) 34275f757f3fSDimitry Andric ->getLegalZfaFPImm(APF, VT) 34285f757f3fSDimitry Andric .first >= 0) 342906c3fb27SDimitry Andric return false; 343006c3fb27SDimitry Andric 343106c3fb27SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 343206c3fb27SDimitry Andric if (VT == MVT::f64 && !Subtarget->is64Bit()) { 343306c3fb27SDimitry Andric assert(APF.isNegZero() && "Unexpected constant."); 343406c3fb27SDimitry Andric return false; 343506c3fb27SDimitry Andric } 343606c3fb27SDimitry Andric SDLoc DL(N); 343706c3fb27SDimitry Andric Imm = selectImm(CurDAG, DL, XLenVT, APF.bitcastToAPInt().getSExtValue(), 343806c3fb27SDimitry Andric *Subtarget); 343906c3fb27SDimitry Andric return true; 344006c3fb27SDimitry Andric } 344106c3fb27SDimitry Andric 3442fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectRVVSimm5(SDValue N, unsigned Width, 3443fe6060f1SDimitry Andric SDValue &Imm) { 3444fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(N)) { 3445fe6060f1SDimitry Andric int64_t ImmVal = SignExtend64(C->getSExtValue(), Width); 3446fe6060f1SDimitry Andric 3447fe6060f1SDimitry Andric if (!isInt<5>(ImmVal)) 3448fe6060f1SDimitry Andric return false; 3449fe6060f1SDimitry Andric 3450fe6060f1SDimitry Andric Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), Subtarget->getXLenVT()); 3451fe6060f1SDimitry Andric return true; 3452fe6060f1SDimitry Andric } 3453fe6060f1SDimitry Andric 3454fe6060f1SDimitry Andric return false; 3455fe6060f1SDimitry Andric } 3456fe6060f1SDimitry Andric 3457349cc55cSDimitry Andric // Try to remove sext.w if the input is a W instruction or can be made into 3458349cc55cSDimitry Andric // a W instruction cheaply. 3459349cc55cSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeSExtW(SDNode *N) { 3460349cc55cSDimitry Andric // Look for the sext.w pattern, addiw rd, rs1, 0. 3461349cc55cSDimitry Andric if (N->getMachineOpcode() != RISCV::ADDIW || 3462349cc55cSDimitry Andric !isNullConstant(N->getOperand(1))) 3463349cc55cSDimitry Andric return false; 3464349cc55cSDimitry Andric 3465349cc55cSDimitry Andric SDValue N0 = N->getOperand(0); 3466349cc55cSDimitry Andric if (!N0.isMachineOpcode()) 3467349cc55cSDimitry Andric return false; 3468349cc55cSDimitry Andric 3469349cc55cSDimitry Andric switch (N0.getMachineOpcode()) { 3470349cc55cSDimitry Andric default: 3471349cc55cSDimitry Andric break; 3472349cc55cSDimitry Andric case RISCV::ADD: 3473349cc55cSDimitry Andric case RISCV::ADDI: 3474349cc55cSDimitry Andric case RISCV::SUB: 3475349cc55cSDimitry Andric case RISCV::MUL: 3476349cc55cSDimitry Andric case RISCV::SLLI: { 3477349cc55cSDimitry Andric // Convert sext.w+add/sub/mul to their W instructions. This will create 3478349cc55cSDimitry Andric // a new independent instruction. This improves latency. 3479349cc55cSDimitry Andric unsigned Opc; 3480349cc55cSDimitry Andric switch (N0.getMachineOpcode()) { 3481349cc55cSDimitry Andric default: 3482349cc55cSDimitry Andric llvm_unreachable("Unexpected opcode!"); 3483349cc55cSDimitry Andric case RISCV::ADD: Opc = RISCV::ADDW; break; 3484349cc55cSDimitry Andric case RISCV::ADDI: Opc = RISCV::ADDIW; break; 3485349cc55cSDimitry Andric case RISCV::SUB: Opc = RISCV::SUBW; break; 3486349cc55cSDimitry Andric case RISCV::MUL: Opc = RISCV::MULW; break; 3487349cc55cSDimitry Andric case RISCV::SLLI: Opc = RISCV::SLLIW; break; 3488349cc55cSDimitry Andric } 3489349cc55cSDimitry Andric 3490349cc55cSDimitry Andric SDValue N00 = N0.getOperand(0); 3491349cc55cSDimitry Andric SDValue N01 = N0.getOperand(1); 3492349cc55cSDimitry Andric 3493349cc55cSDimitry Andric // Shift amount needs to be uimm5. 3494349cc55cSDimitry Andric if (N0.getMachineOpcode() == RISCV::SLLI && 3495349cc55cSDimitry Andric !isUInt<5>(cast<ConstantSDNode>(N01)->getSExtValue())) 3496349cc55cSDimitry Andric break; 3497349cc55cSDimitry Andric 3498349cc55cSDimitry Andric SDNode *Result = 3499349cc55cSDimitry Andric CurDAG->getMachineNode(Opc, SDLoc(N), N->getValueType(0), 3500349cc55cSDimitry Andric N00, N01); 3501349cc55cSDimitry Andric ReplaceUses(N, Result); 3502349cc55cSDimitry Andric return true; 3503349cc55cSDimitry Andric } 3504349cc55cSDimitry Andric case RISCV::ADDW: 3505349cc55cSDimitry Andric case RISCV::ADDIW: 3506349cc55cSDimitry Andric case RISCV::SUBW: 3507349cc55cSDimitry Andric case RISCV::MULW: 3508349cc55cSDimitry Andric case RISCV::SLLIW: 3509bdd1243dSDimitry Andric case RISCV::PACKW: 351006c3fb27SDimitry Andric case RISCV::TH_MULAW: 351106c3fb27SDimitry Andric case RISCV::TH_MULAH: 351206c3fb27SDimitry Andric case RISCV::TH_MULSW: 351306c3fb27SDimitry Andric case RISCV::TH_MULSH: 35145f757f3fSDimitry Andric if (N0.getValueType() == MVT::i32) 35155f757f3fSDimitry Andric break; 35165f757f3fSDimitry Andric 3517349cc55cSDimitry Andric // Result is already sign extended just remove the sext.w. 3518349cc55cSDimitry Andric // NOTE: We only handle the nodes that are selected with hasAllWUsers. 3519349cc55cSDimitry Andric ReplaceUses(N, N0.getNode()); 3520349cc55cSDimitry Andric return true; 3521349cc55cSDimitry Andric } 3522349cc55cSDimitry Andric 3523349cc55cSDimitry Andric return false; 35240b57cec5SDimitry Andric } 35250b57cec5SDimitry Andric 3526*0fca6ea1SDimitry Andric // After ISel, a vector pseudo's mask will be copied to V0 via a CopyToReg 3527*0fca6ea1SDimitry Andric // that's glued to the pseudo. This tries to look up the value that was copied 3528*0fca6ea1SDimitry Andric // to V0. 3529*0fca6ea1SDimitry Andric static SDValue getMaskSetter(SDValue MaskOp, SDValue GlueOp) { 353081ad6265SDimitry Andric // Check that we're using V0 as a mask register. 353106c3fb27SDimitry Andric if (!isa<RegisterSDNode>(MaskOp) || 353206c3fb27SDimitry Andric cast<RegisterSDNode>(MaskOp)->getReg() != RISCV::V0) 3533*0fca6ea1SDimitry Andric return SDValue(); 353481ad6265SDimitry Andric 353581ad6265SDimitry Andric // The glued user defines V0. 353606c3fb27SDimitry Andric const auto *Glued = GlueOp.getNode(); 353781ad6265SDimitry Andric 353881ad6265SDimitry Andric if (!Glued || Glued->getOpcode() != ISD::CopyToReg) 3539*0fca6ea1SDimitry Andric return SDValue(); 354081ad6265SDimitry Andric 354181ad6265SDimitry Andric // Check that we're defining V0 as a mask register. 354281ad6265SDimitry Andric if (!isa<RegisterSDNode>(Glued->getOperand(1)) || 354381ad6265SDimitry Andric cast<RegisterSDNode>(Glued->getOperand(1))->getReg() != RISCV::V0) 3544*0fca6ea1SDimitry Andric return SDValue(); 354581ad6265SDimitry Andric 354681ad6265SDimitry Andric SDValue MaskSetter = Glued->getOperand(2); 354781ad6265SDimitry Andric 35485f757f3fSDimitry Andric // Sometimes the VMSET is wrapped in a COPY_TO_REGCLASS, e.g. if the mask came 35495f757f3fSDimitry Andric // from an extract_subvector or insert_subvector. 35505f757f3fSDimitry Andric if (MaskSetter->isMachineOpcode() && 35515f757f3fSDimitry Andric MaskSetter->getMachineOpcode() == RISCV::COPY_TO_REGCLASS) 35525f757f3fSDimitry Andric MaskSetter = MaskSetter->getOperand(0); 35535f757f3fSDimitry Andric 3554*0fca6ea1SDimitry Andric return MaskSetter; 3555*0fca6ea1SDimitry Andric } 3556*0fca6ea1SDimitry Andric 3557*0fca6ea1SDimitry Andric static bool usesAllOnesMask(SDValue MaskOp, SDValue GlueOp) { 3558*0fca6ea1SDimitry Andric // Check the instruction defining V0; it needs to be a VMSET pseudo. 3559*0fca6ea1SDimitry Andric SDValue MaskSetter = getMaskSetter(MaskOp, GlueOp); 3560*0fca6ea1SDimitry Andric if (!MaskSetter) 3561*0fca6ea1SDimitry Andric return false; 3562*0fca6ea1SDimitry Andric 356381ad6265SDimitry Andric const auto IsVMSet = [](unsigned Opc) { 356481ad6265SDimitry Andric return Opc == RISCV::PseudoVMSET_M_B1 || Opc == RISCV::PseudoVMSET_M_B16 || 356581ad6265SDimitry Andric Opc == RISCV::PseudoVMSET_M_B2 || Opc == RISCV::PseudoVMSET_M_B32 || 356681ad6265SDimitry Andric Opc == RISCV::PseudoVMSET_M_B4 || Opc == RISCV::PseudoVMSET_M_B64 || 356781ad6265SDimitry Andric Opc == RISCV::PseudoVMSET_M_B8; 356881ad6265SDimitry Andric }; 356981ad6265SDimitry Andric 357081ad6265SDimitry Andric // TODO: Check that the VMSET is the expected bitwidth? The pseudo has 357181ad6265SDimitry Andric // undefined behaviour if it's the wrong bitwidth, so we could choose to 357281ad6265SDimitry Andric // assume that it's all-ones? Same applies to its VL. 3573bdd1243dSDimitry Andric return MaskSetter->isMachineOpcode() && 3574bdd1243dSDimitry Andric IsVMSet(MaskSetter.getMachineOpcode()); 3575bdd1243dSDimitry Andric } 3576bdd1243dSDimitry Andric 357706c3fb27SDimitry Andric // Return true if we can make sure mask of N is all-ones mask. 357806c3fb27SDimitry Andric static bool usesAllOnesMask(SDNode *N, unsigned MaskOpIdx) { 357906c3fb27SDimitry Andric return usesAllOnesMask(N->getOperand(MaskOpIdx), 358006c3fb27SDimitry Andric N->getOperand(N->getNumOperands() - 1)); 358106c3fb27SDimitry Andric } 358206c3fb27SDimitry Andric 358306c3fb27SDimitry Andric static bool isImplicitDef(SDValue V) { 3584*0fca6ea1SDimitry Andric if (!V.isMachineOpcode()) 3585*0fca6ea1SDimitry Andric return false; 3586*0fca6ea1SDimitry Andric if (V.getMachineOpcode() == TargetOpcode::REG_SEQUENCE) { 3587*0fca6ea1SDimitry Andric for (unsigned I = 1; I < V.getNumOperands(); I += 2) 3588*0fca6ea1SDimitry Andric if (!isImplicitDef(V.getOperand(I))) 3589*0fca6ea1SDimitry Andric return false; 3590*0fca6ea1SDimitry Andric return true; 3591*0fca6ea1SDimitry Andric } 3592*0fca6ea1SDimitry Andric return V.getMachineOpcode() == TargetOpcode::IMPLICIT_DEF; 359306c3fb27SDimitry Andric } 359406c3fb27SDimitry Andric 3595bdd1243dSDimitry Andric // Optimize masked RVV pseudo instructions with a known all-ones mask to their 3596bdd1243dSDimitry Andric // corresponding "unmasked" pseudo versions. The mask we're interested in will 3597bdd1243dSDimitry Andric // take the form of a V0 physical register operand, with a glued 3598bdd1243dSDimitry Andric // register-setting instruction. 35995f757f3fSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeMaskedRVV(MachineSDNode *N) { 3600bdd1243dSDimitry Andric const RISCV::RISCVMaskedPseudoInfo *I = 3601bdd1243dSDimitry Andric RISCV::getMaskedPseudoInfo(N->getMachineOpcode()); 3602bdd1243dSDimitry Andric if (!I) 3603bdd1243dSDimitry Andric return false; 3604bdd1243dSDimitry Andric 3605bdd1243dSDimitry Andric unsigned MaskOpIdx = I->MaskOpIdx; 3606bdd1243dSDimitry Andric if (!usesAllOnesMask(N, MaskOpIdx)) 360781ad6265SDimitry Andric return false; 360881ad6265SDimitry Andric 360906c3fb27SDimitry Andric // There are two classes of pseudos in the table - compares and 361006c3fb27SDimitry Andric // everything else. See the comment on RISCVMaskedPseudo for details. 361106c3fb27SDimitry Andric const unsigned Opc = I->UnmaskedPseudo; 361206c3fb27SDimitry Andric const MCInstrDesc &MCID = TII->get(Opc); 361306c3fb27SDimitry Andric const bool UseTUPseudo = RISCVII::hasVecPolicyOp(MCID.TSFlags); 361406c3fb27SDimitry Andric #ifndef NDEBUG 361506c3fb27SDimitry Andric const MCInstrDesc &MaskedMCID = TII->get(N->getMachineOpcode()); 361606c3fb27SDimitry Andric assert(RISCVII::hasVecPolicyOp(MaskedMCID.TSFlags) == 361706c3fb27SDimitry Andric RISCVII::hasVecPolicyOp(MCID.TSFlags) && 361806c3fb27SDimitry Andric "Masked and unmasked pseudos are inconsistent"); 361906c3fb27SDimitry Andric const bool HasTiedDest = RISCVII::isFirstDefTiedToFirstUse(MCID); 362006c3fb27SDimitry Andric assert(UseTUPseudo == HasTiedDest && "Unexpected pseudo structure"); 362106c3fb27SDimitry Andric #endif 362281ad6265SDimitry Andric 362381ad6265SDimitry Andric SmallVector<SDValue, 8> Ops; 362406c3fb27SDimitry Andric // Skip the merge operand at index 0 if !UseTUPseudo. 362506c3fb27SDimitry Andric for (unsigned I = !UseTUPseudo, E = N->getNumOperands(); I != E; I++) { 362606c3fb27SDimitry Andric // Skip the mask, and the Glue. 362781ad6265SDimitry Andric SDValue Op = N->getOperand(I); 362806c3fb27SDimitry Andric if (I == MaskOpIdx || Op.getValueType() == MVT::Glue) 362981ad6265SDimitry Andric continue; 363081ad6265SDimitry Andric Ops.push_back(Op); 363181ad6265SDimitry Andric } 363281ad6265SDimitry Andric 363381ad6265SDimitry Andric // Transitively apply any node glued to our new node. 3634bdd1243dSDimitry Andric const auto *Glued = N->getGluedNode(); 363581ad6265SDimitry Andric if (auto *TGlued = Glued->getGluedNode()) 363681ad6265SDimitry Andric Ops.push_back(SDValue(TGlued, TGlued->getNumValues() - 1)); 363781ad6265SDimitry Andric 36385f757f3fSDimitry Andric MachineSDNode *Result = 36395f757f3fSDimitry Andric CurDAG->getMachineNode(Opc, SDLoc(N), N->getVTList(), Ops); 36405f757f3fSDimitry Andric 36415f757f3fSDimitry Andric if (!N->memoperands_empty()) 36425f757f3fSDimitry Andric CurDAG->setNodeMemRefs(Result, N->memoperands()); 36435f757f3fSDimitry Andric 3644bdd1243dSDimitry Andric Result->setFlags(N->getFlags()); 364581ad6265SDimitry Andric ReplaceUses(N, Result); 364681ad6265SDimitry Andric 364781ad6265SDimitry Andric return true; 364881ad6265SDimitry Andric } 364981ad6265SDimitry Andric 365006c3fb27SDimitry Andric static bool IsVMerge(SDNode *N) { 36515f757f3fSDimitry Andric return RISCV::getRVVMCOpcode(N->getMachineOpcode()) == RISCV::VMERGE_VVM; 365206c3fb27SDimitry Andric } 3653bdd1243dSDimitry Andric 365406c3fb27SDimitry Andric static bool IsVMv(SDNode *N) { 36555f757f3fSDimitry Andric return RISCV::getRVVMCOpcode(N->getMachineOpcode()) == RISCV::VMV_V_V; 365606c3fb27SDimitry Andric } 365706c3fb27SDimitry Andric 365806c3fb27SDimitry Andric static unsigned GetVMSetForLMul(RISCVII::VLMUL LMUL) { 365906c3fb27SDimitry Andric switch (LMUL) { 366006c3fb27SDimitry Andric case RISCVII::LMUL_F8: 366106c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B1; 366206c3fb27SDimitry Andric case RISCVII::LMUL_F4: 366306c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B2; 366406c3fb27SDimitry Andric case RISCVII::LMUL_F2: 366506c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B4; 366606c3fb27SDimitry Andric case RISCVII::LMUL_1: 366706c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B8; 366806c3fb27SDimitry Andric case RISCVII::LMUL_2: 366906c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B16; 367006c3fb27SDimitry Andric case RISCVII::LMUL_4: 367106c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B32; 367206c3fb27SDimitry Andric case RISCVII::LMUL_8: 367306c3fb27SDimitry Andric return RISCV::PseudoVMSET_M_B64; 367406c3fb27SDimitry Andric case RISCVII::LMUL_RESERVED: 367506c3fb27SDimitry Andric llvm_unreachable("Unexpected LMUL"); 367606c3fb27SDimitry Andric } 367706c3fb27SDimitry Andric llvm_unreachable("Unknown VLMUL enum"); 367806c3fb27SDimitry Andric } 367906c3fb27SDimitry Andric 3680*0fca6ea1SDimitry Andric // Try to fold away VMERGE_VVM instructions into their true operands: 3681*0fca6ea1SDimitry Andric // 3682*0fca6ea1SDimitry Andric // %true = PseudoVADD_VV ... 3683*0fca6ea1SDimitry Andric // %x = PseudoVMERGE_VVM %false, %false, %true, %mask 3684*0fca6ea1SDimitry Andric // -> 3685*0fca6ea1SDimitry Andric // %x = PseudoVADD_VV_MASK %false, ..., %mask 3686*0fca6ea1SDimitry Andric // 3687*0fca6ea1SDimitry Andric // We can only fold if vmerge's merge operand, vmerge's false operand and 3688*0fca6ea1SDimitry Andric // %true's merge operand (if it has one) are the same. This is because we have 3689*0fca6ea1SDimitry Andric // to consolidate them into one merge operand in the result. 3690*0fca6ea1SDimitry Andric // 3691*0fca6ea1SDimitry Andric // If %true is masked, then we can use its mask instead of vmerge's if vmerge's 3692*0fca6ea1SDimitry Andric // mask is all ones. 3693*0fca6ea1SDimitry Andric // 3694*0fca6ea1SDimitry Andric // We can also fold a VMV_V_V into its true operand, since it is equivalent to a 3695*0fca6ea1SDimitry Andric // VMERGE_VVM with an all ones mask. 3696*0fca6ea1SDimitry Andric // 3697*0fca6ea1SDimitry Andric // The resulting VL is the minimum of the two VLs. 3698*0fca6ea1SDimitry Andric // 3699*0fca6ea1SDimitry Andric // The resulting policy is the effective policy the vmerge would have had, 3700*0fca6ea1SDimitry Andric // i.e. whether or not it's merge operand was implicit-def. 370106c3fb27SDimitry Andric bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) { 370206c3fb27SDimitry Andric SDValue Merge, False, True, VL, Mask, Glue; 370306c3fb27SDimitry Andric // A vmv.v.v is equivalent to a vmerge with an all-ones mask. 370406c3fb27SDimitry Andric if (IsVMv(N)) { 370506c3fb27SDimitry Andric Merge = N->getOperand(0); 370606c3fb27SDimitry Andric False = N->getOperand(0); 370706c3fb27SDimitry Andric True = N->getOperand(1); 370806c3fb27SDimitry Andric VL = N->getOperand(2); 370906c3fb27SDimitry Andric // A vmv.v.v won't have a Mask or Glue, instead we'll construct an all-ones 371006c3fb27SDimitry Andric // mask later below. 371106c3fb27SDimitry Andric } else { 371206c3fb27SDimitry Andric assert(IsVMerge(N)); 371306c3fb27SDimitry Andric Merge = N->getOperand(0); 371406c3fb27SDimitry Andric False = N->getOperand(1); 371506c3fb27SDimitry Andric True = N->getOperand(2); 371606c3fb27SDimitry Andric Mask = N->getOperand(3); 371706c3fb27SDimitry Andric VL = N->getOperand(4); 371806c3fb27SDimitry Andric // We always have a glue node for the mask at v0. 371906c3fb27SDimitry Andric Glue = N->getOperand(N->getNumOperands() - 1); 372006c3fb27SDimitry Andric } 372106c3fb27SDimitry Andric assert(!Mask || cast<RegisterSDNode>(Mask)->getReg() == RISCV::V0); 372206c3fb27SDimitry Andric assert(!Glue || Glue.getValueType() == MVT::Glue); 372306c3fb27SDimitry Andric 372406c3fb27SDimitry Andric // We require that either merge and false are the same, or that merge 372506c3fb27SDimitry Andric // is undefined. 372606c3fb27SDimitry Andric if (Merge != False && !isImplicitDef(Merge)) 372706c3fb27SDimitry Andric return false; 3728bdd1243dSDimitry Andric 3729bdd1243dSDimitry Andric assert(True.getResNo() == 0 && 3730bdd1243dSDimitry Andric "Expect True is the first output of an instruction."); 3731bdd1243dSDimitry Andric 3732bdd1243dSDimitry Andric // Need N is the exactly one using True. 3733bdd1243dSDimitry Andric if (!True.hasOneUse()) 3734bdd1243dSDimitry Andric return false; 3735bdd1243dSDimitry Andric 3736bdd1243dSDimitry Andric if (!True.isMachineOpcode()) 3737bdd1243dSDimitry Andric return false; 3738bdd1243dSDimitry Andric 3739bdd1243dSDimitry Andric unsigned TrueOpc = True.getMachineOpcode(); 374006c3fb27SDimitry Andric const MCInstrDesc &TrueMCID = TII->get(TrueOpc); 374106c3fb27SDimitry Andric uint64_t TrueTSFlags = TrueMCID.TSFlags; 374206c3fb27SDimitry Andric bool HasTiedDest = RISCVII::isFirstDefTiedToFirstUse(TrueMCID); 3743bdd1243dSDimitry Andric 374406c3fb27SDimitry Andric bool IsMasked = false; 3745bdd1243dSDimitry Andric const RISCV::RISCVMaskedPseudoInfo *Info = 374606c3fb27SDimitry Andric RISCV::lookupMaskedIntrinsicByUnmasked(TrueOpc); 374706c3fb27SDimitry Andric if (!Info && HasTiedDest) { 374806c3fb27SDimitry Andric Info = RISCV::getMaskedPseudoInfo(TrueOpc); 374906c3fb27SDimitry Andric IsMasked = true; 375006c3fb27SDimitry Andric } 3751*0fca6ea1SDimitry Andric assert(!(IsMasked && !HasTiedDest) && "Expected tied dest"); 3752bdd1243dSDimitry Andric 3753bdd1243dSDimitry Andric if (!Info) 3754bdd1243dSDimitry Andric return false; 3755bdd1243dSDimitry Andric 3756*0fca6ea1SDimitry Andric // If True has a merge operand then it needs to be the same as vmerge's False, 3757*0fca6ea1SDimitry Andric // since False will be used for the result's merge operand. 375806c3fb27SDimitry Andric if (HasTiedDest && !isImplicitDef(True->getOperand(0))) { 375906c3fb27SDimitry Andric SDValue MergeOpTrue = True->getOperand(0); 376006c3fb27SDimitry Andric if (False != MergeOpTrue) 376106c3fb27SDimitry Andric return false; 376206c3fb27SDimitry Andric } 376306c3fb27SDimitry Andric 3764*0fca6ea1SDimitry Andric // If True is masked then the vmerge must have either the same mask or an all 3765*0fca6ea1SDimitry Andric // 1s mask, since we're going to keep the mask from True. 3766*0fca6ea1SDimitry Andric if (IsMasked && Mask) { 376706c3fb27SDimitry Andric // FIXME: Support mask agnostic True instruction which would have an 376806c3fb27SDimitry Andric // undef merge operand. 3769*0fca6ea1SDimitry Andric SDValue TrueMask = 3770*0fca6ea1SDimitry Andric getMaskSetter(True->getOperand(Info->MaskOpIdx), 3771*0fca6ea1SDimitry Andric True->getOperand(True->getNumOperands() - 1)); 3772*0fca6ea1SDimitry Andric assert(TrueMask); 3773*0fca6ea1SDimitry Andric if (!usesAllOnesMask(Mask, Glue) && getMaskSetter(Mask, Glue) != TrueMask) 377406c3fb27SDimitry Andric return false; 377506c3fb27SDimitry Andric } 377606c3fb27SDimitry Andric 377706c3fb27SDimitry Andric // Skip if True has side effect. 377806c3fb27SDimitry Andric if (TII->get(TrueOpc).hasUnmodeledSideEffects()) 377906c3fb27SDimitry Andric return false; 378006c3fb27SDimitry Andric 378106c3fb27SDimitry Andric // The last operand of a masked instruction may be glued. 378206c3fb27SDimitry Andric bool HasGlueOp = True->getGluedNode() != nullptr; 378306c3fb27SDimitry Andric 378406c3fb27SDimitry Andric // The chain operand may exist either before the glued operands or in the last 378506c3fb27SDimitry Andric // position. 378606c3fb27SDimitry Andric unsigned TrueChainOpIdx = True.getNumOperands() - HasGlueOp - 1; 3787bdd1243dSDimitry Andric bool HasChainOp = 378806c3fb27SDimitry Andric True.getOperand(TrueChainOpIdx).getValueType() == MVT::Other; 3789bdd1243dSDimitry Andric 3790bdd1243dSDimitry Andric if (HasChainOp) { 3791bdd1243dSDimitry Andric // Avoid creating cycles in the DAG. We must ensure that none of the other 3792bdd1243dSDimitry Andric // operands depend on True through it's Chain. 3793bdd1243dSDimitry Andric SmallVector<const SDNode *, 4> LoopWorklist; 3794bdd1243dSDimitry Andric SmallPtrSet<const SDNode *, 16> Visited; 3795bdd1243dSDimitry Andric LoopWorklist.push_back(False.getNode()); 379606c3fb27SDimitry Andric if (Mask) 3797bdd1243dSDimitry Andric LoopWorklist.push_back(Mask.getNode()); 3798bdd1243dSDimitry Andric LoopWorklist.push_back(VL.getNode()); 379906c3fb27SDimitry Andric if (Glue) 380006c3fb27SDimitry Andric LoopWorklist.push_back(Glue.getNode()); 3801bdd1243dSDimitry Andric if (SDNode::hasPredecessorHelper(True.getNode(), Visited, LoopWorklist)) 3802bdd1243dSDimitry Andric return false; 3803bdd1243dSDimitry Andric } 3804bdd1243dSDimitry Andric 380506c3fb27SDimitry Andric // The vector policy operand may be present for masked intrinsics 380606c3fb27SDimitry Andric bool HasVecPolicyOp = RISCVII::hasVecPolicyOp(TrueTSFlags); 380706c3fb27SDimitry Andric unsigned TrueVLIndex = 380806c3fb27SDimitry Andric True.getNumOperands() - HasVecPolicyOp - HasChainOp - HasGlueOp - 2; 3809bdd1243dSDimitry Andric SDValue TrueVL = True.getOperand(TrueVLIndex); 381006c3fb27SDimitry Andric SDValue SEW = True.getOperand(TrueVLIndex + 1); 3811bdd1243dSDimitry Andric 381206c3fb27SDimitry Andric auto GetMinVL = [](SDValue LHS, SDValue RHS) { 381306c3fb27SDimitry Andric if (LHS == RHS) 381406c3fb27SDimitry Andric return LHS; 381506c3fb27SDimitry Andric if (isAllOnesConstant(LHS)) 381606c3fb27SDimitry Andric return RHS; 381706c3fb27SDimitry Andric if (isAllOnesConstant(RHS)) 381806c3fb27SDimitry Andric return LHS; 381906c3fb27SDimitry Andric auto *CLHS = dyn_cast<ConstantSDNode>(LHS); 382006c3fb27SDimitry Andric auto *CRHS = dyn_cast<ConstantSDNode>(RHS); 382106c3fb27SDimitry Andric if (!CLHS || !CRHS) 382206c3fb27SDimitry Andric return SDValue(); 382306c3fb27SDimitry Andric return CLHS->getZExtValue() <= CRHS->getZExtValue() ? LHS : RHS; 3824bdd1243dSDimitry Andric }; 3825bdd1243dSDimitry Andric 382606c3fb27SDimitry Andric // Because N and True must have the same merge operand (or True's operand is 382706c3fb27SDimitry Andric // implicit_def), the "effective" body is the minimum of their VLs. 38288a4dda33SDimitry Andric SDValue OrigVL = VL; 382906c3fb27SDimitry Andric VL = GetMinVL(TrueVL, VL); 383006c3fb27SDimitry Andric if (!VL) 383106c3fb27SDimitry Andric return false; 383206c3fb27SDimitry Andric 3833*0fca6ea1SDimitry Andric // Some operations produce different elementwise results depending on the 3834*0fca6ea1SDimitry Andric // active elements, like viota.m or vredsum. This transformation is illegal 3835*0fca6ea1SDimitry Andric // for these if we change the active elements (i.e. mask or VL). 3836*0fca6ea1SDimitry Andric if (Info->ActiveElementsAffectResult) { 3837*0fca6ea1SDimitry Andric if (Mask && !usesAllOnesMask(Mask, Glue)) 3838*0fca6ea1SDimitry Andric return false; 3839*0fca6ea1SDimitry Andric if (TrueVL != VL) 3840*0fca6ea1SDimitry Andric return false; 3841*0fca6ea1SDimitry Andric } 3842*0fca6ea1SDimitry Andric 384306c3fb27SDimitry Andric // If we end up changing the VL or mask of True, then we need to make sure it 384406c3fb27SDimitry Andric // doesn't raise any observable fp exceptions, since changing the active 384506c3fb27SDimitry Andric // elements will affect how fflags is set. 384606c3fb27SDimitry Andric if (TrueVL != VL || !IsMasked) 384706c3fb27SDimitry Andric if (mayRaiseFPException(True.getNode()) && 384806c3fb27SDimitry Andric !True->getFlags().hasNoFPExcept()) 3849bdd1243dSDimitry Andric return false; 3850bdd1243dSDimitry Andric 3851bdd1243dSDimitry Andric SDLoc DL(N); 385206c3fb27SDimitry Andric 385306c3fb27SDimitry Andric // From the preconditions we checked above, we know the mask and thus glue 385406c3fb27SDimitry Andric // for the result node will be taken from True. 385506c3fb27SDimitry Andric if (IsMasked) { 385606c3fb27SDimitry Andric Mask = True->getOperand(Info->MaskOpIdx); 385706c3fb27SDimitry Andric Glue = True->getOperand(True->getNumOperands() - 1); 385806c3fb27SDimitry Andric assert(Glue.getValueType() == MVT::Glue); 385906c3fb27SDimitry Andric } 386006c3fb27SDimitry Andric // If we end up using the vmerge mask the vmerge is actually a vmv.v.v, create 386106c3fb27SDimitry Andric // an all-ones mask to use. 386206c3fb27SDimitry Andric else if (IsVMv(N)) { 386306c3fb27SDimitry Andric unsigned TSFlags = TII->get(N->getMachineOpcode()).TSFlags; 386406c3fb27SDimitry Andric unsigned VMSetOpc = GetVMSetForLMul(RISCVII::getLMul(TSFlags)); 386506c3fb27SDimitry Andric ElementCount EC = N->getValueType(0).getVectorElementCount(); 386606c3fb27SDimitry Andric MVT MaskVT = MVT::getVectorVT(MVT::i1, EC); 386706c3fb27SDimitry Andric 386806c3fb27SDimitry Andric SDValue AllOnesMask = 386906c3fb27SDimitry Andric SDValue(CurDAG->getMachineNode(VMSetOpc, DL, MaskVT, VL, SEW), 0); 387006c3fb27SDimitry Andric SDValue MaskCopy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, 387106c3fb27SDimitry Andric RISCV::V0, AllOnesMask, SDValue()); 387206c3fb27SDimitry Andric Mask = CurDAG->getRegister(RISCV::V0, MaskVT); 387306c3fb27SDimitry Andric Glue = MaskCopy.getValue(1); 387406c3fb27SDimitry Andric } 387506c3fb27SDimitry Andric 3876bdd1243dSDimitry Andric unsigned MaskedOpc = Info->MaskedPseudo; 387706c3fb27SDimitry Andric #ifndef NDEBUG 387806c3fb27SDimitry Andric const MCInstrDesc &MaskedMCID = TII->get(MaskedOpc); 387906c3fb27SDimitry Andric assert(RISCVII::hasVecPolicyOp(MaskedMCID.TSFlags) && 3880bdd1243dSDimitry Andric "Expected instructions with mask have policy operand."); 388106c3fb27SDimitry Andric assert(MaskedMCID.getOperandConstraint(MaskedMCID.getNumDefs(), 388206c3fb27SDimitry Andric MCOI::TIED_TO) == 0 && 388306c3fb27SDimitry Andric "Expected instructions with mask have a tied dest."); 388406c3fb27SDimitry Andric #endif 388506c3fb27SDimitry Andric 38868a4dda33SDimitry Andric // Use a tumu policy, relaxing it to tail agnostic provided that the merge 38878a4dda33SDimitry Andric // operand is undefined. 38888a4dda33SDimitry Andric // 38898a4dda33SDimitry Andric // However, if the VL became smaller than what the vmerge had originally, then 38908a4dda33SDimitry Andric // elements past VL that were previously in the vmerge's body will have moved 38918a4dda33SDimitry Andric // to the tail. In that case we always need to use tail undisturbed to 38928a4dda33SDimitry Andric // preserve them. 38938a4dda33SDimitry Andric bool MergeVLShrunk = VL != OrigVL; 38948a4dda33SDimitry Andric uint64_t Policy = (isImplicitDef(Merge) && !MergeVLShrunk) 38958a4dda33SDimitry Andric ? RISCVII::TAIL_AGNOSTIC 38968a4dda33SDimitry Andric : /*TUMU*/ 0; 389706c3fb27SDimitry Andric SDValue PolicyOp = 389806c3fb27SDimitry Andric CurDAG->getTargetConstant(Policy, DL, Subtarget->getXLenVT()); 389906c3fb27SDimitry Andric 3900bdd1243dSDimitry Andric 3901bdd1243dSDimitry Andric SmallVector<SDValue, 8> Ops; 3902bdd1243dSDimitry Andric Ops.push_back(False); 390306c3fb27SDimitry Andric 390406c3fb27SDimitry Andric const bool HasRoundingMode = RISCVII::hasRoundModeOp(TrueTSFlags); 390506c3fb27SDimitry Andric const unsigned NormalOpsEnd = TrueVLIndex - IsMasked - HasRoundingMode; 390606c3fb27SDimitry Andric assert(!IsMasked || NormalOpsEnd == Info->MaskOpIdx); 390706c3fb27SDimitry Andric Ops.append(True->op_begin() + HasTiedDest, True->op_begin() + NormalOpsEnd); 390806c3fb27SDimitry Andric 390906c3fb27SDimitry Andric Ops.push_back(Mask); 391006c3fb27SDimitry Andric 391106c3fb27SDimitry Andric // For unmasked "VOp" with rounding mode operand, that is interfaces like 391206c3fb27SDimitry Andric // (..., rm, vl) or (..., rm, vl, policy). 391306c3fb27SDimitry Andric // Its masked version is (..., vm, rm, vl, policy). 391406c3fb27SDimitry Andric // Check the rounding mode pseudo nodes under RISCVInstrInfoVPseudos.td 391506c3fb27SDimitry Andric if (HasRoundingMode) 391606c3fb27SDimitry Andric Ops.push_back(True->getOperand(TrueVLIndex - 1)); 391706c3fb27SDimitry Andric 391806c3fb27SDimitry Andric Ops.append({VL, SEW, PolicyOp}); 3919bdd1243dSDimitry Andric 3920bdd1243dSDimitry Andric // Result node should have chain operand of True. 3921bdd1243dSDimitry Andric if (HasChainOp) 392206c3fb27SDimitry Andric Ops.push_back(True.getOperand(TrueChainOpIdx)); 3923bdd1243dSDimitry Andric 392406c3fb27SDimitry Andric // Add the glue for the CopyToReg of mask->v0. 392506c3fb27SDimitry Andric Ops.push_back(Glue); 3926bdd1243dSDimitry Andric 39275f757f3fSDimitry Andric MachineSDNode *Result = 3928bdd1243dSDimitry Andric CurDAG->getMachineNode(MaskedOpc, DL, True->getVTList(), Ops); 3929bdd1243dSDimitry Andric Result->setFlags(True->getFlags()); 3930bdd1243dSDimitry Andric 39315f757f3fSDimitry Andric if (!cast<MachineSDNode>(True)->memoperands_empty()) 39325f757f3fSDimitry Andric CurDAG->setNodeMemRefs(Result, cast<MachineSDNode>(True)->memoperands()); 39335f757f3fSDimitry Andric 3934bdd1243dSDimitry Andric // Replace vmerge.vvm node by Result. 3935bdd1243dSDimitry Andric ReplaceUses(SDValue(N, 0), SDValue(Result, 0)); 3936bdd1243dSDimitry Andric 3937bdd1243dSDimitry Andric // Replace another value of True. E.g. chain and VL. 3938bdd1243dSDimitry Andric for (unsigned Idx = 1; Idx < True->getNumValues(); ++Idx) 3939bdd1243dSDimitry Andric ReplaceUses(True.getValue(Idx), SDValue(Result, Idx)); 3940bdd1243dSDimitry Andric 3941bdd1243dSDimitry Andric return true; 3942bdd1243dSDimitry Andric } 3943bdd1243dSDimitry Andric 3944bdd1243dSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeMergeVVMFold() { 3945bdd1243dSDimitry Andric bool MadeChange = false; 3946bdd1243dSDimitry Andric SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); 3947bdd1243dSDimitry Andric 3948bdd1243dSDimitry Andric while (Position != CurDAG->allnodes_begin()) { 3949bdd1243dSDimitry Andric SDNode *N = &*--Position; 3950bdd1243dSDimitry Andric if (N->use_empty() || !N->isMachineOpcode()) 3951bdd1243dSDimitry Andric continue; 3952bdd1243dSDimitry Andric 395306c3fb27SDimitry Andric if (IsVMerge(N) || IsVMv(N)) 395406c3fb27SDimitry Andric MadeChange |= performCombineVMergeAndVOps(N); 3955bdd1243dSDimitry Andric } 3956bdd1243dSDimitry Andric return MadeChange; 3957bdd1243dSDimitry Andric } 3958bdd1243dSDimitry Andric 39595f757f3fSDimitry Andric /// If our passthru is an implicit_def, use noreg instead. This side 39605f757f3fSDimitry Andric /// steps issues with MachineCSE not being able to CSE expressions with 39615f757f3fSDimitry Andric /// IMPLICIT_DEF operands while preserving the semantic intent. See 39625f757f3fSDimitry Andric /// pr64282 for context. Note that this transform is the last one 39635f757f3fSDimitry Andric /// performed at ISEL DAG to DAG. 39645f757f3fSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeNoRegPassThru() { 39655f757f3fSDimitry Andric bool MadeChange = false; 39665f757f3fSDimitry Andric SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); 39675f757f3fSDimitry Andric 39685f757f3fSDimitry Andric while (Position != CurDAG->allnodes_begin()) { 39695f757f3fSDimitry Andric SDNode *N = &*--Position; 39705f757f3fSDimitry Andric if (N->use_empty() || !N->isMachineOpcode()) 39715f757f3fSDimitry Andric continue; 39725f757f3fSDimitry Andric 39735f757f3fSDimitry Andric const unsigned Opc = N->getMachineOpcode(); 39745f757f3fSDimitry Andric if (!RISCVVPseudosTable::getPseudoInfo(Opc) || 39755f757f3fSDimitry Andric !RISCVII::isFirstDefTiedToFirstUse(TII->get(Opc)) || 39765f757f3fSDimitry Andric !isImplicitDef(N->getOperand(0))) 39775f757f3fSDimitry Andric continue; 39785f757f3fSDimitry Andric 39795f757f3fSDimitry Andric SmallVector<SDValue> Ops; 39805f757f3fSDimitry Andric Ops.push_back(CurDAG->getRegister(RISCV::NoRegister, N->getValueType(0))); 39815f757f3fSDimitry Andric for (unsigned I = 1, E = N->getNumOperands(); I != E; I++) { 39825f757f3fSDimitry Andric SDValue Op = N->getOperand(I); 39835f757f3fSDimitry Andric Ops.push_back(Op); 39845f757f3fSDimitry Andric } 39855f757f3fSDimitry Andric 39865f757f3fSDimitry Andric MachineSDNode *Result = 39875f757f3fSDimitry Andric CurDAG->getMachineNode(Opc, SDLoc(N), N->getVTList(), Ops); 39885f757f3fSDimitry Andric Result->setFlags(N->getFlags()); 39895f757f3fSDimitry Andric CurDAG->setNodeMemRefs(Result, cast<MachineSDNode>(N)->memoperands()); 39905f757f3fSDimitry Andric ReplaceUses(N, Result); 39915f757f3fSDimitry Andric MadeChange = true; 39925f757f3fSDimitry Andric } 39935f757f3fSDimitry Andric return MadeChange; 39945f757f3fSDimitry Andric } 39955f757f3fSDimitry Andric 39965f757f3fSDimitry Andric 39970b57cec5SDimitry Andric // This pass converts a legalized DAG into a RISCV-specific DAG, ready 39980b57cec5SDimitry Andric // for instruction scheduling. 399981ad6265SDimitry Andric FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM, 40005f757f3fSDimitry Andric CodeGenOptLevel OptLevel) { 4001*0fca6ea1SDimitry Andric return new RISCVDAGToDAGISelLegacy(TM, OptLevel); 40020b57cec5SDimitry Andric } 4003bdd1243dSDimitry Andric 4004*0fca6ea1SDimitry Andric char RISCVDAGToDAGISelLegacy::ID = 0; 4005bdd1243dSDimitry Andric 4006*0fca6ea1SDimitry Andric RISCVDAGToDAGISelLegacy::RISCVDAGToDAGISelLegacy(RISCVTargetMachine &TM, 4007*0fca6ea1SDimitry Andric CodeGenOptLevel OptLevel) 4008*0fca6ea1SDimitry Andric : SelectionDAGISelLegacy( 4009*0fca6ea1SDimitry Andric ID, std::make_unique<RISCVDAGToDAGISel>(TM, OptLevel)) {} 4010*0fca6ea1SDimitry Andric 4011*0fca6ea1SDimitry Andric INITIALIZE_PASS(RISCVDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false) 4012