1 | //===- HexagonSubtarget.h - Define Subtarget for the Hexagon ----*- 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 Hexagon specific subclass of TargetSubtarget. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_LIB_TARGET_HEXAGON_HEXAGONSUBTARGET_H |
14 | #define LLVM_LIB_TARGET_HEXAGON_HEXAGONSUBTARGET_H |
15 | |
16 | #include "HexagonDepArch.h" |
17 | #include "HexagonFrameLowering.h" |
18 | #include "HexagonISelLowering.h" |
19 | #include "HexagonInstrInfo.h" |
20 | #include "HexagonRegisterInfo.h" |
21 | #include "HexagonSelectionDAGInfo.h" |
22 | #include "llvm/ADT/SmallSet.h" |
23 | #include "llvm/ADT/StringRef.h" |
24 | #include "llvm/CodeGen/ScheduleDAGMutation.h" |
25 | #include "llvm/CodeGen/TargetSubtargetInfo.h" |
26 | #include "llvm/MC/MCInstrItineraries.h" |
27 | #include "llvm/Support/Alignment.h" |
28 | #include <memory> |
29 | #include <string> |
30 | #include <vector> |
31 | |
32 | #define |
33 | #include "HexagonGenSubtargetInfo.inc" |
34 | |
35 | namespace llvm { |
36 | |
37 | class MachineInstr; |
38 | class SDep; |
39 | class SUnit; |
40 | class TargetMachine; |
41 | class Triple; |
42 | |
43 | class HexagonSubtarget : public HexagonGenSubtargetInfo { |
44 | virtual void anchor(); |
45 | |
46 | bool UseHVX64BOps = false; |
47 | bool UseHVX128BOps = false; |
48 | |
49 | bool UseAudioOps = false; |
50 | bool UseCompound = false; |
51 | bool UseLongCalls = false; |
52 | bool UseMemops = false; |
53 | bool UsePackets = false; |
54 | bool UseNewValueJumps = false; |
55 | bool UseNewValueStores = false; |
56 | bool UseSmallData = false; |
57 | bool UseUnsafeMath = false; |
58 | bool UseZRegOps = false; |
59 | bool UseHVXIEEEFPOps = false; |
60 | bool UseHVXQFloatOps = false; |
61 | bool UseHVXFloatingPoint = false; |
62 | bool UseCabac = false; |
63 | |
64 | bool HasPreV65 = false; |
65 | bool HasMemNoShuf = false; |
66 | bool EnableDuplex = false; |
67 | bool ReservedR19 = false; |
68 | bool NoreturnStackElim = false; |
69 | |
70 | public: |
71 | Hexagon::ArchEnum HexagonArchVersion; |
72 | Hexagon::ArchEnum HexagonHVXVersion = Hexagon::ArchEnum::NoArch; |
73 | CodeGenOptLevel OptLevel; |
74 | /// True if the target should use Back-Skip-Back scheduling. This is the |
75 | /// default for V60. |
76 | bool UseBSBScheduling; |
77 | |
78 | struct UsrOverflowMutation : public ScheduleDAGMutation { |
79 | void apply(ScheduleDAGInstrs *DAG) override; |
80 | }; |
81 | struct HVXMemLatencyMutation : public ScheduleDAGMutation { |
82 | void apply(ScheduleDAGInstrs *DAG) override; |
83 | }; |
84 | struct CallMutation : public ScheduleDAGMutation { |
85 | void apply(ScheduleDAGInstrs *DAG) override; |
86 | private: |
87 | bool shouldTFRICallBind(const HexagonInstrInfo &HII, |
88 | const SUnit &Inst1, const SUnit &Inst2) const; |
89 | }; |
90 | struct BankConflictMutation : public ScheduleDAGMutation { |
91 | void apply(ScheduleDAGInstrs *DAG) override; |
92 | }; |
93 | |
94 | private: |
95 | enum HexagonProcFamilyEnum { Others, TinyCore }; |
96 | |
97 | std::string CPUString; |
98 | HexagonProcFamilyEnum HexagonProcFamily = Others; |
99 | Triple TargetTriple; |
100 | |
101 | // The following objects can use the TargetTriple, so they must be |
102 | // declared after it. |
103 | HexagonInstrInfo InstrInfo; |
104 | HexagonRegisterInfo RegInfo; |
105 | HexagonTargetLowering TLInfo; |
106 | HexagonSelectionDAGInfo TSInfo; |
107 | HexagonFrameLowering FrameLowering; |
108 | InstrItineraryData InstrItins; |
109 | |
110 | public: |
111 | HexagonSubtarget(const Triple &TT, StringRef CPU, StringRef FS, |
112 | const TargetMachine &TM); |
113 | |
114 | const Triple &getTargetTriple() const { return TargetTriple; } |
115 | bool isEnvironmentMusl() const { |
116 | return TargetTriple.getEnvironment() == Triple::Musl; |
117 | } |
118 | |
119 | /// getInstrItins - Return the instruction itineraries based on subtarget |
120 | /// selection. |
121 | const InstrItineraryData *getInstrItineraryData() const override { |
122 | return &InstrItins; |
123 | } |
124 | const HexagonInstrInfo *getInstrInfo() const override { return &InstrInfo; } |
125 | const HexagonRegisterInfo *getRegisterInfo() const override { |
126 | return &RegInfo; |
127 | } |
128 | const HexagonTargetLowering *getTargetLowering() const override { |
129 | return &TLInfo; |
130 | } |
131 | const HexagonFrameLowering *getFrameLowering() const override { |
132 | return &FrameLowering; |
133 | } |
134 | const HexagonSelectionDAGInfo *getSelectionDAGInfo() const override { |
135 | return &TSInfo; |
136 | } |
137 | |
138 | HexagonSubtarget &initializeSubtargetDependencies(StringRef CPU, |
139 | StringRef FS); |
140 | |
141 | /// ParseSubtargetFeatures - Parses features string setting specified |
142 | /// subtarget options. Definition of function is auto generated by tblgen. |
143 | void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); |
144 | |
145 | bool isXRaySupported() const override { return true; } |
146 | |
147 | bool hasV5Ops() const { |
148 | return getHexagonArchVersion() >= Hexagon::ArchEnum::V5; |
149 | } |
150 | bool hasV5OpsOnly() const { |
151 | return getHexagonArchVersion() == Hexagon::ArchEnum::V5; |
152 | } |
153 | bool hasV55Ops() const { |
154 | return getHexagonArchVersion() >= Hexagon::ArchEnum::V55; |
155 | } |
156 | bool hasV55OpsOnly() const { |
157 | return getHexagonArchVersion() == Hexagon::ArchEnum::V55; |
158 | } |
159 | bool hasV60Ops() const { |
160 | return getHexagonArchVersion() >= Hexagon::ArchEnum::V60; |
161 | } |
162 | bool hasV60OpsOnly() const { |
163 | return getHexagonArchVersion() == Hexagon::ArchEnum::V60; |
164 | } |
165 | bool hasV62Ops() const { |
166 | return getHexagonArchVersion() >= Hexagon::ArchEnum::V62; |
167 | } |
168 | bool hasV62OpsOnly() const { |
169 | return getHexagonArchVersion() == Hexagon::ArchEnum::V62; |
170 | } |
171 | bool hasV65Ops() const { |
172 | return getHexagonArchVersion() >= Hexagon::ArchEnum::V65; |
173 | } |
174 | bool hasV65OpsOnly() const { |
175 | return getHexagonArchVersion() == Hexagon::ArchEnum::V65; |
176 | } |
177 | bool hasV66Ops() const { |
178 | return getHexagonArchVersion() >= Hexagon::ArchEnum::V66; |
179 | } |
180 | bool hasV66OpsOnly() const { |
181 | return getHexagonArchVersion() == Hexagon::ArchEnum::V66; |
182 | } |
183 | bool hasV67Ops() const { |
184 | return getHexagonArchVersion() >= Hexagon::ArchEnum::V67; |
185 | } |
186 | bool hasV67OpsOnly() const { |
187 | return getHexagonArchVersion() == Hexagon::ArchEnum::V67; |
188 | } |
189 | bool hasV68Ops() const { |
190 | return getHexagonArchVersion() >= Hexagon::ArchEnum::V68; |
191 | } |
192 | bool hasV68OpsOnly() const { |
193 | return getHexagonArchVersion() == Hexagon::ArchEnum::V68; |
194 | } |
195 | bool hasV69Ops() const { |
196 | return getHexagonArchVersion() >= Hexagon::ArchEnum::V69; |
197 | } |
198 | bool hasV69OpsOnly() const { |
199 | return getHexagonArchVersion() == Hexagon::ArchEnum::V69; |
200 | } |
201 | bool hasV71Ops() const { |
202 | return getHexagonArchVersion() >= Hexagon::ArchEnum::V71; |
203 | } |
204 | bool hasV71OpsOnly() const { |
205 | return getHexagonArchVersion() == Hexagon::ArchEnum::V71; |
206 | } |
207 | bool hasV73Ops() const { |
208 | return getHexagonArchVersion() >= Hexagon::ArchEnum::V73; |
209 | } |
210 | bool hasV73OpsOnly() const { |
211 | return getHexagonArchVersion() == Hexagon::ArchEnum::V73; |
212 | } |
213 | |
214 | bool useAudioOps() const { return UseAudioOps; } |
215 | bool useCompound() const { return UseCompound; } |
216 | bool useLongCalls() const { return UseLongCalls; } |
217 | bool useMemops() const { return UseMemops; } |
218 | bool usePackets() const { return UsePackets; } |
219 | bool useNewValueJumps() const { return UseNewValueJumps; } |
220 | bool useNewValueStores() const { return UseNewValueStores; } |
221 | bool useSmallData() const { return UseSmallData; } |
222 | bool useUnsafeMath() const { return UseUnsafeMath; } |
223 | bool useZRegOps() const { return UseZRegOps; } |
224 | bool useCabac() const { return UseCabac; } |
225 | |
226 | bool isTinyCore() const { return HexagonProcFamily == TinyCore; } |
227 | bool isTinyCoreWithDuplex() const { return isTinyCore() && EnableDuplex; } |
228 | |
229 | bool useHVXIEEEFPOps() const { return UseHVXIEEEFPOps && useHVXOps(); } |
230 | bool useHVXQFloatOps() const { |
231 | return UseHVXQFloatOps && HexagonHVXVersion >= Hexagon::ArchEnum::V68; |
232 | } |
233 | bool useHVXFloatingPoint() const { return UseHVXFloatingPoint; } |
234 | bool useHVXOps() const { |
235 | return HexagonHVXVersion > Hexagon::ArchEnum::NoArch; |
236 | } |
237 | bool useHVXV60Ops() const { |
238 | return HexagonHVXVersion >= Hexagon::ArchEnum::V60; |
239 | } |
240 | bool useHVXV62Ops() const { |
241 | return HexagonHVXVersion >= Hexagon::ArchEnum::V62; |
242 | } |
243 | bool useHVXV65Ops() const { |
244 | return HexagonHVXVersion >= Hexagon::ArchEnum::V65; |
245 | } |
246 | bool useHVXV66Ops() const { |
247 | return HexagonHVXVersion >= Hexagon::ArchEnum::V66; |
248 | } |
249 | bool useHVXV67Ops() const { |
250 | return HexagonHVXVersion >= Hexagon::ArchEnum::V67; |
251 | } |
252 | bool useHVXV68Ops() const { |
253 | return HexagonHVXVersion >= Hexagon::ArchEnum::V68; |
254 | } |
255 | bool useHVXV69Ops() const { |
256 | return HexagonHVXVersion >= Hexagon::ArchEnum::V69; |
257 | } |
258 | bool useHVXV71Ops() const { |
259 | return HexagonHVXVersion >= Hexagon::ArchEnum::V71; |
260 | } |
261 | bool useHVXV73Ops() const { |
262 | return HexagonHVXVersion >= Hexagon::ArchEnum::V73; |
263 | } |
264 | bool useHVX128BOps() const { return useHVXOps() && UseHVX128BOps; } |
265 | bool useHVX64BOps() const { return useHVXOps() && UseHVX64BOps; } |
266 | |
267 | bool hasMemNoShuf() const { return HasMemNoShuf; } |
268 | bool hasReservedR19() const { return ReservedR19; } |
269 | bool usePredicatedCalls() const; |
270 | |
271 | bool noreturnStackElim() const { return NoreturnStackElim; } |
272 | |
273 | bool useBSBScheduling() const { return UseBSBScheduling; } |
274 | bool enableMachineScheduler() const override; |
275 | |
276 | // Always use the TargetLowering default scheduler. |
277 | // FIXME: This will use the vliw scheduler which is probably just hurting |
278 | // compiler time and will be removed eventually anyway. |
279 | bool enableMachineSchedDefaultSched() const override { return false; } |
280 | |
281 | // For use with PostRAScheduling: get the anti-dependence breaking that should |
282 | // be performed before post-RA scheduling. |
283 | AntiDepBreakMode getAntiDepBreakMode() const override { return ANTIDEP_ALL; } |
284 | /// True if the subtarget should run a scheduler after register |
285 | /// allocation. |
286 | bool enablePostRAScheduler() const override { return true; } |
287 | |
288 | bool enableSubRegLiveness() const override; |
289 | |
290 | const std::string &getCPUString () const { return CPUString; } |
291 | |
292 | const Hexagon::ArchEnum &getHexagonArchVersion() const { |
293 | return HexagonArchVersion; |
294 | } |
295 | |
296 | void getPostRAMutations( |
297 | std::vector<std::unique_ptr<ScheduleDAGMutation>> &Mutations) |
298 | const override; |
299 | |
300 | void getSMSMutations( |
301 | std::vector<std::unique_ptr<ScheduleDAGMutation>> &Mutations) |
302 | const override; |
303 | |
304 | /// Enable use of alias analysis during code generation (during MI |
305 | /// scheduling, DAGCombine, etc.). |
306 | bool useAA() const override; |
307 | |
308 | /// Perform target specific adjustments to the latency of a schedule |
309 | /// dependency. |
310 | void adjustSchedDependency(SUnit *Def, int DefOpIdx, SUnit *Use, int UseOpIdx, |
311 | SDep &Dep, |
312 | const TargetSchedModel *SchedModel) const override; |
313 | |
314 | unsigned getVectorLength() const { |
315 | assert(useHVXOps()); |
316 | if (useHVX64BOps()) |
317 | return 64; |
318 | if (useHVX128BOps()) |
319 | return 128; |
320 | llvm_unreachable("Invalid HVX vector length settings" ); |
321 | } |
322 | |
323 | ArrayRef<MVT> getHVXElementTypes() const { |
324 | static MVT Types[] = {MVT::i8, MVT::i16, MVT::i32}; |
325 | static MVT TypesV68[] = {MVT::i8, MVT::i16, MVT::i32, MVT::f16, MVT::f32}; |
326 | |
327 | if (useHVXV68Ops() && useHVXFloatingPoint()) |
328 | return ArrayRef(TypesV68); |
329 | return ArrayRef(Types); |
330 | } |
331 | |
332 | bool isHVXElementType(MVT Ty, bool IncludeBool = false) const; |
333 | bool isHVXVectorType(EVT VecTy, bool IncludeBool = false) const; |
334 | bool isTypeForHVX(Type *VecTy, bool IncludeBool = false) const; |
335 | |
336 | Align getTypeAlignment(MVT Ty) const { |
337 | if (isHVXVectorType(VecTy: Ty, IncludeBool: true)) |
338 | return Align(getVectorLength()); |
339 | return Align(std::max<unsigned>(a: 1, b: Ty.getSizeInBits() / 8)); |
340 | } |
341 | |
342 | unsigned getL1CacheLineSize() const; |
343 | unsigned getL1PrefetchDistance() const; |
344 | |
345 | Intrinsic::ID getIntrinsicId(unsigned Opc) const; |
346 | |
347 | private: |
348 | // Helper function responsible for increasing the latency only. |
349 | int updateLatency(MachineInstr &SrcInst, MachineInstr &DstInst, |
350 | bool IsArtificial, int Latency) const; |
351 | void restoreLatency(SUnit *Src, SUnit *Dst) const; |
352 | void changeLatency(SUnit *Src, SUnit *Dst, unsigned Lat) const; |
353 | bool isBestZeroLatency(SUnit *Src, SUnit *Dst, const HexagonInstrInfo *TII, |
354 | SmallSet<SUnit*, 4> &ExclSrc, SmallSet<SUnit*, 4> &ExclDst) const; |
355 | }; |
356 | |
357 | } // end namespace llvm |
358 | |
359 | #endif // LLVM_LIB_TARGET_HEXAGON_HEXAGONSUBTARGET_H |
360 | |