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