1 //===--- InfoByHwMode.h -----------------------------------------*- 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 // Classes that implement data parameterized by HW modes for instruction
9 // selection. Currently it is ValueTypeByHwMode (parameterized ValueType),
10 // and RegSizeInfoByHwMode (parameterized register/spill size and alignment
11 // data).
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_UTILS_TABLEGEN_INFOBYHWMODE_H
15 #define LLVM_UTILS_TABLEGEN_INFOBYHWMODE_H
16 
17 #include "CodeGenHwModes.h"
18 #include "llvm/ADT/SmallSet.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/CodeGen/MachineValueType.h"
22 #include "llvm/Support/Compiler.h"
23 #include <cassert>
24 #include <limits>
25 #include <map>
26 #include <string>
27 #include <tuple>
28 #include <utility>
29 
30 namespace llvm {
31 
32 class Record;
33 class raw_ostream;
34 
35 template <typename InfoT> struct InfoByHwMode;
36 
37 std::string getModeName(unsigned Mode);
38 
39 enum : unsigned {
40   DefaultMode = CodeGenHwModes::DefaultMode,
41 };
42 
43 template <typename InfoT>
44 void union_modes(const InfoByHwMode<InfoT> &A,
45                  const InfoByHwMode<InfoT> &B,
46                  SmallVectorImpl<unsigned> &Modes) {
47   auto AI = A.begin();
48   auto BI = B.begin();
49 
50   // Skip default mode, but remember if we had one.
51   bool HasDefault = false;
52   if (AI != A.end() && AI->first == DefaultMode) {
53     HasDefault = true;
54     ++AI;
55   }
56   if (BI != B.end() && BI->first == DefaultMode) {
57     HasDefault = true;
58     ++BI;
59   }
60 
61   while (AI != A.end()) {
62     // If we're done with B, finish A.
63     if (BI == B.end()) {
64       for (; AI != A.end(); ++AI)
65         Modes.push_back(AI->first);
66       break;
67     }
68 
69     if (BI->first < AI->first) {
70       Modes.push_back(BI->first);
71       ++BI;
72     } else {
73       Modes.push_back(AI->first);
74       if (AI->first == BI->first)
75         ++BI;
76       ++AI;
77     }
78   }
79 
80   // Finish B.
81   for (; BI != B.end(); ++BI)
82     Modes.push_back(BI->first);
83 
84   // Make sure that the default mode is last on the list.
85   if (HasDefault)
86     Modes.push_back(DefaultMode);
87 }
88 
89 template <typename InfoT>
90 struct InfoByHwMode {
91   typedef std::map<unsigned,InfoT> MapType;
92   typedef typename MapType::value_type PairType;
93   typedef typename MapType::iterator iterator;
94   typedef typename MapType::const_iterator const_iterator;
95 
96   InfoByHwMode() = default;
97   InfoByHwMode(const MapType &M) : Map(M) {}
98 
99   LLVM_ATTRIBUTE_ALWAYS_INLINE
100   iterator begin() { return Map.begin(); }
101   LLVM_ATTRIBUTE_ALWAYS_INLINE
102   iterator end()   { return Map.end(); }
103   LLVM_ATTRIBUTE_ALWAYS_INLINE
104   const_iterator begin() const { return Map.begin(); }
105   LLVM_ATTRIBUTE_ALWAYS_INLINE
106   const_iterator end() const   { return Map.end(); }
107   LLVM_ATTRIBUTE_ALWAYS_INLINE
108   bool empty() const { return Map.empty(); }
109 
110   LLVM_ATTRIBUTE_ALWAYS_INLINE
111   bool hasMode(unsigned M) const { return Map.find(M) != Map.end(); }
112   LLVM_ATTRIBUTE_ALWAYS_INLINE
113   bool hasDefault() const {
114     return !Map.empty() && Map.begin()->first == DefaultMode;
115   }
116 
117   InfoT &get(unsigned Mode) {
118     auto F = Map.find(Mode);
119     if (F != Map.end())
120       return F->second;
121 
122     // Copy and insert the default mode which should be first.
123     assert(hasDefault());
124     auto P = Map.insert({Mode, Map.begin()->second});
125     return P.first->second;
126   }
127   const InfoT &get(unsigned Mode) const {
128     auto F = Map.find(Mode);
129     if (F != Map.end())
130       return F->second;
131     // Get the default mode which should be first.
132     F = Map.begin();
133     assert(F != Map.end() && F->first == DefaultMode);
134     return F->second;
135   }
136 
137   LLVM_ATTRIBUTE_ALWAYS_INLINE
138   bool isSimple() const {
139     return Map.size() == 1 && Map.begin()->first == DefaultMode;
140   }
141   LLVM_ATTRIBUTE_ALWAYS_INLINE
142   const InfoT &getSimple() const {
143     assert(isSimple());
144     return Map.begin()->second;
145   }
146   void makeSimple(unsigned Mode) {
147     assert(hasMode(Mode) || hasDefault());
148     InfoT I = get(Mode);
149     Map.clear();
150     Map.insert(std::make_pair(DefaultMode, I));
151   }
152 
153 protected:
154   MapType Map;
155 };
156 
157 struct ValueTypeByHwMode : public InfoByHwMode<MVT> {
158   ValueTypeByHwMode(Record *R, const CodeGenHwModes &CGH);
159   ValueTypeByHwMode(Record *R, MVT T);
160   ValueTypeByHwMode(MVT T) { Map.insert({DefaultMode,T}); }
161   ValueTypeByHwMode() = default;
162 
163   bool operator== (const ValueTypeByHwMode &T) const;
164   bool operator< (const ValueTypeByHwMode &T) const;
165 
166   bool isValid() const {
167     return !Map.empty();
168   }
169   MVT getType(unsigned Mode) const { return get(Mode); }
170   MVT &getOrCreateTypeForMode(unsigned Mode, MVT Type);
171 
172   static StringRef getMVTName(MVT T);
173   void writeToStream(raw_ostream &OS) const;
174   void dump() const;
175 
176   unsigned PtrAddrSpace = std::numeric_limits<unsigned>::max();
177   bool isPointer() const {
178     return PtrAddrSpace != std::numeric_limits<unsigned>::max();
179   }
180 };
181 
182 ValueTypeByHwMode getValueTypeByHwMode(Record *Rec,
183                                        const CodeGenHwModes &CGH);
184 
185 struct RegSizeInfo {
186   unsigned RegSize;
187   unsigned SpillSize;
188   unsigned SpillAlignment;
189 
190   RegSizeInfo(Record *R, const CodeGenHwModes &CGH);
191   RegSizeInfo() = default;
192   bool operator< (const RegSizeInfo &I) const;
193   bool operator== (const RegSizeInfo &I) const {
194     return std::tie(RegSize, SpillSize, SpillAlignment) ==
195            std::tie(I.RegSize, I.SpillSize, I.SpillAlignment);
196   }
197   bool operator!= (const RegSizeInfo &I) const {
198     return !(*this == I);
199   }
200 
201   bool isSubClassOf(const RegSizeInfo &I) const;
202   void writeToStream(raw_ostream &OS) const;
203 };
204 
205 struct RegSizeInfoByHwMode : public InfoByHwMode<RegSizeInfo> {
206   RegSizeInfoByHwMode(Record *R, const CodeGenHwModes &CGH);
207   RegSizeInfoByHwMode() = default;
208   bool operator< (const RegSizeInfoByHwMode &VI) const;
209   bool operator== (const RegSizeInfoByHwMode &VI) const;
210   bool operator!= (const RegSizeInfoByHwMode &VI) const {
211     return !(*this == VI);
212   }
213 
214   bool isSubClassOf(const RegSizeInfoByHwMode &I) const;
215   bool hasStricterSpillThan(const RegSizeInfoByHwMode &I) const;
216 
217   void writeToStream(raw_ostream &OS) const;
218 
219   void insertRegSizeForMode(unsigned Mode, RegSizeInfo Info) {
220     Map.insert(std::make_pair(Mode, Info));
221   }
222 };
223 
224 raw_ostream &operator<<(raw_ostream &OS, const ValueTypeByHwMode &T);
225 raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfo &T);
226 raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfoByHwMode &T);
227 
228 struct EncodingInfoByHwMode : public InfoByHwMode<Record*> {
229   EncodingInfoByHwMode(Record *R, const CodeGenHwModes &CGH);
230   EncodingInfoByHwMode() = default;
231 };
232 
233 } // namespace llvm
234 
235 #endif // LLVM_UTILS_TABLEGEN_INFOBYHWMODE_H
236