blob: 025cee3b2b909e71905215dd47fccf44637358e0 [file] [log] [blame]
Vyacheslav Klochkov6daefcf2016-08-11 22:07:33 +00001//===-- X86InstrFMA3Info.h - X86 FMA3 Instruction Information -------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file contains the implementation of the classes providing information
11// about existing X86 FMA3 opcodes, classifying and grouping them.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_LIB_TARGET_X86_UTILS_X86INSTRFMA3INFO_H
16#define LLVM_LIB_TARGET_X86_UTILS_X86INSTRFMA3INFO_H
17
18#include "X86.h"
19#include "llvm/ADT/DenseMap.h"
20#include <cassert>
21#include <set>
22
Benjamin Kramer4c2582a2016-10-18 19:39:31 +000023namespace llvm {
Vyacheslav Klochkov6daefcf2016-08-11 22:07:33 +000024/// This class is used to group {132, 213, 231} forms of FMA opcodes together.
25/// Each of the groups has either 3 register opcodes, 3 memory opcodes,
26/// or 6 register and memory opcodes. Also, each group has an attrubutes field
27/// describing it.
28class X86InstrFMA3Group {
29private:
30 /// Reference to an array holding 3 forms of register FMA opcodes.
31 /// It may be set to nullptr if the group of FMA opcodes does not have
32 /// any register form opcodes.
33 const uint16_t *RegOpcodes;
34
35 /// Reference to an array holding 3 forms of memory FMA opcodes.
36 /// It may be set to nullptr if the group of FMA opcodes does not have
37 /// any register form opcodes.
38 const uint16_t *MemOpcodes;
39
40 /// This bitfield specifies the attributes associated with the created
41 /// FMA groups of opcodes.
42 unsigned Attributes;
43
44 static const unsigned Form132 = 0;
45 static const unsigned Form213 = 1;
46 static const unsigned Form231 = 2;
47
48public:
49 /// This bit must be set in the 'Attributes' field of FMA group if such
50 /// group of FMA opcodes consists of FMA intrinsic opcodes.
51 static const unsigned X86FMA3Intrinsic = 0x1;
52
53 /// This bit must be set in the 'Attributes' field of FMA group if such
54 /// group of FMA opcodes consists of AVX512 opcodes accepting a k-mask and
55 /// passing the elements from the 1st operand to the result of the operation
56 /// when the correpondings bits in the k-mask are unset.
57 static const unsigned X86FMA3KMergeMasked = 0x2;
58
59 /// This bit must be set in the 'Attributes' field of FMA group if such
60 /// group of FMA opcodes consists of AVX512 opcodes accepting a k-zeromask.
61 static const unsigned X86FMA3KZeroMasked = 0x4;
62
63 /// Constructor. Creates a new group of FMA opcodes with three register form
64 /// FMA opcodes \p RegOpcodes and three memory form FMA opcodes \p MemOpcodes.
65 /// The parameters \p RegOpcodes and \p MemOpcodes may be set to nullptr,
66 /// which means that the created group of FMA opcodes does not have the
67 /// corresponding (register or memory) opcodes.
68 /// The parameter \p Attr specifies the attributes describing the created
69 /// group.
70 X86InstrFMA3Group(const uint16_t *RegOpcodes, const uint16_t *MemOpcodes,
71 unsigned Attr)
72 : RegOpcodes(RegOpcodes), MemOpcodes(MemOpcodes), Attributes(Attr) {
73 assert((RegOpcodes || MemOpcodes) &&
74 "Cannot create a group not having any opcodes.");
75 }
76
77 /// Returns a memory form opcode that is the equivalent of the given register
78 /// form opcode \p RegOpcode. 0 is returned if the group does not have
79 /// either register of memory opcodes.
80 unsigned getMemOpcode(unsigned RegOpcode) const {
81 if (!RegOpcodes || !MemOpcodes)
82 return 0;
83 for (unsigned Form = 0; Form < 3; Form++)
84 if (RegOpcodes[Form] == RegOpcode)
85 return MemOpcodes[Form];
86 return 0;
87 }
88
89 /// Returns the 132 form of FMA register opcode.
90 unsigned getReg132Opcode() const {
91 assert(RegOpcodes && "The group does not have register opcodes.");
92 return RegOpcodes[Form132];
93 }
94
95 /// Returns the 213 form of FMA register opcode.
96 unsigned getReg213Opcode() const {
97 assert(RegOpcodes && "The group does not have register opcodes.");
98 return RegOpcodes[Form213];
99 }
100
101 /// Returns the 231 form of FMA register opcode.
102 unsigned getReg231Opcode() const {
103 assert(RegOpcodes && "The group does not have register opcodes.");
104 return RegOpcodes[Form231];
105 }
106
107 /// Returns the 132 form of FMA memory opcode.
108 unsigned getMem132Opcode() const {
109 assert(MemOpcodes && "The group does not have memory opcodes.");
110 return MemOpcodes[Form132];
111 }
112
113 /// Returns the 213 form of FMA memory opcode.
114 unsigned getMem213Opcode() const {
115 assert(MemOpcodes && "The group does not have memory opcodes.");
116 return MemOpcodes[Form213];
117 }
118
119 /// Returns the 231 form of FMA memory opcode.
120 unsigned getMem231Opcode() const {
121 assert(MemOpcodes && "The group does not have memory opcodes.");
122 return MemOpcodes[Form231];
123 }
124
125 /// Returns true iff the group of FMA opcodes holds intrinsic opcodes.
126 bool isIntrinsic() const { return (Attributes & X86FMA3Intrinsic) != 0; }
127
128 /// Returns true iff the group of FMA opcodes holds k-merge-masked opcodes.
129 bool isKMergeMasked() const {
130 return (Attributes & X86FMA3KMergeMasked) != 0;
131 }
132
133 /// Returns true iff the group of FMA opcodes holds k-zero-masked opcodes.
134 bool isKZeroMasked() const { return (Attributes & X86FMA3KZeroMasked) != 0; }
135
136 /// Returns true iff the group of FMA opcodes holds any of k-masked opcodes.
137 bool isKMasked() const {
138 return (Attributes & (X86FMA3KMergeMasked | X86FMA3KZeroMasked)) != 0;
139 }
140
141 /// Returns true iff the given \p Opcode is a register opcode from the
142 /// groups of FMA opcodes.
143 bool isRegOpcodeFromGroup(unsigned Opcode) const {
144 if (!RegOpcodes)
145 return false;
146 for (unsigned Form = 0; Form < 3; Form++)
147 if (Opcode == RegOpcodes[Form])
148 return true;
149 return false;
150 }
151
152 /// Returns true iff the given \p Opcode is a memory opcode from the
153 /// groups of FMA opcodes.
154 bool isMemOpcodeFromGroup(unsigned Opcode) const {
155 if (!MemOpcodes)
156 return false;
157 for (unsigned Form = 0; Form < 3; Form++)
158 if (Opcode == MemOpcodes[Form])
159 return true;
160 return false;
161 }
162};
163
164/// This class provides information about all existing FMA3 opcodes
165///
166class X86InstrFMA3Info {
167private:
168 /// A map that is used to find the group of FMA opcodes using any FMA opcode
169 /// from the group.
170 DenseMap<unsigned, const X86InstrFMA3Group *> OpcodeToGroup;
171
172 /// Creates groups of FMA opcodes and initializes Opcode-to-Group map.
173 /// This method can be called many times, but the actual initialization is
174 /// called only once.
175 static void initGroupsOnce();
176
177 /// Creates groups of FMA opcodes and initializes Opcode-to-Group map.
178 /// This method must be called ONLY from initGroupsOnce(). Otherwise, such
179 /// call is not thread safe.
180 void initGroupsOnceImpl();
181
182 /// Creates one group of FMA opcodes having the register opcodes
183 /// \p RegOpcodes and memory opcodes \p MemOpcodes. The parameter \p Attr
184 /// specifies the attributes describing the created group.
185 void initRMGroup(const uint16_t *RegOpcodes,
186 const uint16_t *MemOpcodes, unsigned Attr = 0);
187
188 /// Creates one group of FMA opcodes having only the register opcodes
189 /// \p RegOpcodes. The parameter \p Attr specifies the attributes describing
190 /// the created group.
191 void initRGroup(const uint16_t *RegOpcodes, unsigned Attr = 0);
192
193 /// Creates one group of FMA opcodes having only the memory opcodes
194 /// \p MemOpcodes. The parameter \p Attr specifies the attributes describing
195 /// the created group.
196 void initMGroup(const uint16_t *MemOpcodes, unsigned Attr = 0);
197
198public:
199 /// Returns the reference to an object of this class. It is assumed that
200 /// only one object may exist.
201 static X86InstrFMA3Info *getX86InstrFMA3Info();
202
203 /// Constructor. Just creates an object of the class.
204 X86InstrFMA3Info() {}
205
206 /// Destructor. Deallocates the memory used for FMA3 Groups.
207 ~X86InstrFMA3Info() {
208 std::set<const X86InstrFMA3Group *> DeletedGroups;
209 auto E = OpcodeToGroup.end();
210 for (auto I = OpcodeToGroup.begin(); I != E; I++) {
211 const X86InstrFMA3Group *G = I->second;
212 if (DeletedGroups.find(G) == DeletedGroups.end()) {
213 DeletedGroups.insert(G);
214 delete G;
215 }
216 }
217 }
218
219 /// Returns a reference to a group of FMA3 opcodes to where the given
220 /// \p Opcode is included. If the given \p Opcode is not recognized as FMA3
221 /// and not included into any FMA3 group, then nullptr is returned.
222 static const X86InstrFMA3Group *getFMA3Group(unsigned Opcode) {
223 // Ensure that the groups of opcodes are initialized.
224 initGroupsOnce();
225
226 // Find the group including the given opcode.
227 const X86InstrFMA3Info *FMA3Info = getX86InstrFMA3Info();
228 auto I = FMA3Info->OpcodeToGroup.find(Opcode);
229 if (I == FMA3Info->OpcodeToGroup.end())
230 return nullptr;
231
232 return I->second;
233 }
234
235 /// Returns true iff the given \p Opcode is recognized as FMA3 by this class.
236 static bool isFMA3(unsigned Opcode) {
237 return getFMA3Group(Opcode) != nullptr;
238 }
239
240 /// Iterator that is used to walk on FMA register opcodes having memory
241 /// form equivalents.
242 class rm_iterator {
243 private:
244 /// Iterator associated with the OpcodeToGroup map. It must always be
245 /// initialized with an entry from OpcodeToGroup for which I->first
246 /// points to a register FMA opcode and I->second points to a group of
247 /// FMA opcodes having memory form equivalent of I->first.
248 DenseMap<unsigned, const X86InstrFMA3Group *>::const_iterator I;
249
250 public:
251 /// Constructor. Creates rm_iterator. The parameter \p I must be an
252 /// iterator to OpcodeToGroup map entry having I->first pointing to
253 /// register form FMA opcode and I->second pointing to a group of FMA
254 /// opcodes holding memory form equivalent for I->fist.
255 rm_iterator(DenseMap<unsigned, const X86InstrFMA3Group *>::const_iterator I)
256 : I(I) {}
257
258 /// Returns the register form FMA opcode.
259 unsigned getRegOpcode() const { return I->first; };
260
261 /// Returns the memory form equivalent opcode for FMA register opcode
262 /// referenced by I->first.
263 unsigned getMemOpcode() const {
264 unsigned Opcode = I->first;
265 const X86InstrFMA3Group *Group = I->second;
266 return Group->getMemOpcode(Opcode);
267 }
268
269 /// Returns a reference to a group of FMA opcodes.
270 const X86InstrFMA3Group *getGroup() const { return I->second; }
271
272 bool operator==(const rm_iterator &OtherIt) const { return I == OtherIt.I; }
273 bool operator!=(const rm_iterator &OtherIt) const { return I != OtherIt.I; }
274
275 /// Increment. Advances the 'I' iterator to the next OpcodeToGroup entry
276 /// having I->first pointing to register form FMA and I->second pointing
277 /// to a group of FMA opcodes holding memory form equivalen for I->first.
278 rm_iterator &operator++() {
279 auto E = getX86InstrFMA3Info()->OpcodeToGroup.end();
280 for (++I; I != E; ++I) {
281 unsigned RegOpcode = I->first;
282 const X86InstrFMA3Group *Group = I->second;
283 if (Group->getMemOpcode(RegOpcode) != 0)
284 break;
285 }
286 return *this;
287 }
288 };
289
290 /// Returns rm_iterator pointing to the first entry of OpcodeToGroup map
291 /// with a register FMA opcode having memory form opcode equivalent.
292 static rm_iterator rm_begin() {
293 initGroupsOnce();
294 const X86InstrFMA3Info *FMA3Info = getX86InstrFMA3Info();
295 auto I = FMA3Info->OpcodeToGroup.begin();
296 auto E = FMA3Info->OpcodeToGroup.end();
297 while (I != E) {
298 unsigned Opcode = I->first;
299 const X86InstrFMA3Group *G = I->second;
300 if (G->getMemOpcode(Opcode) != 0)
301 break;
302 I++;
303 }
304 return rm_iterator(I);
305 }
306
307 /// Returns the last rm_iterator.
308 static rm_iterator rm_end() {
309 initGroupsOnce();
310 return rm_iterator(getX86InstrFMA3Info()->OpcodeToGroup.end());
311 }
312};
Benjamin Kramer4c2582a2016-10-18 19:39:31 +0000313} // namespace llvm
Vyacheslav Klochkov6daefcf2016-08-11 22:07:33 +0000314
315#endif