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 | bool hasV75Ops() const { |
214 | return getHexagonArchVersion() >= Hexagon::ArchEnum::V75; |
215 | } |
216 | bool hasV75OpsOnly() const { |
217 | return getHexagonArchVersion() == Hexagon::ArchEnum::V75; |
218 | } |
219 | bool hasV79Ops() const { |
220 | return getHexagonArchVersion() >= Hexagon::ArchEnum::V79; |
221 | } |
222 | bool hasV79OpsOnly() const { |
223 | return getHexagonArchVersion() == Hexagon::ArchEnum::V79; |
224 | } |
225 | bool useHVXV79Ops() const { |
226 | return HexagonHVXVersion >= Hexagon::ArchEnum::V79; |
227 | } |
228 | |
229 | bool useAudioOps() const { return UseAudioOps; } |
230 | bool useCompound() const { return UseCompound; } |
231 | bool useLongCalls() const { return UseLongCalls; } |
232 | bool useMemops() const { return UseMemops; } |
233 | bool usePackets() const { return UsePackets; } |
234 | bool useNewValueJumps() const { return UseNewValueJumps; } |
235 | bool useNewValueStores() const { return UseNewValueStores; } |
236 | bool useSmallData() const { return UseSmallData; } |
237 | bool useUnsafeMath() const { return UseUnsafeMath; } |
238 | bool useZRegOps() const { return UseZRegOps; } |
239 | bool useCabac() const { return UseCabac; } |
240 | |
241 | bool isTinyCore() const { return HexagonProcFamily == TinyCore; } |
242 | bool isTinyCoreWithDuplex() const { return isTinyCore() && EnableDuplex; } |
243 | |
244 | bool useHVXIEEEFPOps() const { return UseHVXIEEEFPOps && useHVXOps(); } |
245 | bool useHVXQFloatOps() const { |
246 | return UseHVXQFloatOps && HexagonHVXVersion >= Hexagon::ArchEnum::V68; |
247 | } |
248 | bool useHVXFloatingPoint() const { return UseHVXFloatingPoint; } |
249 | bool useHVXOps() const { |
250 | return HexagonHVXVersion > Hexagon::ArchEnum::NoArch; |
251 | } |
252 | bool useHVXV60Ops() const { |
253 | return HexagonHVXVersion >= Hexagon::ArchEnum::V60; |
254 | } |
255 | bool useHVXV62Ops() const { |
256 | return HexagonHVXVersion >= Hexagon::ArchEnum::V62; |
257 | } |
258 | bool useHVXV65Ops() const { |
259 | return HexagonHVXVersion >= Hexagon::ArchEnum::V65; |
260 | } |
261 | bool useHVXV66Ops() const { |
262 | return HexagonHVXVersion >= Hexagon::ArchEnum::V66; |
263 | } |
264 | bool useHVXV67Ops() const { |
265 | return HexagonHVXVersion >= Hexagon::ArchEnum::V67; |
266 | } |
267 | bool useHVXV68Ops() const { |
268 | return HexagonHVXVersion >= Hexagon::ArchEnum::V68; |
269 | } |
270 | bool useHVXV69Ops() const { |
271 | return HexagonHVXVersion >= Hexagon::ArchEnum::V69; |
272 | } |
273 | bool useHVXV71Ops() const { |
274 | return HexagonHVXVersion >= Hexagon::ArchEnum::V71; |
275 | } |
276 | bool useHVXV73Ops() const { |
277 | return HexagonHVXVersion >= Hexagon::ArchEnum::V73; |
278 | } |
279 | bool useHVX128BOps() const { return useHVXOps() && UseHVX128BOps; } |
280 | bool useHVX64BOps() const { return useHVXOps() && UseHVX64BOps; } |
281 | |
282 | bool hasMemNoShuf() const { return HasMemNoShuf; } |
283 | bool hasReservedR19() const { return ReservedR19; } |
284 | bool usePredicatedCalls() const; |
285 | |
286 | bool noreturnStackElim() const { return NoreturnStackElim; } |
287 | |
288 | bool useBSBScheduling() const { return UseBSBScheduling; } |
289 | bool enableMachineScheduler() const override; |
290 | |
291 | // Always use the TargetLowering default scheduler. |
292 | // FIXME: This will use the vliw scheduler which is probably just hurting |
293 | // compiler time and will be removed eventually anyway. |
294 | bool enableMachineSchedDefaultSched() const override { return false; } |
295 | |
296 | // For use with PostRAScheduling: get the anti-dependence breaking that should |
297 | // be performed before post-RA scheduling. |
298 | AntiDepBreakMode getAntiDepBreakMode() const override { return ANTIDEP_ALL; } |
299 | /// True if the subtarget should run a scheduler after register |
300 | /// allocation. |
301 | bool enablePostRAScheduler() const override { return true; } |
302 | |
303 | bool enableSubRegLiveness() const override; |
304 | |
305 | const std::string &getCPUString () const { return CPUString; } |
306 | |
307 | const Hexagon::ArchEnum &getHexagonArchVersion() const { |
308 | return HexagonArchVersion; |
309 | } |
310 | |
311 | void getPostRAMutations( |
312 | std::vector<std::unique_ptr<ScheduleDAGMutation>> &Mutations) |
313 | const override; |
314 | |
315 | void getSMSMutations( |
316 | std::vector<std::unique_ptr<ScheduleDAGMutation>> &Mutations) |
317 | const override; |
318 | |
319 | /// Enable use of alias analysis during code generation (during MI |
320 | /// scheduling, DAGCombine, etc.). |
321 | bool useAA() const override; |
322 | |
323 | /// Perform target specific adjustments to the latency of a schedule |
324 | /// dependency. |
325 | void adjustSchedDependency(SUnit *Def, int DefOpIdx, SUnit *Use, int UseOpIdx, |
326 | SDep &Dep, |
327 | const TargetSchedModel *SchedModel) const override; |
328 | |
329 | unsigned getVectorLength() const { |
330 | assert(useHVXOps()); |
331 | if (useHVX64BOps()) |
332 | return 64; |
333 | if (useHVX128BOps()) |
334 | return 128; |
335 | llvm_unreachable("Invalid HVX vector length settings" ); |
336 | } |
337 | |
338 | ArrayRef<MVT> getHVXElementTypes() const { |
339 | static MVT Types[] = {MVT::i8, MVT::i16, MVT::i32}; |
340 | static MVT TypesV68[] = {MVT::i8, MVT::i16, MVT::i32, MVT::f16, MVT::f32}; |
341 | |
342 | if (useHVXV68Ops() && useHVXFloatingPoint()) |
343 | return ArrayRef(TypesV68); |
344 | return ArrayRef(Types); |
345 | } |
346 | |
347 | bool isHVXElementType(MVT Ty, bool IncludeBool = false) const; |
348 | bool isHVXVectorType(EVT VecTy, bool IncludeBool = false) const; |
349 | bool isTypeForHVX(Type *VecTy, bool IncludeBool = false) const; |
350 | |
351 | Align getTypeAlignment(MVT Ty) const { |
352 | if (isHVXVectorType(VecTy: Ty, IncludeBool: true)) |
353 | return Align(getVectorLength()); |
354 | return Align(std::max<unsigned>(a: 1, b: Ty.getSizeInBits() / 8)); |
355 | } |
356 | |
357 | unsigned getL1CacheLineSize() const; |
358 | unsigned getL1PrefetchDistance() const; |
359 | |
360 | Intrinsic::ID getIntrinsicId(unsigned Opc) const; |
361 | |
362 | private: |
363 | // Helper function responsible for increasing the latency only. |
364 | int updateLatency(MachineInstr &SrcInst, MachineInstr &DstInst, |
365 | bool IsArtificial, int Latency) const; |
366 | void restoreLatency(SUnit *Src, SUnit *Dst) const; |
367 | void changeLatency(SUnit *Src, SUnit *Dst, unsigned Lat) const; |
368 | bool isBestZeroLatency(SUnit *Src, SUnit *Dst, const HexagonInstrInfo *TII, |
369 | SmallSet<SUnit*, 4> &ExclSrc, SmallSet<SUnit*, 4> &ExclDst) const; |
370 | }; |
371 | |
372 | } // end namespace llvm |
373 | |
374 | #endif // LLVM_LIB_TARGET_HEXAGON_HEXAGONSUBTARGET_H |
375 | |