| 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 SelectAddrFrameIndex(SDValue Addr, SDValue &Base, SDValue &Offset); |
| 49 | bool SelectAddrRegImm(SDValue Addr, SDValue &Base, SDValue &Offset); |
| 50 | bool SelectAddrRegImm9(SDValue Addr, SDValue &Base, SDValue &Offset); |
| 51 | bool SelectAddrRegImmLsb00000(SDValue Addr, SDValue &Base, SDValue &Offset); |
| 52 | |
| 53 | bool SelectAddrRegRegScale(SDValue Addr, unsigned MaxShiftAmount, |
| 54 | SDValue &Base, SDValue &Index, SDValue &Scale); |
| 55 | |
| 56 | template <unsigned MaxShift> |
| 57 | bool SelectAddrRegRegScale(SDValue Addr, SDValue &Base, SDValue &Index, |
| 58 | SDValue &Scale) { |
| 59 | return SelectAddrRegRegScale(Addr, MaxShiftAmount: MaxShift, Base, Index, Scale); |
| 60 | } |
| 61 | |
| 62 | template <unsigned MaxShift, unsigned Bits> |
| 63 | bool SelectAddrRegZextRegScale(SDValue Addr, SDValue &Base, SDValue &Index, |
| 64 | SDValue &Scale) { |
| 65 | if (SelectAddrRegRegScale(Addr, MaxShiftAmount: MaxShift, Base, Index, Scale)) { |
| 66 | if (Index.getOpcode() == ISD::AND) { |
| 67 | auto *C = dyn_cast<ConstantSDNode>(Val: Index.getOperand(i: 1)); |
| 68 | if (C && C->getZExtValue() == maskTrailingOnes<uint64_t>(N: Bits)) { |
| 69 | Index = Index.getOperand(i: 0); |
| 70 | return true; |
| 71 | } |
| 72 | } |
| 73 | } |
| 74 | return false; |
| 75 | } |
| 76 | |
| 77 | bool SelectAddrRegReg(SDValue Addr, SDValue &Base, SDValue &Offset); |
| 78 | |
| 79 | bool tryShrinkShlLogicImm(SDNode *Node); |
| 80 | bool (SDNode *Node); |
| 81 | bool trySignedBitfieldInsertInSign(SDNode *Node); |
| 82 | bool (SDNode *Node, const SDLoc &DL, MVT VT, |
| 83 | SDValue X, unsigned Msb, unsigned Lsb); |
| 84 | bool tryUnsignedBitfieldInsertInZero(SDNode *Node, const SDLoc &DL, MVT VT, |
| 85 | SDValue X, unsigned Msb, unsigned Lsb); |
| 86 | bool tryIndexedLoad(SDNode *Node); |
| 87 | |
| 88 | bool selectShiftMask(SDValue N, unsigned ShiftWidth, SDValue &ShAmt); |
| 89 | bool selectShiftMaskXLen(SDValue N, SDValue &ShAmt) { |
| 90 | return selectShiftMask(N, ShiftWidth: Subtarget->getXLen(), ShAmt); |
| 91 | } |
| 92 | bool selectShiftMask32(SDValue N, SDValue &ShAmt) { |
| 93 | return selectShiftMask(N, ShiftWidth: 32, ShAmt); |
| 94 | } |
| 95 | |
| 96 | bool selectSETCC(SDValue N, ISD::CondCode ExpectedCCVal, SDValue &Val); |
| 97 | bool selectSETNE(SDValue N, SDValue &Val) { |
| 98 | return selectSETCC(N, ExpectedCCVal: ISD::SETNE, Val); |
| 99 | } |
| 100 | bool selectSETEQ(SDValue N, SDValue &Val) { |
| 101 | return selectSETCC(N, ExpectedCCVal: ISD::SETEQ, Val); |
| 102 | } |
| 103 | |
| 104 | bool selectSExtBits(SDValue N, unsigned Bits, SDValue &Val); |
| 105 | template <unsigned Bits> bool selectSExtBits(SDValue N, SDValue &Val) { |
| 106 | return selectSExtBits(N, Bits, Val); |
| 107 | } |
| 108 | bool selectZExtBits(SDValue N, unsigned Bits, SDValue &Val); |
| 109 | template <unsigned Bits> bool selectZExtBits(SDValue N, SDValue &Val) { |
| 110 | return selectZExtBits(N, Bits, Val); |
| 111 | } |
| 112 | |
| 113 | bool selectSHXADDOp(SDValue N, unsigned ShAmt, SDValue &Val); |
| 114 | template <unsigned ShAmt> bool selectSHXADDOp(SDValue N, SDValue &Val) { |
| 115 | return selectSHXADDOp(N, ShAmt, Val); |
| 116 | } |
| 117 | |
| 118 | bool selectSHXADD_UWOp(SDValue N, unsigned ShAmt, SDValue &Val); |
| 119 | template <unsigned ShAmt> bool selectSHXADD_UWOp(SDValue N, SDValue &Val) { |
| 120 | return selectSHXADD_UWOp(N, ShAmt, Val); |
| 121 | } |
| 122 | |
| 123 | bool selectZExtImm32(SDValue N, SDValue &Val); |
| 124 | bool selectNegImm(SDValue N, SDValue &Val); |
| 125 | bool selectInvLogicImm(SDValue N, SDValue &Val); |
| 126 | |
| 127 | bool orIsAdd(const SDNode *Node) const; |
| 128 | bool hasAllNBitUsers(SDNode *Node, unsigned Bits, |
| 129 | const unsigned Depth = 0) const; |
| 130 | bool hasAllBUsers(SDNode *Node) const { return hasAllNBitUsers(Node, Bits: 8); } |
| 131 | bool hasAllHUsers(SDNode *Node) const { return hasAllNBitUsers(Node, Bits: 16); } |
| 132 | bool hasAllWUsers(SDNode *Node) const { return hasAllNBitUsers(Node, Bits: 32); } |
| 133 | |
| 134 | bool selectSimm5Shl2(SDValue N, SDValue &Simm5, SDValue &Shl2); |
| 135 | |
| 136 | bool selectVLOp(SDValue N, SDValue &VL); |
| 137 | |
| 138 | bool selectVSplat(SDValue N, SDValue &SplatVal); |
| 139 | bool selectVSplatSimm5(SDValue N, SDValue &SplatVal); |
| 140 | bool selectVSplatUimm(SDValue N, unsigned Bits, SDValue &SplatVal); |
| 141 | template <unsigned Bits> bool selectVSplatUimmBits(SDValue N, SDValue &Val) { |
| 142 | return selectVSplatUimm(N, Bits, SplatVal&: Val); |
| 143 | } |
| 144 | bool selectVSplatSimm5Plus1(SDValue N, SDValue &SplatVal); |
| 145 | bool selectVSplatSimm5Plus1NoDec(SDValue N, SDValue &SplatVal); |
| 146 | bool selectVSplatSimm5Plus1NonZero(SDValue N, SDValue &SplatVal); |
| 147 | bool selectVSplatImm64Neg(SDValue N, SDValue &SplatVal); |
| 148 | // Matches the splat of a value which can be extended or truncated, such that |
| 149 | // only the bottom 8 bits are preserved. |
| 150 | bool selectLow8BitsVSplat(SDValue N, SDValue &SplatVal); |
| 151 | bool selectScalarFPAsInt(SDValue N, SDValue &Imm); |
| 152 | |
| 153 | bool selectRVVSimm5(SDValue N, unsigned Width, SDValue &Imm); |
| 154 | template <unsigned Width> bool selectRVVSimm5(SDValue N, SDValue &Imm) { |
| 155 | return selectRVVSimm5(N, Width, Imm); |
| 156 | } |
| 157 | |
| 158 | void addVectorLoadStoreOperands(SDNode *Node, unsigned SEWImm, |
| 159 | const SDLoc &DL, unsigned CurOp, |
| 160 | bool IsMasked, bool IsStridedOrIndexed, |
| 161 | SmallVectorImpl<SDValue> &Operands, |
| 162 | bool IsLoad = false, MVT *IndexVT = nullptr); |
| 163 | |
| 164 | void selectVLSEG(SDNode *Node, unsigned NF, bool IsMasked, bool IsStrided); |
| 165 | void selectVLSEGFF(SDNode *Node, unsigned NF, bool IsMasked); |
| 166 | void selectVLXSEG(SDNode *Node, unsigned NF, bool IsMasked, bool IsOrdered); |
| 167 | void selectVSSEG(SDNode *Node, unsigned NF, bool IsMasked, bool IsStrided); |
| 168 | void selectVSXSEG(SDNode *Node, unsigned NF, bool IsMasked, bool IsOrdered); |
| 169 | |
| 170 | void selectVSETVLI(SDNode *Node); |
| 171 | |
| 172 | void selectSF_VC_X_SE(SDNode *Node); |
| 173 | |
| 174 | // Return the RISC-V condition code that matches the given DAG integer |
| 175 | // condition code. The CondCode must be one of those supported by the RISC-V |
| 176 | // ISA (see translateSetCCForBranch). |
| 177 | static RISCVCC::CondCode getRISCVCCForIntCC(ISD::CondCode CC) { |
| 178 | switch (CC) { |
| 179 | default: |
| 180 | llvm_unreachable("Unsupported CondCode" ); |
| 181 | case ISD::SETEQ: |
| 182 | return RISCVCC::COND_EQ; |
| 183 | case ISD::SETNE: |
| 184 | return RISCVCC::COND_NE; |
| 185 | case ISD::SETLT: |
| 186 | return RISCVCC::COND_LT; |
| 187 | case ISD::SETGE: |
| 188 | return RISCVCC::COND_GE; |
| 189 | case ISD::SETULT: |
| 190 | return RISCVCC::COND_LTU; |
| 191 | case ISD::SETUGE: |
| 192 | return RISCVCC::COND_GEU; |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | // Include the pieces autogenerated from the target description. |
| 197 | #define GET_DAGISEL_DECL |
| 198 | #include "RISCVGenDAGISel.inc" |
| 199 | |
| 200 | private: |
| 201 | bool doPeepholeSExtW(SDNode *Node); |
| 202 | bool doPeepholeMaskedRVV(MachineSDNode *Node); |
| 203 | bool doPeepholeMergeVVMFold(); |
| 204 | bool doPeepholeNoRegPassThru(); |
| 205 | bool performCombineVMergeAndVOps(SDNode *N); |
| 206 | bool selectImm64IfCheaper(int64_t Imm, int64_t OrigImm, SDValue N, |
| 207 | SDValue &Val); |
| 208 | }; |
| 209 | |
| 210 | class RISCVDAGToDAGISelLegacy : public SelectionDAGISelLegacy { |
| 211 | public: |
| 212 | static char ID; |
| 213 | explicit RISCVDAGToDAGISelLegacy(RISCVTargetMachine &TargetMachine, |
| 214 | CodeGenOptLevel OptLevel); |
| 215 | }; |
| 216 | |
| 217 | } // namespace llvm |
| 218 | |
| 219 | #endif |
| 220 | |