1//===-- RISCVSubtarget.cpp - RISC-V Subtarget Information -----------------===//
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 implements the RISC-V specific subclass of TargetSubtargetInfo.
10//
11//===----------------------------------------------------------------------===//
12
13#include "RISCVSubtarget.h"
14#include "GISel/RISCVCallLowering.h"
15#include "GISel/RISCVInlineAsmLowering.h"
16#include "GISel/RISCVLegalizerInfo.h"
17#include "RISCV.h"
18#include "RISCVFrameLowering.h"
19#include "RISCVSelectionDAGInfo.h"
20#include "RISCVTargetMachine.h"
21#include "llvm/CodeGen/MachineFrameInfo.h"
22#include "llvm/MC/TargetRegistry.h"
23#include "llvm/Support/ErrorHandling.h"
24
25using namespace llvm;
26
27#define DEBUG_TYPE "riscv-subtarget"
28
29#define GET_SUBTARGETINFO_TARGET_DESC
30#define GET_SUBTARGETINFO_CTOR
31#include "RISCVGenSubtargetInfo.inc"
32
33#define GET_RISCV_MACRO_FUSION_PRED_IMPL
34#include "RISCVGenMacroFusion.inc"
35
36namespace llvm::RISCVTuneInfoTable {
37
38#define GET_RISCVTuneInfoTable_IMPL
39#include "RISCVGenSearchableTables.inc"
40} // namespace llvm::RISCVTuneInfoTable
41
42static cl::opt<unsigned> RVVVectorLMULMax(
43 "riscv-v-fixed-length-vector-lmul-max",
44 cl::desc("The maximum LMUL value to use for fixed length vectors. "
45 "Fractional LMUL values are not supported."),
46 cl::init(Val: 8), cl::Hidden);
47
48static cl::opt<bool> RISCVDisableUsingConstantPoolForLargeInts(
49 "riscv-disable-using-constant-pool-for-large-ints",
50 cl::desc("Disable using constant pool for large integers."),
51 cl::init(Val: false), cl::Hidden);
52
53static cl::opt<unsigned> RISCVMaxBuildIntsCost(
54 "riscv-max-build-ints-cost",
55 cl::desc("The maximum cost used for building integers."), cl::init(Val: 0),
56 cl::Hidden);
57
58static cl::opt<bool> UseAA("riscv-use-aa", cl::init(Val: true),
59 cl::desc("Enable the use of AA during codegen."));
60
61static cl::opt<unsigned> RISCVMinimumJumpTableEntries(
62 "riscv-min-jump-table-entries", cl::Hidden,
63 cl::desc("Set minimum number of entries to use a jump table on RISCV"));
64
65static cl::opt<bool> UseMIPSLoadStorePairsOpt(
66 "use-riscv-mips-load-store-pairs",
67 cl::desc("Enable the load/store pair optimization pass"), cl::init(Val: false),
68 cl::Hidden);
69
70static cl::opt<bool> UseMIPSCCMovInsn("use-riscv-mips-ccmov",
71 cl::desc("Use 'mips.ccmov' instruction"),
72 cl::init(Val: true), cl::Hidden);
73
74void RISCVSubtarget::anchor() {}
75
76RISCVSubtarget &
77RISCVSubtarget::initializeSubtargetDependencies(const Triple &TT, StringRef CPU,
78 StringRef TuneCPU, StringRef FS,
79 StringRef ABIName) {
80 // Determine default and user-specified characteristics
81 bool Is64Bit = TT.isArch64Bit();
82 if (CPU.empty() || CPU == "generic")
83 CPU = Is64Bit ? "generic-rv64" : "generic-rv32";
84
85 if (TuneCPU.empty())
86 TuneCPU = CPU;
87 if (TuneCPU == "generic")
88 TuneCPU = Is64Bit ? "generic-rv64" : "generic-rv32";
89
90 TuneInfo = RISCVTuneInfoTable::getRISCVTuneInfo(Name: TuneCPU);
91 // If there is no TuneInfo for this CPU, we fail back to generic.
92 if (!TuneInfo)
93 TuneInfo = RISCVTuneInfoTable::getRISCVTuneInfo(Name: "generic");
94 assert(TuneInfo && "TuneInfo shouldn't be nullptr!");
95
96 ParseSubtargetFeatures(CPU, TuneCPU, FS);
97
98 RISCV::updateCZceFeatureImplications(STI&: *this);
99
100 // Re-sync the flags.
101 HasStdExtZcd = hasFeature(Feature: RISCV::FeatureStdExtZcd);
102 HasStdExtZcf = hasFeature(Feature: RISCV::FeatureStdExtZcf);
103 HasStdExtC = hasFeature(Feature: RISCV::FeatureStdExtC);
104 HasStdExtZce = hasFeature(Feature: RISCV::FeatureStdExtZce);
105
106 TargetABI = RISCVABI::computeTargetABI(STI: *this, ABIName);
107 RISCVFeatures::validate(TT, FeatureBits: getFeatureBits());
108 return *this;
109}
110
111RISCVSubtarget::RISCVSubtarget(const Triple &TT, StringRef CPU,
112 StringRef TuneCPU, StringRef FS,
113 StringRef ABIName, unsigned RVVVectorBitsMin,
114 unsigned RVVVectorBitsMax,
115 const TargetMachine &TM)
116 : RISCVGenSubtargetInfo(TT, CPU, TuneCPU, FS),
117 IsLittleEndian(TT.isLittleEndian()), RVVVectorBitsMin(RVVVectorBitsMin),
118 RVVVectorBitsMax(RVVVectorBitsMax),
119 FrameLowering(
120 initializeSubtargetDependencies(TT, CPU, TuneCPU, FS, ABIName)),
121 InstrInfo(*this), TLInfo(TM, *this) {
122 TSInfo = std::make_unique<RISCVSelectionDAGInfo>();
123}
124
125RISCVSubtarget::~RISCVSubtarget() = default;
126
127const SelectionDAGTargetInfo *RISCVSubtarget::getSelectionDAGInfo() const {
128 return TSInfo.get();
129}
130
131const InlineAsmLowering *RISCVSubtarget::getInlineAsmLowering() const {
132 if (!InlineAsmLoweringInfo)
133 InlineAsmLoweringInfo.reset(
134 p: new RISCVInlineAsmLowering(getTargetLowering()));
135 return InlineAsmLoweringInfo.get();
136}
137
138const CallLowering *RISCVSubtarget::getCallLowering() const {
139 if (!CallLoweringInfo)
140 CallLoweringInfo.reset(p: new RISCVCallLowering(*getTargetLowering()));
141 return CallLoweringInfo.get();
142}
143
144InstructionSelector *RISCVSubtarget::getInstructionSelector() const {
145 if (!InstSelector) {
146 InstSelector.reset(p: createRISCVInstructionSelector(
147 *static_cast<const RISCVTargetMachine *>(&TLInfo.getTargetMachine()),
148 *this, *getRegBankInfo()));
149 }
150 return InstSelector.get();
151}
152
153const LegalizerInfo *RISCVSubtarget::getLegalizerInfo() const {
154 if (!Legalizer)
155 Legalizer.reset(p: new RISCVLegalizerInfo(*this));
156 return Legalizer.get();
157}
158
159const RISCVRegisterBankInfo *RISCVSubtarget::getRegBankInfo() const {
160 if (!RegBankInfo)
161 RegBankInfo.reset(p: new RISCVRegisterBankInfo(getHwMode()));
162 return RegBankInfo.get();
163}
164
165bool RISCVSubtarget::useConstantPoolForLargeInts() const {
166 return !RISCVDisableUsingConstantPoolForLargeInts;
167}
168
169// Returns true if VT is a P extension packed SIMD type.
170bool RISCVSubtarget::isPExtPackedType(MVT VT) const {
171 if (!HasStdExtP)
172 return false;
173
174 // RV32 supports 32-bit and 64-bit vectors. RV64 only support 64-bit vectors.
175 if (!is64Bit() && (VT == MVT::v4i8 || VT == MVT::v2i16))
176 return true;
177
178 return VT == MVT::v8i8 || VT == MVT::v4i16 || VT == MVT::v2i32;
179}
180
181// Returns true if VT is a P extension packed double-wide SIMD type.
182bool RISCVSubtarget::isPExtPackedDoubleType(MVT VT) const {
183 if (!HasStdExtP || is64Bit())
184 return false;
185
186 return VT == MVT::v8i8 || VT == MVT::v4i16 || VT == MVT::v2i32;
187}
188
189unsigned RISCVSubtarget::getMaxBuildIntsCost() const {
190 // Loading integer from constant pool needs two instructions (the reason why
191 // the minimum cost is 2): an address calculation instruction and a load
192 // instruction. Usually, address calculation and instructions used for
193 // building integers (addi, slli, etc.) can be done in one cycle, so here we
194 // set the default cost to (LoadLatency + 1) if no threshold is provided.
195 return RISCVMaxBuildIntsCost == 0
196 ? getSchedModel().LoadLatency + 1
197 : std::max<unsigned>(a: 2, b: RISCVMaxBuildIntsCost);
198}
199
200unsigned RISCVSubtarget::getMaxRVVVectorSizeInBits() const {
201 assert(hasVInstructions() &&
202 "Tried to get vector length without Zve or V extension support!");
203
204 // ZvlLen specifies the minimum required vlen. The upper bound provided by
205 // riscv-v-vector-bits-max should be no less than it.
206 if (RVVVectorBitsMax != 0 && RVVVectorBitsMax < ZvlLen)
207 report_fatal_error(reason: "riscv-v-vector-bits-max specified is lower "
208 "than the Zvl*b limitation");
209
210 return RVVVectorBitsMax;
211}
212
213unsigned RISCVSubtarget::getMinRVVVectorSizeInBits() const {
214 assert(hasVInstructions() &&
215 "Tried to get vector length without Zve or V extension support!");
216
217 if (RVVVectorBitsMin == -1U)
218 return ZvlLen;
219
220 // ZvlLen specifies the minimum required vlen. The lower bound provided by
221 // riscv-v-vector-bits-min should be no less than it.
222 if (RVVVectorBitsMin != 0 && RVVVectorBitsMin < ZvlLen)
223 report_fatal_error(reason: "riscv-v-vector-bits-min specified is lower "
224 "than the Zvl*b limitation");
225
226 return RVVVectorBitsMin;
227}
228
229unsigned RISCVSubtarget::getMaxLMULForFixedLengthVectors() const {
230 assert(hasVInstructions() &&
231 "Tried to get vector length without Zve or V extension support!");
232 assert(RVVVectorLMULMax <= 8 &&
233 llvm::has_single_bit<uint32_t>(RVVVectorLMULMax) &&
234 "V extension requires a LMUL to be at most 8 and a power of 2!");
235 return llvm::bit_floor(Value: std::clamp<unsigned>(val: RVVVectorLMULMax, lo: 1, hi: 8));
236}
237
238bool RISCVSubtarget::useRVVForFixedLengthVectors() const {
239 return hasVInstructions() &&
240 getMinRVVVectorSizeInBits() >= RISCV::RVVBitsPerBlock;
241}
242
243bool RISCVSubtarget::enableSubRegLiveness() const { return true; }
244
245bool RISCVSubtarget::enableMachinePipeliner() const {
246 return getSchedModel().hasInstrSchedModel();
247}
248
249void RISCVSubtarget::mirFileLoaded(MachineFunction &MF) const {
250 // We usually compute max call frame size after ISel. Do the computation now
251 // if the .mir file didn't specify it. Note that this will probably give you
252 // bogus values after PEI has eliminated the callframe setup/destroy pseudo
253 // instructions, specify explicitly if you need it to be correct.
254 MachineFrameInfo &MFI = MF.getFrameInfo();
255 if (!MFI.isMaxCallFrameSizeComputed())
256 MFI.computeMaxCallFrameSize(MF);
257}
258
259 /// Enable use of alias analysis during code generation (during MI
260 /// scheduling, DAGCombine, etc.).
261bool RISCVSubtarget::useAA() const { return UseAA; }
262
263unsigned RISCVSubtarget::getMinimumJumpTableEntries() const {
264 return RISCVMinimumJumpTableEntries.getNumOccurrences() > 0
265 ? RISCVMinimumJumpTableEntries
266 : TuneInfo->MinimumJumpTableEntries;
267}
268
269void RISCVSubtarget::overrideSchedPolicy(MachineSchedPolicy &Policy,
270 const SchedRegion &Region) const {
271 // Do bidirectional scheduling since it provides a more balanced scheduling
272 // leading to better performance. This will increase compile time.
273 Policy.OnlyTopDown = false;
274 Policy.OnlyBottomUp = false;
275
276 // Disabling the latency heuristic can reduce the number of spills/reloads but
277 // will cause some regressions on some cores.
278 Policy.DisableLatencyHeuristic = DisableLatencySchedHeuristic;
279
280 // Spilling is generally expensive on all RISC-V cores, so always enable
281 // register-pressure tracking. This will increase compile time.
282 Policy.ShouldTrackPressure = true;
283}
284
285void RISCVSubtarget::overridePostRASchedPolicy(
286 MachineSchedPolicy &Policy, const SchedRegion &Region) const {
287 MISched::Direction PostRASchedDirection = getPostRASchedDirection();
288 if (PostRASchedDirection == MISched::TopDown) {
289 Policy.OnlyTopDown = true;
290 Policy.OnlyBottomUp = false;
291 } else if (PostRASchedDirection == MISched::BottomUp) {
292 Policy.OnlyTopDown = false;
293 Policy.OnlyBottomUp = true;
294 } else if (PostRASchedDirection == MISched::Bidirectional) {
295 Policy.OnlyTopDown = false;
296 Policy.OnlyBottomUp = false;
297 }
298}
299
300bool RISCVSubtarget::useMIPSLoadStorePairs() const {
301 return UseMIPSLoadStorePairsOpt && HasVendorXMIPSLSP;
302}
303
304bool RISCVSubtarget::useMIPSCCMovInsn() const {
305 return UseMIPSCCMovInsn && HasVendorXMIPSCMov;
306}
307