| 1 | //===---- RISCVISelDAGToDAG.h - A dag to dag inst selector for RISC-V -----===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file defines an instruction selector for the RISC-V target. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #ifndef LLVM_LIB_TARGET_RISCV_RISCVISELDAGTODAG_H |
| 14 | #define LLVM_LIB_TARGET_RISCV_RISCVISELDAGTODAG_H |
| 15 | |
| 16 | #include "RISCV.h" |
| 17 | #include "RISCVTargetMachine.h" |
| 18 | #include "llvm/CodeGen/SelectionDAGISel.h" |
| 19 | #include "llvm/Support/KnownBits.h" |
| 20 | |
| 21 | // RISC-V specific code to select RISC-V machine instructions for |
| 22 | // SelectionDAG operations. |
| 23 | namespace llvm { |
| 24 | class RISCVDAGToDAGISel : public SelectionDAGISel { |
| 25 | const RISCVSubtarget *Subtarget = nullptr; |
| 26 | |
| 27 | public: |
| 28 | RISCVDAGToDAGISel() = delete; |
| 29 | |
| 30 | explicit RISCVDAGToDAGISel(RISCVTargetMachine &TargetMachine, |
| 31 | CodeGenOptLevel OptLevel) |
| 32 | : SelectionDAGISel(TargetMachine, OptLevel) {} |
| 33 | |
| 34 | bool runOnMachineFunction(MachineFunction &MF) override { |
| 35 | Subtarget = &MF.getSubtarget<RISCVSubtarget>(); |
| 36 | return SelectionDAGISel::runOnMachineFunction(mf&: MF); |
| 37 | } |
| 38 | |
| 39 | void PreprocessISelDAG() override; |
| 40 | void PostprocessISelDAG() override; |
| 41 | |
| 42 | void Select(SDNode *Node) override; |
| 43 | |
| 44 | bool SelectInlineAsmMemoryOperand(const SDValue &Op, |
| 45 | InlineAsm::ConstraintCode ConstraintID, |
| 46 | std::vector<SDValue> &OutOps) override; |
| 47 | |
| 48 | bool areOffsetsWithinAlignment(SDValue Addr, Align Alignment); |
| 49 | |
| 50 | bool SelectAddrFrameIndex(SDValue Addr, SDValue &Base, SDValue &Offset); |
| 51 | bool SelectAddrRegImm(SDValue Addr, SDValue &Base, SDValue &Offset); |
| 52 | bool SelectAddrRegImm9(SDValue Addr, SDValue &Base, SDValue &Offset); |
| 53 | bool SelectAddrRegImmLsb00000(SDValue Addr, SDValue &Base, SDValue &Offset); |
| 54 | |
| 55 | bool SelectAddrRegRegScale(SDValue Addr, unsigned MaxShiftAmount, |
| 56 | SDValue &Base, SDValue &Index, SDValue &Scale); |
| 57 | |
| 58 | template <unsigned MaxShift> |
| 59 | bool SelectAddrRegRegScale(SDValue Addr, SDValue &Base, SDValue &Index, |
| 60 | SDValue &Scale) { |
| 61 | return SelectAddrRegRegScale(Addr, MaxShiftAmount: MaxShift, Base, Index, Scale); |
| 62 | } |
| 63 | |
| 64 | bool SelectAddrRegZextRegScale(SDValue Addr, unsigned MaxShiftAmount, |
| 65 | unsigned Bits, SDValue &Base, SDValue &Index, |
| 66 | SDValue &Scale); |
| 67 | |
| 68 | template <unsigned MaxShift, unsigned Bits> |
| 69 | bool SelectAddrRegZextRegScale(SDValue Addr, SDValue &Base, SDValue &Index, |
| 70 | SDValue &Scale) { |
| 71 | return SelectAddrRegZextRegScale(Addr, MaxShiftAmount: MaxShift, Bits, Base, Index, Scale); |
| 72 | } |
| 73 | |
| 74 | bool SelectAddrRegReg(SDValue Addr, SDValue &Base, SDValue &Offset); |
| 75 | |
| 76 | bool tryShrinkShlLogicImm(SDNode *Node); |
| 77 | bool (SDNode *Node); |
| 78 | bool trySignedBitfieldInsertInSign(SDNode *Node); |
| 79 | bool (SDNode *Node, const SDLoc &DL, MVT VT, |
| 80 | SDValue X, unsigned Msb, unsigned Lsb); |
| 81 | bool tryUnsignedBitfieldInsertInZero(SDNode *Node, const SDLoc &DL, MVT VT, |
| 82 | SDValue X, unsigned Msb, unsigned Lsb); |
| 83 | bool tryIndexedLoad(SDNode *Node); |
| 84 | |
| 85 | bool selectShiftMask(SDValue N, unsigned ShiftWidth, SDValue &ShAmt); |
| 86 | bool selectShiftMaskXLen(SDValue N, SDValue &ShAmt) { |
| 87 | return selectShiftMask(N, ShiftWidth: Subtarget->getXLen(), ShAmt); |
| 88 | } |
| 89 | bool selectShiftMask32(SDValue N, SDValue &ShAmt) { |
| 90 | return selectShiftMask(N, ShiftWidth: 32, ShAmt); |
| 91 | } |
| 92 | |
| 93 | bool selectSETCC(SDValue N, ISD::CondCode ExpectedCCVal, SDValue &Val); |
| 94 | bool selectSETNE(SDValue N, SDValue &Val) { |
| 95 | return selectSETCC(N, ExpectedCCVal: ISD::SETNE, Val); |
| 96 | } |
| 97 | bool selectSETEQ(SDValue N, SDValue &Val) { |
| 98 | return selectSETCC(N, ExpectedCCVal: ISD::SETEQ, Val); |
| 99 | } |
| 100 | |
| 101 | bool selectSExtBits(SDValue N, unsigned Bits, SDValue &Val); |
| 102 | template <unsigned Bits> bool selectSExtBits(SDValue N, SDValue &Val) { |
| 103 | return selectSExtBits(N, Bits, Val); |
| 104 | } |
| 105 | bool selectZExtBits(SDValue N, unsigned Bits, SDValue &Val); |
| 106 | template <unsigned Bits> bool selectZExtBits(SDValue N, SDValue &Val) { |
| 107 | return selectZExtBits(N, Bits, Val); |
| 108 | } |
| 109 | |
| 110 | bool selectSHXADDOp(SDValue N, unsigned ShAmt, SDValue &Val); |
| 111 | template <unsigned ShAmt> bool selectSHXADDOp(SDValue N, SDValue &Val) { |
| 112 | return selectSHXADDOp(N, ShAmt, Val); |
| 113 | } |
| 114 | |
| 115 | bool selectSHXADD_UWOp(SDValue N, unsigned ShAmt, SDValue &Val); |
| 116 | template <unsigned ShAmt> bool selectSHXADD_UWOp(SDValue N, SDValue &Val) { |
| 117 | return selectSHXADD_UWOp(N, ShAmt, Val); |
| 118 | } |
| 119 | |
| 120 | bool selectZExtImm32(SDValue N, SDValue &Val); |
| 121 | bool selectNegImm(SDValue N, SDValue &Val); |
| 122 | bool selectInvLogicImm(SDValue N, SDValue &Val); |
| 123 | |
| 124 | bool orDisjoint(const SDNode *Node) const; |
| 125 | bool hasAllNBitUsers(SDNode *Node, unsigned Bits, |
| 126 | const unsigned Depth = 0) const; |
| 127 | bool hasAllBUsers(SDNode *Node) const { return hasAllNBitUsers(Node, Bits: 8); } |
| 128 | bool hasAllHUsers(SDNode *Node) const { return hasAllNBitUsers(Node, Bits: 16); } |
| 129 | bool hasAllWUsers(SDNode *Node) const { return hasAllNBitUsers(Node, Bits: 32); } |
| 130 | |
| 131 | bool selectSimm5Shl2(SDValue N, SDValue &Simm5, SDValue &Shl2); |
| 132 | |
| 133 | bool selectVLOp(SDValue N, SDValue &VL); |
| 134 | |
| 135 | bool selectVSplat(SDValue N, SDValue &SplatVal); |
| 136 | bool selectVSplatSimm5(SDValue N, SDValue &SplatVal); |
| 137 | bool selectVSplatUimm(SDValue N, unsigned Bits, SDValue &SplatVal); |
| 138 | template <unsigned Bits> bool selectVSplatUimmBits(SDValue N, SDValue &Val) { |
| 139 | return selectVSplatUimm(N, Bits, SplatVal&: Val); |
| 140 | } |
| 141 | bool selectVSplatSimm5Plus1(SDValue N, SDValue &SplatVal); |
| 142 | bool selectVSplatSimm5Plus1NoDec(SDValue N, SDValue &SplatVal); |
| 143 | bool selectVSplatSimm5Plus1NonZero(SDValue N, SDValue &SplatVal); |
| 144 | bool selectVSplatImm64Neg(SDValue N, SDValue &SplatVal); |
| 145 | // Matches the splat of a value which can be extended or truncated, such that |
| 146 | // only the bottom 8 bits are preserved. |
| 147 | bool selectLow8BitsVSplat(SDValue N, SDValue &SplatVal); |
| 148 | bool selectScalarFPAsInt(SDValue N, SDValue &Imm); |
| 149 | |
| 150 | bool selectRVVSimm5(SDValue N, unsigned Width, SDValue &Imm); |
| 151 | template <unsigned Width> bool selectRVVSimm5(SDValue N, SDValue &Imm) { |
| 152 | return selectRVVSimm5(N, Width, Imm); |
| 153 | } |
| 154 | |
| 155 | void addVectorLoadStoreOperands(SDNode *Node, unsigned SEWImm, |
| 156 | const SDLoc &DL, unsigned CurOp, |
| 157 | bool IsMasked, bool IsStridedOrIndexed, |
| 158 | SmallVectorImpl<SDValue> &Operands, |
| 159 | bool IsLoad = false, MVT *IndexVT = nullptr); |
| 160 | |
| 161 | void selectVLSEG(SDNode *Node, unsigned NF, bool IsMasked, bool IsStrided); |
| 162 | void selectVLSEGFF(SDNode *Node, unsigned NF, bool IsMasked); |
| 163 | void selectVLXSEG(SDNode *Node, unsigned NF, bool IsMasked, bool IsOrdered); |
| 164 | void selectVSSEG(SDNode *Node, unsigned NF, bool IsMasked, bool IsStrided); |
| 165 | void selectVSXSEG(SDNode *Node, unsigned NF, bool IsMasked, bool IsOrdered); |
| 166 | |
| 167 | void selectVSETVLI(SDNode *Node); |
| 168 | void selectXSfmmVSET(SDNode *Node); |
| 169 | |
| 170 | void selectSF_VC_X_SE(SDNode *Node); |
| 171 | |
| 172 | // Return the RISC-V condition code that matches the given DAG integer |
| 173 | // condition code. The CondCode must be one of those supported by the RISC-V |
| 174 | // ISA (see translateSetCCForBranch). |
| 175 | static RISCVCC::CondCode getRISCVCCForIntCC(ISD::CondCode CC) { |
| 176 | switch (CC) { |
| 177 | default: |
| 178 | llvm_unreachable("Unsupported CondCode" ); |
| 179 | case ISD::SETEQ: |
| 180 | return RISCVCC::COND_EQ; |
| 181 | case ISD::SETNE: |
| 182 | return RISCVCC::COND_NE; |
| 183 | case ISD::SETLT: |
| 184 | return RISCVCC::COND_LT; |
| 185 | case ISD::SETGE: |
| 186 | return RISCVCC::COND_GE; |
| 187 | case ISD::SETULT: |
| 188 | return RISCVCC::COND_LTU; |
| 189 | case ISD::SETUGE: |
| 190 | return RISCVCC::COND_GEU; |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | // Include the pieces autogenerated from the target description. |
| 195 | #define GET_DAGISEL_DECL |
| 196 | #include "RISCVGenDAGISel.inc" |
| 197 | |
| 198 | private: |
| 199 | bool doPeepholeSExtW(SDNode *Node); |
| 200 | bool doPeepholeMaskedRVV(MachineSDNode *Node); |
| 201 | bool doPeepholeNoRegPassThru(); |
| 202 | bool performCombineVMergeAndVOps(SDNode *N); |
| 203 | bool selectImm64IfCheaper(int64_t Imm, int64_t OrigImm, SDValue N, |
| 204 | SDValue &Val); |
| 205 | }; |
| 206 | |
| 207 | class RISCVDAGToDAGISelLegacy : public SelectionDAGISelLegacy { |
| 208 | public: |
| 209 | static char ID; |
| 210 | explicit RISCVDAGToDAGISelLegacy(RISCVTargetMachine &TargetMachine, |
| 211 | CodeGenOptLevel OptLevel); |
| 212 | }; |
| 213 | |
| 214 | } // namespace llvm |
| 215 | |
| 216 | #endif |
| 217 | |