1 //===- llvm/MC/MCSubtargetInfo.h - Subtarget Information --------*- 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 describes the subtarget options of a Target machine.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_MC_MCSUBTARGETINFO_H
14 #define LLVM_MC_MCSUBTARGETINFO_H
15 
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/ADT/Triple.h"
19 #include "llvm/MC/MCInstrItineraries.h"
20 #include "llvm/MC/MCSchedule.h"
21 #include "llvm/MC/SubtargetFeature.h"
22 #include <algorithm>
23 #include <cassert>
24 #include <cstdint>
25 #include <string>
26 
27 namespace llvm {
28 
29 class MCInst;
30 
31 //===----------------------------------------------------------------------===//
32 
33 /// Used to provide key value pairs for feature and CPU bit flags.
34 struct SubtargetFeatureKV {
35   const char *Key;                      ///< K-V key string
36   const char *Desc;                     ///< Help descriptor
37   unsigned Value;                       ///< K-V integer value
38   FeatureBitArray Implies;              ///< K-V bit mask
39 
40   /// Compare routine for std::lower_bound
41   bool operator<(StringRef S) const {
42     return StringRef(Key) < S;
43   }
44 
45   /// Compare routine for std::is_sorted.
46   bool operator<(const SubtargetFeatureKV &Other) const {
47     return StringRef(Key) < StringRef(Other.Key);
48   }
49 };
50 
51 //===----------------------------------------------------------------------===//
52 
53 /// Used to provide key value pairs for feature and CPU bit flags.
54 struct SubtargetSubTypeKV {
55   const char *Key;                      ///< K-V key string
56   FeatureBitArray Implies;              ///< K-V bit mask
57   const MCSchedModel *SchedModel;
58 
59   /// Compare routine for std::lower_bound
60   bool operator<(StringRef S) const {
61     return StringRef(Key) < S;
62   }
63 
64   /// Compare routine for std::is_sorted.
65   bool operator<(const SubtargetSubTypeKV &Other) const {
66     return StringRef(Key) < StringRef(Other.Key);
67   }
68 };
69 
70 //===----------------------------------------------------------------------===//
71 ///
72 /// Generic base class for all target subtargets.
73 ///
74 class MCSubtargetInfo {
75   Triple TargetTriple;
76   std::string CPU; // CPU being targeted.
77   ArrayRef<SubtargetFeatureKV> ProcFeatures;  // Processor feature list
78   ArrayRef<SubtargetSubTypeKV> ProcDesc;  // Processor descriptions
79 
80   // Scheduler machine model
81   const MCWriteProcResEntry *WriteProcResTable;
82   const MCWriteLatencyEntry *WriteLatencyTable;
83   const MCReadAdvanceEntry *ReadAdvanceTable;
84   const MCSchedModel *CPUSchedModel;
85 
86   const InstrStage *Stages;            // Instruction itinerary stages
87   const unsigned *OperandCycles;       // Itinerary operand cycles
88   const unsigned *ForwardingPaths;
89   FeatureBitset FeatureBits;           // Feature bits for current CPU + FS
90 
91 public:
92   MCSubtargetInfo(const MCSubtargetInfo &) = default;
93   MCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS,
94                   ArrayRef<SubtargetFeatureKV> PF,
95                   ArrayRef<SubtargetSubTypeKV> PD,
96                   const MCWriteProcResEntry *WPR, const MCWriteLatencyEntry *WL,
97                   const MCReadAdvanceEntry *RA, const InstrStage *IS,
98                   const unsigned *OC, const unsigned *FP);
99   MCSubtargetInfo() = delete;
100   MCSubtargetInfo &operator=(const MCSubtargetInfo &) = delete;
101   MCSubtargetInfo &operator=(MCSubtargetInfo &&) = delete;
102   virtual ~MCSubtargetInfo() = default;
103 
104   const Triple &getTargetTriple() const { return TargetTriple; }
105   StringRef getCPU() const { return CPU; }
106 
107   const FeatureBitset& getFeatureBits() const { return FeatureBits; }
108   void setFeatureBits(const FeatureBitset &FeatureBits_) {
109     FeatureBits = FeatureBits_;
110   }
111 
112   bool hasFeature(unsigned Feature) const {
113     return FeatureBits[Feature];
114   }
115 
116 protected:
117   /// Initialize the scheduling model and feature bits.
118   ///
119   /// FIXME: Find a way to stick this in the constructor, since it should only
120   /// be called during initialization.
121   void InitMCProcessorInfo(StringRef CPU, StringRef FS);
122 
123 public:
124   /// Set the features to the default for the given CPU with an appended feature
125   /// string.
126   void setDefaultFeatures(StringRef CPU, StringRef FS);
127 
128   /// Toggle a feature and return the re-computed feature bits.
129   /// This version does not change the implied bits.
130   FeatureBitset ToggleFeature(uint64_t FB);
131 
132   /// Toggle a feature and return the re-computed feature bits.
133   /// This version does not change the implied bits.
134   FeatureBitset ToggleFeature(const FeatureBitset& FB);
135 
136   /// Toggle a set of features and return the re-computed feature bits.
137   /// This version will also change all implied bits.
138   FeatureBitset ToggleFeature(StringRef FS);
139 
140   /// Apply a feature flag and return the re-computed feature bits, including
141   /// all feature bits implied by the flag.
142   FeatureBitset ApplyFeatureFlag(StringRef FS);
143 
144   /// Set/clear additional feature bits, including all other bits they imply.
145   FeatureBitset SetFeatureBitsTransitively(const FeatureBitset& FB);
146   FeatureBitset ClearFeatureBitsTransitively(const FeatureBitset &FB);
147 
148   /// Check whether the subtarget features are enabled/disabled as per
149   /// the provided string, ignoring all other features.
150   bool checkFeatures(StringRef FS) const;
151 
152   /// Get the machine model of a CPU.
153   const MCSchedModel &getSchedModelForCPU(StringRef CPU) const;
154 
155   /// Get the machine model for this subtarget's CPU.
156   const MCSchedModel &getSchedModel() const { return *CPUSchedModel; }
157 
158   /// Return an iterator at the first process resource consumed by the given
159   /// scheduling class.
160   const MCWriteProcResEntry *getWriteProcResBegin(
161     const MCSchedClassDesc *SC) const {
162     return &WriteProcResTable[SC->WriteProcResIdx];
163   }
164   const MCWriteProcResEntry *getWriteProcResEnd(
165     const MCSchedClassDesc *SC) const {
166     return getWriteProcResBegin(SC) + SC->NumWriteProcResEntries;
167   }
168 
169   const MCWriteLatencyEntry *getWriteLatencyEntry(const MCSchedClassDesc *SC,
170                                                   unsigned DefIdx) const {
171     assert(DefIdx < SC->NumWriteLatencyEntries &&
172            "MachineModel does not specify a WriteResource for DefIdx");
173 
174     return &WriteLatencyTable[SC->WriteLatencyIdx + DefIdx];
175   }
176 
177   int getReadAdvanceCycles(const MCSchedClassDesc *SC, unsigned UseIdx,
178                            unsigned WriteResID) const {
179     // TODO: The number of read advance entries in a class can be significant
180     // (~50). Consider compressing the WriteID into a dense ID of those that are
181     // used by ReadAdvance and representing them as a bitset.
182     for (const MCReadAdvanceEntry *I = &ReadAdvanceTable[SC->ReadAdvanceIdx],
183            *E = I + SC->NumReadAdvanceEntries; I != E; ++I) {
184       if (I->UseIdx < UseIdx)
185         continue;
186       if (I->UseIdx > UseIdx)
187         break;
188       // Find the first WriteResIdx match, which has the highest cycle count.
189       if (!I->WriteResourceID || I->WriteResourceID == WriteResID) {
190         return I->Cycles;
191       }
192     }
193     return 0;
194   }
195 
196   /// Return the set of ReadAdvance entries declared by the scheduling class
197   /// descriptor in input.
198   ArrayRef<MCReadAdvanceEntry>
199   getReadAdvanceEntries(const MCSchedClassDesc &SC) const {
200     if (!SC.NumReadAdvanceEntries)
201       return ArrayRef<MCReadAdvanceEntry>();
202     return ArrayRef<MCReadAdvanceEntry>(&ReadAdvanceTable[SC.ReadAdvanceIdx],
203                                         SC.NumReadAdvanceEntries);
204   }
205 
206   /// Get scheduling itinerary of a CPU.
207   InstrItineraryData getInstrItineraryForCPU(StringRef CPU) const;
208 
209   /// Initialize an InstrItineraryData instance.
210   void initInstrItins(InstrItineraryData &InstrItins) const;
211 
212   /// Resolve a variant scheduling class for the given MCInst and CPU.
213   virtual unsigned
214   resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI,
215                            unsigned CPUID) const {
216     return 0;
217   }
218 
219   /// Check whether the CPU string is valid.
220   bool isCPUStringValid(StringRef CPU) const {
221     auto Found = std::lower_bound(ProcDesc.begin(), ProcDesc.end(), CPU);
222     return Found != ProcDesc.end() && StringRef(Found->Key) == CPU;
223   }
224 };
225 
226 } // end namespace llvm
227 
228 #endif // LLVM_MC_MCSUBTARGETINFO_H
229