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 GET_SUBTARGETINFO_HEADER 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 getTargetTriple()114 const Triple &getTargetTriple() const { return TargetTriple; } isEnvironmentMusl()115 bool isEnvironmentMusl() const { 116 return TargetTriple.getEnvironment() == Triple::Musl; 117 } 118 119 /// getInstrItins - Return the instruction itineraries based on subtarget 120 /// selection. getInstrItineraryData()121 const InstrItineraryData *getInstrItineraryData() const override { 122 return &InstrItins; 123 } getInstrInfo()124 const HexagonInstrInfo *getInstrInfo() const override { return &InstrInfo; } getRegisterInfo()125 const HexagonRegisterInfo *getRegisterInfo() const override { 126 return &RegInfo; 127 } getTargetLowering()128 const HexagonTargetLowering *getTargetLowering() const override { 129 return &TLInfo; 130 } getFrameLowering()131 const HexagonFrameLowering *getFrameLowering() const override { 132 return &FrameLowering; 133 } getSelectionDAGInfo()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 isXRaySupported()145 bool isXRaySupported() const override { return true; } 146 hasV5Ops()147 bool hasV5Ops() const { 148 return getHexagonArchVersion() >= Hexagon::ArchEnum::V5; 149 } hasV5OpsOnly()150 bool hasV5OpsOnly() const { 151 return getHexagonArchVersion() == Hexagon::ArchEnum::V5; 152 } hasV55Ops()153 bool hasV55Ops() const { 154 return getHexagonArchVersion() >= Hexagon::ArchEnum::V55; 155 } hasV55OpsOnly()156 bool hasV55OpsOnly() const { 157 return getHexagonArchVersion() == Hexagon::ArchEnum::V55; 158 } hasV60Ops()159 bool hasV60Ops() const { 160 return getHexagonArchVersion() >= Hexagon::ArchEnum::V60; 161 } hasV60OpsOnly()162 bool hasV60OpsOnly() const { 163 return getHexagonArchVersion() == Hexagon::ArchEnum::V60; 164 } hasV62Ops()165 bool hasV62Ops() const { 166 return getHexagonArchVersion() >= Hexagon::ArchEnum::V62; 167 } hasV62OpsOnly()168 bool hasV62OpsOnly() const { 169 return getHexagonArchVersion() == Hexagon::ArchEnum::V62; 170 } hasV65Ops()171 bool hasV65Ops() const { 172 return getHexagonArchVersion() >= Hexagon::ArchEnum::V65; 173 } hasV65OpsOnly()174 bool hasV65OpsOnly() const { 175 return getHexagonArchVersion() == Hexagon::ArchEnum::V65; 176 } hasV66Ops()177 bool hasV66Ops() const { 178 return getHexagonArchVersion() >= Hexagon::ArchEnum::V66; 179 } hasV66OpsOnly()180 bool hasV66OpsOnly() const { 181 return getHexagonArchVersion() == Hexagon::ArchEnum::V66; 182 } hasV67Ops()183 bool hasV67Ops() const { 184 return getHexagonArchVersion() >= Hexagon::ArchEnum::V67; 185 } hasV67OpsOnly()186 bool hasV67OpsOnly() const { 187 return getHexagonArchVersion() == Hexagon::ArchEnum::V67; 188 } hasV68Ops()189 bool hasV68Ops() const { 190 return getHexagonArchVersion() >= Hexagon::ArchEnum::V68; 191 } hasV68OpsOnly()192 bool hasV68OpsOnly() const { 193 return getHexagonArchVersion() == Hexagon::ArchEnum::V68; 194 } hasV69Ops()195 bool hasV69Ops() const { 196 return getHexagonArchVersion() >= Hexagon::ArchEnum::V69; 197 } hasV69OpsOnly()198 bool hasV69OpsOnly() const { 199 return getHexagonArchVersion() == Hexagon::ArchEnum::V69; 200 } hasV71Ops()201 bool hasV71Ops() const { 202 return getHexagonArchVersion() >= Hexagon::ArchEnum::V71; 203 } hasV71OpsOnly()204 bool hasV71OpsOnly() const { 205 return getHexagonArchVersion() == Hexagon::ArchEnum::V71; 206 } hasV73Ops()207 bool hasV73Ops() const { 208 return getHexagonArchVersion() >= Hexagon::ArchEnum::V73; 209 } hasV73OpsOnly()210 bool hasV73OpsOnly() const { 211 return getHexagonArchVersion() == Hexagon::ArchEnum::V73; 212 } 213 useAudioOps()214 bool useAudioOps() const { return UseAudioOps; } useCompound()215 bool useCompound() const { return UseCompound; } useLongCalls()216 bool useLongCalls() const { return UseLongCalls; } useMemops()217 bool useMemops() const { return UseMemops; } usePackets()218 bool usePackets() const { return UsePackets; } useNewValueJumps()219 bool useNewValueJumps() const { return UseNewValueJumps; } useNewValueStores()220 bool useNewValueStores() const { return UseNewValueStores; } useSmallData()221 bool useSmallData() const { return UseSmallData; } useUnsafeMath()222 bool useUnsafeMath() const { return UseUnsafeMath; } useZRegOps()223 bool useZRegOps() const { return UseZRegOps; } useCabac()224 bool useCabac() const { return UseCabac; } 225 isTinyCore()226 bool isTinyCore() const { return HexagonProcFamily == TinyCore; } isTinyCoreWithDuplex()227 bool isTinyCoreWithDuplex() const { return isTinyCore() && EnableDuplex; } 228 useHVXIEEEFPOps()229 bool useHVXIEEEFPOps() const { return UseHVXIEEEFPOps && useHVXOps(); } useHVXQFloatOps()230 bool useHVXQFloatOps() const { 231 return UseHVXQFloatOps && HexagonHVXVersion >= Hexagon::ArchEnum::V68; 232 } useHVXFloatingPoint()233 bool useHVXFloatingPoint() const { return UseHVXFloatingPoint; } useHVXOps()234 bool useHVXOps() const { 235 return HexagonHVXVersion > Hexagon::ArchEnum::NoArch; 236 } useHVXV60Ops()237 bool useHVXV60Ops() const { 238 return HexagonHVXVersion >= Hexagon::ArchEnum::V60; 239 } useHVXV62Ops()240 bool useHVXV62Ops() const { 241 return HexagonHVXVersion >= Hexagon::ArchEnum::V62; 242 } useHVXV65Ops()243 bool useHVXV65Ops() const { 244 return HexagonHVXVersion >= Hexagon::ArchEnum::V65; 245 } useHVXV66Ops()246 bool useHVXV66Ops() const { 247 return HexagonHVXVersion >= Hexagon::ArchEnum::V66; 248 } useHVXV67Ops()249 bool useHVXV67Ops() const { 250 return HexagonHVXVersion >= Hexagon::ArchEnum::V67; 251 } useHVXV68Ops()252 bool useHVXV68Ops() const { 253 return HexagonHVXVersion >= Hexagon::ArchEnum::V68; 254 } useHVXV69Ops()255 bool useHVXV69Ops() const { 256 return HexagonHVXVersion >= Hexagon::ArchEnum::V69; 257 } useHVXV71Ops()258 bool useHVXV71Ops() const { 259 return HexagonHVXVersion >= Hexagon::ArchEnum::V71; 260 } useHVXV73Ops()261 bool useHVXV73Ops() const { 262 return HexagonHVXVersion >= Hexagon::ArchEnum::V73; 263 } useHVX128BOps()264 bool useHVX128BOps() const { return useHVXOps() && UseHVX128BOps; } useHVX64BOps()265 bool useHVX64BOps() const { return useHVXOps() && UseHVX64BOps; } 266 hasMemNoShuf()267 bool hasMemNoShuf() const { return HasMemNoShuf; } hasReservedR19()268 bool hasReservedR19() const { return ReservedR19; } 269 bool usePredicatedCalls() const; 270 noreturnStackElim()271 bool noreturnStackElim() const { return NoreturnStackElim; } 272 useBSBScheduling()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. enableMachineSchedDefaultSched()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. getAntiDepBreakMode()283 AntiDepBreakMode getAntiDepBreakMode() const override { return ANTIDEP_ALL; } 284 /// True if the subtarget should run a scheduler after register 285 /// allocation. enablePostRAScheduler()286 bool enablePostRAScheduler() const override { return true; } 287 288 bool enableSubRegLiveness() const override; 289 getCPUString()290 const std::string &getCPUString () const { return CPUString; } 291 getHexagonArchVersion()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 getVectorLength()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 getHVXElementTypes()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 getTypeAlignment(MVT Ty)336 Align getTypeAlignment(MVT Ty) const { 337 if (isHVXVectorType(Ty, true)) 338 return Align(getVectorLength()); 339 return Align(std::max<unsigned>(1, 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