1 | //===-- RISCVSubtarget.h - Define Subtarget for the RISC-V ------*- C++ -*-===// |
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 declares the RISC-V specific subclass of TargetSubtargetInfo. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_LIB_TARGET_RISCV_RISCVSUBTARGET_H |
14 | #define LLVM_LIB_TARGET_RISCV_RISCVSUBTARGET_H |
15 | |
16 | #include "GISel/RISCVRegisterBankInfo.h" |
17 | #include "MCTargetDesc/RISCVBaseInfo.h" |
18 | #include "RISCVFrameLowering.h" |
19 | #include "RISCVISelLowering.h" |
20 | #include "RISCVInstrInfo.h" |
21 | #include "llvm/CodeGen/GlobalISel/CallLowering.h" |
22 | #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" |
23 | #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" |
24 | #include "llvm/CodeGen/SelectionDAGTargetInfo.h" |
25 | #include "llvm/CodeGen/TargetSubtargetInfo.h" |
26 | #include "llvm/IR/DataLayout.h" |
27 | #include "llvm/Target/TargetMachine.h" |
28 | #include <bitset> |
29 | |
30 | #define GET_RISCV_MACRO_FUSION_PRED_DECL |
31 | #include "RISCVGenMacroFusion.inc" |
32 | |
33 | #define |
34 | #include "RISCVGenSubtargetInfo.inc" |
35 | |
36 | namespace llvm { |
37 | class StringRef; |
38 | |
39 | namespace RISCVTuneInfoTable { |
40 | |
41 | struct RISCVTuneInfo { |
42 | const char *Name; |
43 | uint8_t PrefFunctionAlignment; |
44 | uint8_t PrefLoopAlignment; |
45 | |
46 | // Information needed by LoopDataPrefetch. |
47 | uint16_t CacheLineSize; |
48 | uint16_t PrefetchDistance; |
49 | uint16_t MinPrefetchStride; |
50 | unsigned MaxPrefetchIterationsAhead; |
51 | |
52 | unsigned MinimumJumpTableEntries; |
53 | }; |
54 | |
55 | #define GET_RISCVTuneInfoTable_DECL |
56 | #include "RISCVGenSearchableTables.inc" |
57 | } // namespace RISCVTuneInfoTable |
58 | |
59 | class RISCVSubtarget : public RISCVGenSubtargetInfo { |
60 | public: |
61 | // clang-format off |
62 | enum RISCVProcFamilyEnum : uint8_t { |
63 | Others, |
64 | SiFive7, |
65 | VentanaVeyron, |
66 | }; |
67 | // clang-format on |
68 | private: |
69 | virtual void anchor(); |
70 | |
71 | RISCVProcFamilyEnum RISCVProcFamily = Others; |
72 | |
73 | #define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \ |
74 | bool ATTRIBUTE = DEFAULT; |
75 | #include "RISCVGenSubtargetInfo.inc" |
76 | |
77 | unsigned ZvlLen = 0; |
78 | unsigned RVVVectorBitsMin; |
79 | unsigned RVVVectorBitsMax; |
80 | uint8_t MaxInterleaveFactor = 2; |
81 | RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown; |
82 | std::bitset<RISCV::NUM_TARGET_REGS> UserReservedRegister; |
83 | const RISCVTuneInfoTable::RISCVTuneInfo *TuneInfo; |
84 | |
85 | RISCVFrameLowering FrameLowering; |
86 | RISCVInstrInfo InstrInfo; |
87 | RISCVRegisterInfo RegInfo; |
88 | RISCVTargetLowering TLInfo; |
89 | SelectionDAGTargetInfo TSInfo; |
90 | |
91 | /// Initializes using the passed in CPU and feature strings so that we can |
92 | /// use initializer lists for subtarget initialization. |
93 | RISCVSubtarget &initializeSubtargetDependencies(const Triple &TT, |
94 | StringRef CPU, |
95 | StringRef TuneCPU, |
96 | StringRef FS, |
97 | StringRef ABIName); |
98 | |
99 | public: |
100 | // Initializes the data members to match that of the specified triple. |
101 | RISCVSubtarget(const Triple &TT, StringRef CPU, StringRef TuneCPU, |
102 | StringRef FS, StringRef ABIName, unsigned RVVVectorBitsMin, |
103 | unsigned RVVVectorLMULMax, const TargetMachine &TM); |
104 | |
105 | // Parses features string setting specified subtarget options. The |
106 | // definition of this function is auto-generated by tblgen. |
107 | void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); |
108 | |
109 | const RISCVFrameLowering *getFrameLowering() const override { |
110 | return &FrameLowering; |
111 | } |
112 | const RISCVInstrInfo *getInstrInfo() const override { return &InstrInfo; } |
113 | const RISCVRegisterInfo *getRegisterInfo() const override { |
114 | return &RegInfo; |
115 | } |
116 | const RISCVTargetLowering *getTargetLowering() const override { |
117 | return &TLInfo; |
118 | } |
119 | const SelectionDAGTargetInfo *getSelectionDAGInfo() const override { |
120 | return &TSInfo; |
121 | } |
122 | bool enableMachineScheduler() const override { return true; } |
123 | |
124 | bool enablePostRAScheduler() const override { return UsePostRAScheduler; } |
125 | |
126 | Align getPrefFunctionAlignment() const { |
127 | return Align(TuneInfo->PrefFunctionAlignment); |
128 | } |
129 | Align getPrefLoopAlignment() const { |
130 | return Align(TuneInfo->PrefLoopAlignment); |
131 | } |
132 | |
133 | /// Returns RISC-V processor family. |
134 | /// Avoid this function! CPU specifics should be kept local to this class |
135 | /// and preferably modeled with SubtargetFeatures or properties in |
136 | /// initializeProperties(). |
137 | RISCVProcFamilyEnum getProcFamily() const { return RISCVProcFamily; } |
138 | |
139 | #define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \ |
140 | bool GETTER() const { return ATTRIBUTE; } |
141 | #include "RISCVGenSubtargetInfo.inc" |
142 | |
143 | bool hasStdExtCOrZca() const { return HasStdExtC || HasStdExtZca; } |
144 | bool hasStdExtCOrZcd() const { return HasStdExtC || HasStdExtZcd; } |
145 | bool hasStdExtCOrZcfOrZce() const { |
146 | return HasStdExtC || HasStdExtZcf || HasStdExtZce; |
147 | } |
148 | bool hasStdExtZvl() const { return ZvlLen != 0; } |
149 | bool hasStdExtFOrZfinx() const { return HasStdExtF || HasStdExtZfinx; } |
150 | bool hasStdExtDOrZdinx() const { return HasStdExtD || HasStdExtZdinx; } |
151 | bool hasStdExtZfhOrZhinx() const { return HasStdExtZfh || HasStdExtZhinx; } |
152 | bool hasStdExtZfhminOrZhinxmin() const { |
153 | return HasStdExtZfhmin || HasStdExtZhinxmin; |
154 | } |
155 | bool hasHalfFPLoadStoreMove() const { |
156 | return HasStdExtZfhmin || HasStdExtZfbfmin; |
157 | } |
158 | |
159 | bool hasConditionalMoveFusion() const { |
160 | // Do we support fusing a branch+mv or branch+c.mv as a conditional move. |
161 | return (hasConditionalCompressedMoveFusion() && hasStdExtCOrZca()) || |
162 | hasShortForwardBranchOpt(); |
163 | } |
164 | |
165 | bool is64Bit() const { return IsRV64; } |
166 | MVT getXLenVT() const { |
167 | return is64Bit() ? MVT::i64 : MVT::i32; |
168 | } |
169 | unsigned getXLen() const { |
170 | return is64Bit() ? 64 : 32; |
171 | } |
172 | unsigned getFLen() const { |
173 | if (HasStdExtD) |
174 | return 64; |
175 | |
176 | if (HasStdExtF) |
177 | return 32; |
178 | |
179 | return 0; |
180 | } |
181 | unsigned getELen() const { |
182 | assert(hasVInstructions() && "Expected V extension" ); |
183 | return hasVInstructionsI64() ? 64 : 32; |
184 | } |
185 | unsigned getRealMinVLen() const { |
186 | unsigned VLen = getMinRVVVectorSizeInBits(); |
187 | return VLen == 0 ? ZvlLen : VLen; |
188 | } |
189 | unsigned getRealMaxVLen() const { |
190 | unsigned VLen = getMaxRVVVectorSizeInBits(); |
191 | return VLen == 0 ? 65536 : VLen; |
192 | } |
193 | // If we know the exact VLEN, return it. Otherwise, return std::nullopt. |
194 | std::optional<unsigned> getRealVLen() const { |
195 | unsigned Min = getRealMinVLen(); |
196 | if (Min != getRealMaxVLen()) |
197 | return std::nullopt; |
198 | return Min; |
199 | } |
200 | |
201 | /// If the ElementCount or TypeSize \p X is scalable and VScale (VLEN) is |
202 | /// exactly known, returns \p X converted to a fixed quantity. Otherwise |
203 | /// returns \p X unmodified. |
204 | template <typename Quantity> Quantity expandVScale(Quantity X) const { |
205 | if (auto VLen = getRealVLen(); VLen && X.isScalable()) { |
206 | const unsigned VScale = *VLen / RISCV::RVVBitsPerBlock; |
207 | X = Quantity::getFixed(X.getKnownMinValue() * VScale); |
208 | } |
209 | return X; |
210 | } |
211 | |
212 | RISCVABI::ABI getTargetABI() const { return TargetABI; } |
213 | bool isSoftFPABI() const { |
214 | return TargetABI == RISCVABI::ABI_LP64 || |
215 | TargetABI == RISCVABI::ABI_ILP32 || |
216 | TargetABI == RISCVABI::ABI_ILP32E; |
217 | } |
218 | bool isRegisterReservedByUser(Register i) const { |
219 | assert(i < RISCV::NUM_TARGET_REGS && "Register out of range" ); |
220 | return UserReservedRegister[i]; |
221 | } |
222 | |
223 | // Vector codegen related methods. |
224 | bool hasVInstructions() const { return HasStdExtZve32x; } |
225 | bool hasVInstructionsI64() const { return HasStdExtZve64x; } |
226 | bool hasVInstructionsF16Minimal() const { return HasStdExtZvfhmin; } |
227 | bool hasVInstructionsF16() const { return HasStdExtZvfh; } |
228 | bool hasVInstructionsBF16() const { return HasStdExtZvfbfmin; } |
229 | bool hasVInstructionsF32() const { return HasStdExtZve32f; } |
230 | bool hasVInstructionsF64() const { return HasStdExtZve64d; } |
231 | // F16 and F64 both require F32. |
232 | bool hasVInstructionsAnyF() const { return hasVInstructionsF32(); } |
233 | bool hasVInstructionsFullMultiply() const { return HasStdExtV; } |
234 | unsigned getMaxInterleaveFactor() const { |
235 | return hasVInstructions() ? MaxInterleaveFactor : 1; |
236 | } |
237 | |
238 | // Returns VLEN divided by DLEN. Where DLEN is the datapath width of the |
239 | // vector hardware implementation which may be less than VLEN. |
240 | unsigned getDLenFactor() const { |
241 | if (DLenFactor2) |
242 | return 2; |
243 | return 1; |
244 | } |
245 | |
246 | protected: |
247 | // GlobalISel related APIs. |
248 | mutable std::unique_ptr<CallLowering> CallLoweringInfo; |
249 | mutable std::unique_ptr<InstructionSelector> InstSelector; |
250 | mutable std::unique_ptr<LegalizerInfo> Legalizer; |
251 | mutable std::unique_ptr<RISCVRegisterBankInfo> RegBankInfo; |
252 | |
253 | // Return the known range for the bit length of RVV data registers as set |
254 | // at the command line. A value of 0 means nothing is known about that particular |
255 | // limit beyond what's implied by the architecture. |
256 | // NOTE: Please use getRealMinVLen and getRealMaxVLen instead! |
257 | unsigned getMaxRVVVectorSizeInBits() const; |
258 | unsigned getMinRVVVectorSizeInBits() const; |
259 | |
260 | public: |
261 | const CallLowering *getCallLowering() const override; |
262 | InstructionSelector *getInstructionSelector() const override; |
263 | const LegalizerInfo *getLegalizerInfo() const override; |
264 | const RISCVRegisterBankInfo *getRegBankInfo() const override; |
265 | |
266 | bool isTargetAndroid() const { return getTargetTriple().isAndroid(); } |
267 | bool isTargetFuchsia() const { return getTargetTriple().isOSFuchsia(); } |
268 | |
269 | bool useConstantPoolForLargeInts() const; |
270 | |
271 | // Maximum cost used for building integers, integers will be put into constant |
272 | // pool if exceeded. |
273 | unsigned getMaxBuildIntsCost() const; |
274 | |
275 | unsigned getMaxLMULForFixedLengthVectors() const; |
276 | bool useRVVForFixedLengthVectors() const; |
277 | |
278 | bool enableSubRegLiveness() const override; |
279 | |
280 | void getPostRAMutations(std::vector<std::unique_ptr<ScheduleDAGMutation>> |
281 | &Mutations) const override; |
282 | |
283 | bool useAA() const override; |
284 | |
285 | unsigned getCacheLineSize() const override { |
286 | return TuneInfo->CacheLineSize; |
287 | }; |
288 | unsigned getPrefetchDistance() const override { |
289 | return TuneInfo->PrefetchDistance; |
290 | }; |
291 | unsigned getMinPrefetchStride(unsigned NumMemAccesses, |
292 | unsigned NumStridedMemAccesses, |
293 | unsigned NumPrefetches, |
294 | bool HasCall) const override { |
295 | return TuneInfo->MinPrefetchStride; |
296 | }; |
297 | unsigned getMaxPrefetchIterationsAhead() const override { |
298 | return TuneInfo->MaxPrefetchIterationsAhead; |
299 | }; |
300 | |
301 | unsigned getMinimumJumpTableEntries() const; |
302 | |
303 | bool supportsInitUndef() const override { return hasVInstructions(); } |
304 | }; |
305 | } // End llvm namespace |
306 | |
307 | #endif |
308 | |