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/MachineScheduler.h" |
25 | #include "llvm/CodeGen/TargetSubtargetInfo.h" |
26 | #include "llvm/IR/DataLayout.h" |
27 | #include "llvm/Support/Compiler.h" |
28 | #include "llvm/Target/TargetMachine.h" |
29 | #include <bitset> |
30 | |
31 | #define GET_RISCV_MACRO_FUSION_PRED_DECL |
32 | #include "RISCVGenMacroFusion.inc" |
33 | |
34 | #define |
35 | #include "RISCVGenSubtargetInfo.inc" |
36 | |
37 | namespace llvm { |
38 | class StringRef; |
39 | |
40 | namespace RISCVTuneInfoTable { |
41 | |
42 | struct RISCVTuneInfo { |
43 | const char *Name; |
44 | uint8_t PrefFunctionAlignment; |
45 | uint8_t PrefLoopAlignment; |
46 | |
47 | // Information needed by LoopDataPrefetch. |
48 | uint16_t CacheLineSize; |
49 | uint16_t PrefetchDistance; |
50 | uint16_t MinPrefetchStride; |
51 | unsigned MaxPrefetchIterationsAhead; |
52 | |
53 | unsigned MinimumJumpTableEntries; |
54 | |
55 | // Tail duplication threshold at -O3. |
56 | unsigned TailDupAggressiveThreshold; |
57 | |
58 | unsigned MaxStoresPerMemsetOptSize; |
59 | unsigned MaxStoresPerMemset; |
60 | |
61 | unsigned MaxGluedStoresPerMemcpy; |
62 | unsigned MaxStoresPerMemcpyOptSize; |
63 | unsigned MaxStoresPerMemcpy; |
64 | |
65 | unsigned MaxStoresPerMemmoveOptSize; |
66 | unsigned MaxStoresPerMemmove; |
67 | |
68 | unsigned MaxLoadsPerMemcmpOptSize; |
69 | unsigned MaxLoadsPerMemcmp; |
70 | |
71 | // The direction of PostRA scheduling. |
72 | MISched::Direction PostRASchedDirection; |
73 | }; |
74 | |
75 | #define GET_RISCVTuneInfoTable_DECL |
76 | #include "RISCVGenSearchableTables.inc" |
77 | } // namespace RISCVTuneInfoTable |
78 | |
79 | class RISCVSubtarget : public RISCVGenSubtargetInfo { |
80 | public: |
81 | // clang-format off |
82 | enum RISCVProcFamilyEnum : uint8_t { |
83 | Others, |
84 | SiFive7, |
85 | VentanaVeyron, |
86 | MIPSP8700, |
87 | Andes45, |
88 | }; |
89 | enum RISCVVRGatherCostModelEnum : uint8_t { |
90 | Quadratic, |
91 | NLog2N, |
92 | }; |
93 | // clang-format on |
94 | private: |
95 | virtual void anchor(); |
96 | |
97 | RISCVProcFamilyEnum RISCVProcFamily = Others; |
98 | RISCVVRGatherCostModelEnum RISCVVRGatherCostModel = Quadratic; |
99 | |
100 | #define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \ |
101 | bool ATTRIBUTE = DEFAULT; |
102 | #include "RISCVGenSubtargetInfo.inc" |
103 | |
104 | unsigned XSfmmTE = 0; |
105 | unsigned ZvlLen = 0; |
106 | unsigned RVVVectorBitsMin; |
107 | unsigned RVVVectorBitsMax; |
108 | uint8_t MaxInterleaveFactor = 2; |
109 | RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown; |
110 | std::bitset<RISCV::NUM_TARGET_REGS> UserReservedRegister; |
111 | const RISCVTuneInfoTable::RISCVTuneInfo *TuneInfo; |
112 | |
113 | RISCVFrameLowering FrameLowering; |
114 | RISCVInstrInfo InstrInfo; |
115 | RISCVRegisterInfo RegInfo; |
116 | RISCVTargetLowering TLInfo; |
117 | |
118 | /// Initializes using the passed in CPU and feature strings so that we can |
119 | /// use initializer lists for subtarget initialization. |
120 | RISCVSubtarget &initializeSubtargetDependencies(const Triple &TT, |
121 | StringRef CPU, |
122 | StringRef TuneCPU, |
123 | StringRef FS, |
124 | StringRef ABIName); |
125 | |
126 | public: |
127 | // Initializes the data members to match that of the specified triple. |
128 | RISCVSubtarget(const Triple &TT, StringRef CPU, StringRef TuneCPU, |
129 | StringRef FS, StringRef ABIName, unsigned RVVVectorBitsMin, |
130 | unsigned RVVVectorLMULMax, const TargetMachine &TM); |
131 | |
132 | ~RISCVSubtarget() override; |
133 | |
134 | // Parses features string setting specified subtarget options. The |
135 | // definition of this function is auto-generated by tblgen. |
136 | void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); |
137 | |
138 | const RISCVFrameLowering *getFrameLowering() const override { |
139 | return &FrameLowering; |
140 | } |
141 | const RISCVInstrInfo *getInstrInfo() const override { return &InstrInfo; } |
142 | const RISCVRegisterInfo *getRegisterInfo() const override { |
143 | return &RegInfo; |
144 | } |
145 | const RISCVTargetLowering *getTargetLowering() const override { |
146 | return &TLInfo; |
147 | } |
148 | |
149 | bool enableMachineScheduler() const override { return true; } |
150 | |
151 | bool enablePostRAScheduler() const override { return UsePostRAScheduler; } |
152 | |
153 | Align getPrefFunctionAlignment() const { |
154 | return Align(TuneInfo->PrefFunctionAlignment); |
155 | } |
156 | Align getPrefLoopAlignment() const { |
157 | return Align(TuneInfo->PrefLoopAlignment); |
158 | } |
159 | |
160 | /// Returns RISC-V processor family. |
161 | /// Avoid this function! CPU specifics should be kept local to this class |
162 | /// and preferably modeled with SubtargetFeatures or properties in |
163 | /// initializeProperties(). |
164 | RISCVProcFamilyEnum getProcFamily() const { return RISCVProcFamily; } |
165 | |
166 | RISCVVRGatherCostModelEnum getVRGatherCostModel() const { return RISCVVRGatherCostModel; } |
167 | |
168 | #define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \ |
169 | bool GETTER() const { return ATTRIBUTE; } |
170 | #include "RISCVGenSubtargetInfo.inc" |
171 | |
172 | LLVM_DEPRECATED("Now Equivalent to hasStdExtZca" , "hasStdExtZca" ) |
173 | bool hasStdExtCOrZca() const { return HasStdExtZca; } |
174 | bool hasStdExtCOrZcd() const { return HasStdExtC || HasStdExtZcd; } |
175 | bool hasStdExtCOrZcfOrZce() const { |
176 | return HasStdExtC || HasStdExtZcf || HasStdExtZce; |
177 | } |
178 | bool hasStdExtZvl() const { return ZvlLen != 0; } |
179 | bool hasStdExtFOrZfinx() const { return HasStdExtF || HasStdExtZfinx; } |
180 | bool hasStdExtDOrZdinx() const { return HasStdExtD || HasStdExtZdinx; } |
181 | bool hasStdExtZfhOrZhinx() const { return HasStdExtZfh || HasStdExtZhinx; } |
182 | bool hasStdExtZfhminOrZhinxmin() const { |
183 | return HasStdExtZfhmin || HasStdExtZhinxmin; |
184 | } |
185 | bool hasHalfFPLoadStoreMove() const { |
186 | return HasStdExtZfhmin || HasStdExtZfbfmin; |
187 | } |
188 | |
189 | bool hasConditionalMoveFusion() const { |
190 | // Do we support fusing a branch+mv or branch+c.mv as a conditional move. |
191 | return (hasConditionalCompressedMoveFusion() && hasStdExtZca()) || |
192 | hasShortForwardBranchOpt(); |
193 | } |
194 | |
195 | bool is64Bit() const { return IsRV64; } |
196 | MVT getXLenVT() const { |
197 | return is64Bit() ? MVT::i64 : MVT::i32; |
198 | } |
199 | unsigned getXLen() const { |
200 | return is64Bit() ? 64 : 32; |
201 | } |
202 | bool useLoadStorePairs() const; |
203 | bool useCCMovInsn() const; |
204 | unsigned getFLen() const { |
205 | if (HasStdExtD) |
206 | return 64; |
207 | |
208 | if (HasStdExtF) |
209 | return 32; |
210 | |
211 | return 0; |
212 | } |
213 | unsigned getELen() const { |
214 | assert(hasVInstructions() && "Expected V extension" ); |
215 | return hasVInstructionsI64() ? 64 : 32; |
216 | } |
217 | unsigned getRealMinVLen() const { |
218 | unsigned VLen = getMinRVVVectorSizeInBits(); |
219 | return VLen == 0 ? ZvlLen : VLen; |
220 | } |
221 | unsigned getRealMaxVLen() const { |
222 | unsigned VLen = getMaxRVVVectorSizeInBits(); |
223 | return VLen == 0 ? 65536 : VLen; |
224 | } |
225 | // If we know the exact VLEN, return it. Otherwise, return std::nullopt. |
226 | std::optional<unsigned> getRealVLen() const { |
227 | unsigned Min = getRealMinVLen(); |
228 | if (Min != getRealMaxVLen()) |
229 | return std::nullopt; |
230 | return Min; |
231 | } |
232 | |
233 | /// If the ElementCount or TypeSize \p X is scalable and VScale (VLEN) is |
234 | /// exactly known, returns \p X converted to a fixed quantity. Otherwise |
235 | /// returns \p X unmodified. |
236 | template <typename Quantity> Quantity expandVScale(Quantity X) const { |
237 | if (auto VLen = getRealVLen(); VLen && X.isScalable()) { |
238 | const unsigned VScale = *VLen / RISCV::RVVBitsPerBlock; |
239 | X = Quantity::getFixed(X.getKnownMinValue() * VScale); |
240 | } |
241 | return X; |
242 | } |
243 | |
244 | RISCVABI::ABI getTargetABI() const { return TargetABI; } |
245 | bool isSoftFPABI() const { |
246 | return TargetABI == RISCVABI::ABI_LP64 || |
247 | TargetABI == RISCVABI::ABI_ILP32 || |
248 | TargetABI == RISCVABI::ABI_ILP32E; |
249 | } |
250 | bool isRegisterReservedByUser(Register i) const override { |
251 | assert(i.id() < RISCV::NUM_TARGET_REGS && "Register out of range" ); |
252 | return UserReservedRegister[i.id()]; |
253 | } |
254 | |
255 | // XRay support - require D and C extensions. |
256 | bool isXRaySupported() const override { return hasStdExtD() && hasStdExtC(); } |
257 | |
258 | // Vector codegen related methods. |
259 | bool hasVInstructions() const { return HasStdExtZve32x; } |
260 | bool hasVInstructionsI64() const { return HasStdExtZve64x; } |
261 | bool hasVInstructionsF16Minimal() const { return HasStdExtZvfhmin; } |
262 | bool hasVInstructionsF16() const { return HasStdExtZvfh; } |
263 | bool hasVInstructionsBF16Minimal() const { return HasStdExtZvfbfmin; } |
264 | bool hasVInstructionsF32() const { return HasStdExtZve32f; } |
265 | bool hasVInstructionsF64() const { return HasStdExtZve64d; } |
266 | // F16 and F64 both require F32. |
267 | bool hasVInstructionsAnyF() const { return hasVInstructionsF32(); } |
268 | bool hasVInstructionsFullMultiply() const { return HasStdExtV; } |
269 | unsigned getMaxInterleaveFactor() const { |
270 | return hasVInstructions() ? MaxInterleaveFactor : 1; |
271 | } |
272 | |
273 | bool hasOptimizedSegmentLoadStore(unsigned NF) const { |
274 | switch (NF) { |
275 | case 2: |
276 | return hasOptimizedNF2SegmentLoadStore(); |
277 | case 3: |
278 | return hasOptimizedNF3SegmentLoadStore(); |
279 | case 4: |
280 | return hasOptimizedNF4SegmentLoadStore(); |
281 | case 5: |
282 | return hasOptimizedNF5SegmentLoadStore(); |
283 | case 6: |
284 | return hasOptimizedNF6SegmentLoadStore(); |
285 | case 7: |
286 | return hasOptimizedNF7SegmentLoadStore(); |
287 | case 8: |
288 | return hasOptimizedNF8SegmentLoadStore(); |
289 | default: |
290 | llvm_unreachable("Unexpected NF" ); |
291 | } |
292 | } |
293 | |
294 | // Returns VLEN divided by DLEN. Where DLEN is the datapath width of the |
295 | // vector hardware implementation which may be less than VLEN. |
296 | unsigned getDLenFactor() const { |
297 | if (DLenFactor2) |
298 | return 2; |
299 | return 1; |
300 | } |
301 | |
302 | protected: |
303 | // SelectionDAGISel related APIs. |
304 | std::unique_ptr<const SelectionDAGTargetInfo> TSInfo; |
305 | |
306 | // GlobalISel related APIs. |
307 | mutable std::unique_ptr<CallLowering> CallLoweringInfo; |
308 | mutable std::unique_ptr<InstructionSelector> InstSelector; |
309 | mutable std::unique_ptr<LegalizerInfo> Legalizer; |
310 | mutable std::unique_ptr<RISCVRegisterBankInfo> RegBankInfo; |
311 | |
312 | // Return the known range for the bit length of RVV data registers as set |
313 | // at the command line. A value of 0 means nothing is known about that particular |
314 | // limit beyond what's implied by the architecture. |
315 | // NOTE: Please use getRealMinVLen and getRealMaxVLen instead! |
316 | unsigned getMaxRVVVectorSizeInBits() const; |
317 | unsigned getMinRVVVectorSizeInBits() const; |
318 | |
319 | public: |
320 | const SelectionDAGTargetInfo *getSelectionDAGInfo() const override; |
321 | const CallLowering *getCallLowering() const override; |
322 | InstructionSelector *getInstructionSelector() const override; |
323 | const LegalizerInfo *getLegalizerInfo() const override; |
324 | const RISCVRegisterBankInfo *getRegBankInfo() const override; |
325 | |
326 | bool isTargetAndroid() const { return getTargetTriple().isAndroid(); } |
327 | bool isTargetFuchsia() const { return getTargetTriple().isOSFuchsia(); } |
328 | |
329 | bool useConstantPoolForLargeInts() const; |
330 | |
331 | // Maximum cost used for building integers, integers will be put into constant |
332 | // pool if exceeded. |
333 | unsigned getMaxBuildIntsCost() const; |
334 | |
335 | unsigned getMaxLMULForFixedLengthVectors() const; |
336 | bool useRVVForFixedLengthVectors() const; |
337 | |
338 | bool enableSubRegLiveness() const override; |
339 | |
340 | bool enableMachinePipeliner() const override; |
341 | |
342 | bool useDFAforSMS() const override { return false; } |
343 | |
344 | bool useAA() const override; |
345 | |
346 | unsigned getCacheLineSize() const override { |
347 | return TuneInfo->CacheLineSize; |
348 | }; |
349 | unsigned getPrefetchDistance() const override { |
350 | return TuneInfo->PrefetchDistance; |
351 | }; |
352 | unsigned getMinPrefetchStride(unsigned NumMemAccesses, |
353 | unsigned NumStridedMemAccesses, |
354 | unsigned NumPrefetches, |
355 | bool HasCall) const override { |
356 | return TuneInfo->MinPrefetchStride; |
357 | }; |
358 | unsigned getMaxPrefetchIterationsAhead() const override { |
359 | return TuneInfo->MaxPrefetchIterationsAhead; |
360 | }; |
361 | bool enableWritePrefetching() const override { return true; } |
362 | |
363 | unsigned getMinimumJumpTableEntries() const; |
364 | |
365 | unsigned getTailDupAggressiveThreshold() const { |
366 | return TuneInfo->TailDupAggressiveThreshold; |
367 | } |
368 | |
369 | unsigned getMaxStoresPerMemset(bool OptSize) const { |
370 | return OptSize ? TuneInfo->MaxStoresPerMemsetOptSize |
371 | : TuneInfo->MaxStoresPerMemset; |
372 | } |
373 | |
374 | unsigned getMaxGluedStoresPerMemcpy() const { |
375 | return TuneInfo->MaxGluedStoresPerMemcpy; |
376 | } |
377 | |
378 | unsigned getMaxStoresPerMemcpy(bool OptSize) const { |
379 | return OptSize ? TuneInfo->MaxStoresPerMemcpyOptSize |
380 | : TuneInfo->MaxStoresPerMemcpy; |
381 | } |
382 | |
383 | unsigned getMaxStoresPerMemmove(bool OptSize) const { |
384 | return OptSize ? TuneInfo->MaxStoresPerMemmoveOptSize |
385 | : TuneInfo->MaxStoresPerMemmove; |
386 | } |
387 | |
388 | unsigned getMaxLoadsPerMemcmp(bool OptSize) const { |
389 | return OptSize ? TuneInfo->MaxLoadsPerMemcmpOptSize |
390 | : TuneInfo->MaxLoadsPerMemcmp; |
391 | } |
392 | |
393 | MISched::Direction getPostRASchedDirection() const { |
394 | return TuneInfo->PostRASchedDirection; |
395 | } |
396 | |
397 | void overrideSchedPolicy(MachineSchedPolicy &Policy, |
398 | unsigned NumRegionInstrs) const override; |
399 | |
400 | void overridePostRASchedPolicy(MachineSchedPolicy &Policy, |
401 | unsigned NumRegionInstrs) const override; |
402 | }; |
403 | } // End llvm namespace |
404 | |
405 | #endif |
406 | |