LLVM 24.0.0git
X86InstrFoldTables.cpp
Go to the documentation of this file.
1//===-- X86InstrFoldTables.cpp - X86 Instruction Folding Tables -----------===//
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 contains the X86 memory folding tables.
10//
11//===----------------------------------------------------------------------===//
12
13#include "X86InstrFoldTables.h"
14#include "X86InstrInfo.h"
15#include "llvm/ADT/STLExtras.h"
16#include <atomic>
17#include <vector>
18
19using namespace llvm;
20
21// These tables are sorted by their RegOp value allowing them to be binary
22// searched at runtime without the need for additional storage. The enum values
23// are currently emitted in X86GenInstrInfo.inc in alphabetical order. Which
24// makes sorting these tables a simple matter of alphabetizing the table.
25#include "X86GenFoldTables.inc"
26
27// Table to map instructions safe to broadcast using a different width from the
28// element width.
30 { X86::VANDNPDZ128rr, X86::VANDNPSZ128rmb, TB_BCAST_SS },
31 { X86::VANDNPDZ256rr, X86::VANDNPSZ256rmb, TB_BCAST_SS },
32 { X86::VANDNPDZrr, X86::VANDNPSZrmb, TB_BCAST_SS },
33 { X86::VANDNPSZ128rr, X86::VANDNPDZ128rmb, TB_BCAST_SD },
34 { X86::VANDNPSZ256rr, X86::VANDNPDZ256rmb, TB_BCAST_SD },
35 { X86::VANDNPSZrr, X86::VANDNPDZrmb, TB_BCAST_SD },
36 { X86::VANDPDZ128rr, X86::VANDPSZ128rmb, TB_BCAST_SS },
37 { X86::VANDPDZ256rr, X86::VANDPSZ256rmb, TB_BCAST_SS },
38 { X86::VANDPDZrr, X86::VANDPSZrmb, TB_BCAST_SS },
39 { X86::VANDPSZ128rr, X86::VANDPDZ128rmb, TB_BCAST_SD },
40 { X86::VANDPSZ256rr, X86::VANDPDZ256rmb, TB_BCAST_SD },
41 { X86::VANDPSZrr, X86::VANDPDZrmb, TB_BCAST_SD },
42 { X86::VORPDZ128rr, X86::VORPSZ128rmb, TB_BCAST_SS },
43 { X86::VORPDZ256rr, X86::VORPSZ256rmb, TB_BCAST_SS },
44 { X86::VORPDZrr, X86::VORPSZrmb, TB_BCAST_SS },
45 { X86::VORPSZ128rr, X86::VORPDZ128rmb, TB_BCAST_SD },
46 { X86::VORPSZ256rr, X86::VORPDZ256rmb, TB_BCAST_SD },
47 { X86::VORPSZrr, X86::VORPDZrmb, TB_BCAST_SD },
48 { X86::VPANDDZ128rr, X86::VPANDQZ128rmb, TB_BCAST_Q },
49 { X86::VPANDDZ256rr, X86::VPANDQZ256rmb, TB_BCAST_Q },
50 { X86::VPANDDZrr, X86::VPANDQZrmb, TB_BCAST_Q },
51 { X86::VPANDNDZ128rr, X86::VPANDNQZ128rmb, TB_BCAST_Q },
52 { X86::VPANDNDZ256rr, X86::VPANDNQZ256rmb, TB_BCAST_Q },
53 { X86::VPANDNDZrr, X86::VPANDNQZrmb, TB_BCAST_Q },
54 { X86::VPANDNQZ128rr, X86::VPANDNDZ128rmb, TB_BCAST_D },
55 { X86::VPANDNQZ256rr, X86::VPANDNDZ256rmb, TB_BCAST_D },
56 { X86::VPANDNQZrr, X86::VPANDNDZrmb, TB_BCAST_D },
57 { X86::VPANDQZ128rr, X86::VPANDDZ128rmb, TB_BCAST_D },
58 { X86::VPANDQZ256rr, X86::VPANDDZ256rmb, TB_BCAST_D },
59 { X86::VPANDQZrr, X86::VPANDDZrmb, TB_BCAST_D },
60 { X86::VPORDZ128rr, X86::VPORQZ128rmb, TB_BCAST_Q },
61 { X86::VPORDZ256rr, X86::VPORQZ256rmb, TB_BCAST_Q },
62 { X86::VPORDZrr, X86::VPORQZrmb, TB_BCAST_Q },
63 { X86::VPORQZ128rr, X86::VPORDZ128rmb, TB_BCAST_D },
64 { X86::VPORQZ256rr, X86::VPORDZ256rmb, TB_BCAST_D },
65 { X86::VPORQZrr, X86::VPORDZrmb, TB_BCAST_D },
66 { X86::VPXORDZ128rr, X86::VPXORQZ128rmb, TB_BCAST_Q },
67 { X86::VPXORDZ256rr, X86::VPXORQZ256rmb, TB_BCAST_Q },
68 { X86::VPXORDZrr, X86::VPXORQZrmb, TB_BCAST_Q },
69 { X86::VPXORQZ128rr, X86::VPXORDZ128rmb, TB_BCAST_D },
70 { X86::VPXORQZ256rr, X86::VPXORDZ256rmb, TB_BCAST_D },
71 { X86::VPXORQZrr, X86::VPXORDZrmb, TB_BCAST_D },
72 { X86::VXORPDZ128rr, X86::VXORPSZ128rmb, TB_BCAST_SS },
73 { X86::VXORPDZ256rr, X86::VXORPSZ256rmb, TB_BCAST_SS },
74 { X86::VXORPDZrr, X86::VXORPSZrmb, TB_BCAST_SS },
75 { X86::VXORPSZ128rr, X86::VXORPDZ128rmb, TB_BCAST_SD },
76 { X86::VXORPSZ256rr, X86::VXORPDZ256rmb, TB_BCAST_SD },
77 { X86::VXORPSZrr, X86::VXORPDZrmb, TB_BCAST_SD },
78};
79
81 { X86::VPTERNLOGDZ128rri, X86::VPTERNLOGQZ128rmbi, TB_BCAST_Q },
82 { X86::VPTERNLOGDZ256rri, X86::VPTERNLOGQZ256rmbi, TB_BCAST_Q },
83 { X86::VPTERNLOGDZrri, X86::VPTERNLOGQZrmbi, TB_BCAST_Q },
84 { X86::VPTERNLOGQZ128rri, X86::VPTERNLOGDZ128rmbi, TB_BCAST_D },
85 { X86::VPTERNLOGQZ256rri, X86::VPTERNLOGDZ256rmbi, TB_BCAST_D },
86 { X86::VPTERNLOGQZrri, X86::VPTERNLOGDZrmbi, TB_BCAST_D },
87};
88
89static const X86FoldTableEntry *
91#ifndef NDEBUG
92#define CHECK_SORTED_UNIQUE(TABLE) \
93 assert(llvm::is_sorted(TABLE) && #TABLE " is not sorted"); \
94 assert(std::adjacent_find(std::begin(Table), std::end(Table)) == \
95 std::end(Table) && \
96 #TABLE " is not unique");
97
98 // Make sure the tables are sorted.
99 static std::atomic<bool> FoldTablesChecked(false);
100 if (!FoldTablesChecked.load(std::memory_order_relaxed)) {
101 CHECK_SORTED_UNIQUE(Table2Addr)
102 CHECK_SORTED_UNIQUE(Table0)
103 CHECK_SORTED_UNIQUE(Table1)
104 CHECK_SORTED_UNIQUE(Table2)
105 CHECK_SORTED_UNIQUE(Table3)
106 CHECK_SORTED_UNIQUE(Table4)
107 CHECK_SORTED_UNIQUE(BroadcastTable1)
108 CHECK_SORTED_UNIQUE(BroadcastTable2)
109 CHECK_SORTED_UNIQUE(BroadcastTable3)
110 CHECK_SORTED_UNIQUE(BroadcastTable4)
113 CHECK_SORTED_UNIQUE(MemUnfoldTable)
114 FoldTablesChecked.store(true, std::memory_order_relaxed);
115 }
116#endif
117
119 if (Data != Table.end() && Data->KeyOp == RegOp &&
120 !(Data->Flags & TB_NO_FORWARD))
121 return Data;
122 return nullptr;
123}
124
126 return lookupFoldTableImpl(Table2Addr, RegOp);
127}
128
129const X86FoldTableEntry *llvm::lookupFoldTable(unsigned RegOp, unsigned OpNum) {
131 if (OpNum == 0)
132 FoldTable = ArrayRef(Table0);
133 else if (OpNum == 1)
134 FoldTable = ArrayRef(Table1);
135 else if (OpNum == 2)
136 FoldTable = ArrayRef(Table2);
137 else if (OpNum == 3)
138 FoldTable = ArrayRef(Table3);
139 else if (OpNum == 4)
140 FoldTable = ArrayRef(Table4);
141 else
142 return nullptr;
143
144 return lookupFoldTableImpl(FoldTable, RegOp);
145}
146
148 // NonFoldableWithSameMask table stores instruction opcodes that are unsafe
149 // for masked-load folding when the same mask is used.
150 ArrayRef<unsigned> Table(NonFoldableWithSameMaskTable);
151 auto I = llvm::lower_bound(Table, RegOp);
152 return I != Table.end() && *I == RegOp;
153}
154
156 unsigned OpNum) {
158 if (OpNum == 1)
159 FoldTable = ArrayRef(BroadcastTable1);
160 else if (OpNum == 2)
161 FoldTable = ArrayRef(BroadcastTable2);
162 else if (OpNum == 3)
163 FoldTable = ArrayRef(BroadcastTable3);
164 else if (OpNum == 4)
165 FoldTable = ArrayRef(BroadcastTable4);
166 else
167 return nullptr;
168
169 return lookupFoldTableImpl(FoldTable, RegOp);
170}
171
173 ArrayRef<X86FoldTableEntry> Table(MemUnfoldTable);
175 if (I != Table.end() && I->KeyOp == MemOp)
176 return &*I;
177 return nullptr;
178}
179
180namespace {
181
182// This class stores the memory -> broadcast folding tables. It is instantiated
183// as a function scope static variable to lazily init the folding table.
184struct X86BroadcastFoldTable {
185 // Stores memory broadcast folding tables entries sorted by opcode.
186 std::vector<X86FoldTableEntry> Table;
187
188 X86BroadcastFoldTable() {
189 // Broadcast tables.
190 for (const X86FoldTableEntry &Reg2Bcst : BroadcastTable2) {
191 unsigned RegOp = Reg2Bcst.KeyOp;
192 unsigned BcstOp = Reg2Bcst.DstOp;
193 if (const X86FoldTableEntry *Reg2Mem = lookupFoldTable(RegOp, 2)) {
194 unsigned MemOp = Reg2Mem->DstOp;
195 uint16_t Flags =
196 Reg2Mem->Flags | Reg2Bcst.Flags | TB_INDEX_2 | TB_FOLDED_LOAD;
197 Table.push_back({MemOp, BcstOp, Flags});
198 }
199 }
200 for (const X86FoldTableEntry &Reg2Bcst : BroadcastSizeTable2) {
201 unsigned RegOp = Reg2Bcst.KeyOp;
202 unsigned BcstOp = Reg2Bcst.DstOp;
203 if (const X86FoldTableEntry *Reg2Mem = lookupFoldTable(RegOp, 2)) {
204 unsigned MemOp = Reg2Mem->DstOp;
205 uint16_t Flags =
206 Reg2Mem->Flags | Reg2Bcst.Flags | TB_INDEX_2 | TB_FOLDED_LOAD;
207 Table.push_back({MemOp, BcstOp, Flags});
208 }
209 }
210
211 for (const X86FoldTableEntry &Reg2Bcst : BroadcastTable3) {
212 unsigned RegOp = Reg2Bcst.KeyOp;
213 unsigned BcstOp = Reg2Bcst.DstOp;
214 if (const X86FoldTableEntry *Reg2Mem = lookupFoldTable(RegOp, 3)) {
215 unsigned MemOp = Reg2Mem->DstOp;
216 uint16_t Flags =
217 Reg2Mem->Flags | Reg2Bcst.Flags | TB_INDEX_3 | TB_FOLDED_LOAD;
218 Table.push_back({MemOp, BcstOp, Flags});
219 }
220 }
221 for (const X86FoldTableEntry &Reg2Bcst : BroadcastSizeTable3) {
222 unsigned RegOp = Reg2Bcst.KeyOp;
223 unsigned BcstOp = Reg2Bcst.DstOp;
224 if (const X86FoldTableEntry *Reg2Mem = lookupFoldTable(RegOp, 3)) {
225 unsigned MemOp = Reg2Mem->DstOp;
226 uint16_t Flags =
227 Reg2Mem->Flags | Reg2Bcst.Flags | TB_INDEX_3 | TB_FOLDED_LOAD;
228 Table.push_back({MemOp, BcstOp, Flags});
229 }
230 }
231
232 for (const X86FoldTableEntry &Reg2Bcst : BroadcastTable4) {
233 unsigned RegOp = Reg2Bcst.KeyOp;
234 unsigned BcstOp = Reg2Bcst.DstOp;
235 if (const X86FoldTableEntry *Reg2Mem = lookupFoldTable(RegOp, 4)) {
236 unsigned MemOp = Reg2Mem->DstOp;
237 uint16_t Flags =
238 Reg2Mem->Flags | Reg2Bcst.Flags | TB_INDEX_4 | TB_FOLDED_LOAD;
239 Table.push_back({MemOp, BcstOp, Flags});
240 }
241 }
242
243 // Sort the memory->broadcast fold table.
244 array_pod_sort(Table.begin(), Table.end());
245 }
246};
247} // namespace
248
250 unsigned BroadcastBits) {
251 switch (Entry.Flags & TB_BCAST_MASK) {
252 case TB_BCAST_W:
253 case TB_BCAST_SH:
254 return BroadcastBits == 16;
255 case TB_BCAST_D:
256 case TB_BCAST_SS:
257 return BroadcastBits == 32;
258 case TB_BCAST_Q:
259 case TB_BCAST_SD:
260 return BroadcastBits == 64;
261 }
262 return false;
263}
264
265const X86FoldTableEntry *
266llvm::lookupBroadcastFoldTableBySize(unsigned MemOp, unsigned BroadcastBits) {
267 static X86BroadcastFoldTable BroadcastFoldTable;
268 auto &Table = BroadcastFoldTable.Table;
269 for (auto I = llvm::lower_bound(Table, MemOp);
270 I != Table.end() && I->KeyOp == MemOp; ++I) {
271 if (matchBroadcastSize(*I, BroadcastBits))
272 return &*I;
273 }
274 return nullptr;
275}
#define I(x, y, z)
Definition MD5.cpp:57
This file contains some templates that are useful if you are working with the STL at all.
static const X86FoldTableEntry BroadcastSizeTable2[]
#define CHECK_SORTED_UNIQUE(TABLE)
static const X86FoldTableEntry BroadcastSizeTable3[]
static const X86FoldTableEntry * lookupFoldTableImpl(ArrayRef< X86FoldTableEntry > Table, unsigned RegOp)
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
This is an optimization pass for GlobalISel generic memory operations.
const X86FoldTableEntry * lookupBroadcastFoldTableBySize(unsigned MemOp, unsigned BroadcastBits)
bool isNonFoldableWithSameMask(unsigned RegOp)
const X86FoldTableEntry * lookupBroadcastFoldTable(unsigned RegOp, unsigned OpNum)
const X86FoldTableEntry * lookupTwoAddrFoldTable(unsigned RegOp)
auto lower_bound(R &&Range, T &&Value)
Provide wrappers to std::lower_bound which take ranges instead of having to pass begin/end explicitly...
Definition STLExtras.h:2068
ArrayRef(const T &OneElt) -> ArrayRef< T >
const X86FoldTableEntry * lookupUnfoldTable(unsigned MemOp)
bool matchBroadcastSize(const X86FoldTableEntry &Entry, unsigned BroadcastBits)
void array_pod_sort(IteratorTy Start, IteratorTy End)
array_pod_sort - This sorts an array with the specified start and end extent.
Definition STLExtras.h:1612
const X86FoldTableEntry * lookupFoldTable(unsigned RegOp, unsigned OpNum)