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 | |