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