File: | lib/Target/Hexagon/HexagonStoreWidening.cpp |
Warning: | line 340, column 32 Value stored to 'S2' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- HexagonStoreWidening.cpp -------------------------------------------===// |
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 | // Replace sequences of "narrow" stores to adjacent memory locations with |
9 | // a fewer "wide" stores that have the same effect. |
10 | // For example, replace: |
11 | // S4_storeirb_io %100, 0, 0 ; store-immediate-byte |
12 | // S4_storeirb_io %100, 1, 0 ; store-immediate-byte |
13 | // with |
14 | // S4_storeirh_io %100, 0, 0 ; store-immediate-halfword |
15 | // The above is the general idea. The actual cases handled by the code |
16 | // may be a bit more complex. |
17 | // The purpose of this pass is to reduce the number of outstanding stores, |
18 | // or as one could say, "reduce store queue pressure". Also, wide stores |
19 | // mean fewer stores, and since there are only two memory instructions allowed |
20 | // per packet, it also means fewer packets, and ultimately fewer cycles. |
21 | //===---------------------------------------------------------------------===// |
22 | |
23 | #define DEBUG_TYPE"hexagon-widen-stores" "hexagon-widen-stores" |
24 | |
25 | #include "HexagonInstrInfo.h" |
26 | #include "HexagonRegisterInfo.h" |
27 | #include "HexagonSubtarget.h" |
28 | #include "llvm/ADT/SmallPtrSet.h" |
29 | #include "llvm/Analysis/AliasAnalysis.h" |
30 | #include "llvm/Analysis/MemoryLocation.h" |
31 | #include "llvm/CodeGen/MachineBasicBlock.h" |
32 | #include "llvm/CodeGen/MachineFunction.h" |
33 | #include "llvm/CodeGen/MachineFunctionPass.h" |
34 | #include "llvm/CodeGen/MachineInstr.h" |
35 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
36 | #include "llvm/CodeGen/MachineMemOperand.h" |
37 | #include "llvm/CodeGen/MachineOperand.h" |
38 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
39 | #include "llvm/IR/DebugLoc.h" |
40 | #include "llvm/MC/MCInstrDesc.h" |
41 | #include "llvm/Pass.h" |
42 | #include "llvm/Support/Debug.h" |
43 | #include "llvm/Support/ErrorHandling.h" |
44 | #include "llvm/Support/MathExtras.h" |
45 | #include "llvm/Support/raw_ostream.h" |
46 | #include <algorithm> |
47 | #include <cassert> |
48 | #include <cstdint> |
49 | #include <iterator> |
50 | #include <vector> |
51 | |
52 | using namespace llvm; |
53 | |
54 | namespace llvm { |
55 | |
56 | FunctionPass *createHexagonStoreWidening(); |
57 | void initializeHexagonStoreWideningPass(PassRegistry&); |
58 | |
59 | } // end namespace llvm |
60 | |
61 | namespace { |
62 | |
63 | struct HexagonStoreWidening : public MachineFunctionPass { |
64 | const HexagonInstrInfo *TII; |
65 | const HexagonRegisterInfo *TRI; |
66 | const MachineRegisterInfo *MRI; |
67 | AliasAnalysis *AA; |
68 | MachineFunction *MF; |
69 | |
70 | public: |
71 | static char ID; |
72 | |
73 | HexagonStoreWidening() : MachineFunctionPass(ID) { |
74 | initializeHexagonStoreWideningPass(*PassRegistry::getPassRegistry()); |
75 | } |
76 | |
77 | bool runOnMachineFunction(MachineFunction &MF) override; |
78 | |
79 | StringRef getPassName() const override { return "Hexagon Store Widening"; } |
80 | |
81 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
82 | AU.addRequired<AAResultsWrapperPass>(); |
83 | AU.addPreserved<AAResultsWrapperPass>(); |
84 | MachineFunctionPass::getAnalysisUsage(AU); |
85 | } |
86 | |
87 | static bool handledStoreType(const MachineInstr *MI); |
88 | |
89 | private: |
90 | static const int MaxWideSize = 4; |
91 | |
92 | using InstrGroup = std::vector<MachineInstr *>; |
93 | using InstrGroupList = std::vector<InstrGroup>; |
94 | |
95 | bool instrAliased(InstrGroup &Stores, const MachineMemOperand &MMO); |
96 | bool instrAliased(InstrGroup &Stores, const MachineInstr *MI); |
97 | void createStoreGroup(MachineInstr *BaseStore, InstrGroup::iterator Begin, |
98 | InstrGroup::iterator End, InstrGroup &Group); |
99 | void createStoreGroups(MachineBasicBlock &MBB, |
100 | InstrGroupList &StoreGroups); |
101 | bool processBasicBlock(MachineBasicBlock &MBB); |
102 | bool processStoreGroup(InstrGroup &Group); |
103 | bool selectStores(InstrGroup::iterator Begin, InstrGroup::iterator End, |
104 | InstrGroup &OG, unsigned &TotalSize, unsigned MaxSize); |
105 | bool createWideStores(InstrGroup &OG, InstrGroup &NG, unsigned TotalSize); |
106 | bool replaceStores(InstrGroup &OG, InstrGroup &NG); |
107 | bool storesAreAdjacent(const MachineInstr *S1, const MachineInstr *S2); |
108 | }; |
109 | |
110 | } // end anonymous namespace |
111 | |
112 | char HexagonStoreWidening::ID = 0; |
113 | |
114 | INITIALIZE_PASS_BEGIN(HexagonStoreWidening, "hexagon-widen-stores",static void *initializeHexagonStoreWideningPassOnce(PassRegistry &Registry) { |
115 | "Hexason Store Widening", false, false)static void *initializeHexagonStoreWideningPassOnce(PassRegistry &Registry) { |
116 | INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)initializeAAResultsWrapperPassPass(Registry); |
117 | INITIALIZE_PASS_END(HexagonStoreWidening, "hexagon-widen-stores",PassInfo *PI = new PassInfo( "Hexagon Store Widening", "hexagon-widen-stores" , &HexagonStoreWidening::ID, PassInfo::NormalCtor_t(callDefaultCtor <HexagonStoreWidening>), false, false); Registry.registerPass (*PI, true); return PI; } static llvm::once_flag InitializeHexagonStoreWideningPassFlag ; void llvm::initializeHexagonStoreWideningPass(PassRegistry & Registry) { llvm::call_once(InitializeHexagonStoreWideningPassFlag , initializeHexagonStoreWideningPassOnce, std::ref(Registry)) ; } |
118 | "Hexagon Store Widening", false, false)PassInfo *PI = new PassInfo( "Hexagon Store Widening", "hexagon-widen-stores" , &HexagonStoreWidening::ID, PassInfo::NormalCtor_t(callDefaultCtor <HexagonStoreWidening>), false, false); Registry.registerPass (*PI, true); return PI; } static llvm::once_flag InitializeHexagonStoreWideningPassFlag ; void llvm::initializeHexagonStoreWideningPass(PassRegistry & Registry) { llvm::call_once(InitializeHexagonStoreWideningPassFlag , initializeHexagonStoreWideningPassOnce, std::ref(Registry)) ; } |
119 | |
120 | // Some local helper functions... |
121 | static unsigned getBaseAddressRegister(const MachineInstr *MI) { |
122 | const MachineOperand &MO = MI->getOperand(0); |
123 | assert(MO.isReg() && "Expecting register operand")((MO.isReg() && "Expecting register operand") ? static_cast <void> (0) : __assert_fail ("MO.isReg() && \"Expecting register operand\"" , "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 123, __PRETTY_FUNCTION__)); |
124 | return MO.getReg(); |
125 | } |
126 | |
127 | static int64_t getStoreOffset(const MachineInstr *MI) { |
128 | unsigned OpC = MI->getOpcode(); |
129 | assert(HexagonStoreWidening::handledStoreType(MI) && "Unhandled opcode")((HexagonStoreWidening::handledStoreType(MI) && "Unhandled opcode" ) ? static_cast<void> (0) : __assert_fail ("HexagonStoreWidening::handledStoreType(MI) && \"Unhandled opcode\"" , "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 129, __PRETTY_FUNCTION__)); |
130 | |
131 | switch (OpC) { |
132 | case Hexagon::S4_storeirb_io: |
133 | case Hexagon::S4_storeirh_io: |
134 | case Hexagon::S4_storeiri_io: { |
135 | const MachineOperand &MO = MI->getOperand(1); |
136 | assert(MO.isImm() && "Expecting immediate offset")((MO.isImm() && "Expecting immediate offset") ? static_cast <void> (0) : __assert_fail ("MO.isImm() && \"Expecting immediate offset\"" , "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 136, __PRETTY_FUNCTION__)); |
137 | return MO.getImm(); |
138 | } |
139 | } |
140 | dbgs() << *MI; |
141 | llvm_unreachable("Store offset calculation missing for a handled opcode")::llvm::llvm_unreachable_internal("Store offset calculation missing for a handled opcode" , "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 141); |
142 | return 0; |
143 | } |
144 | |
145 | static const MachineMemOperand &getStoreTarget(const MachineInstr *MI) { |
146 | assert(!MI->memoperands_empty() && "Expecting memory operands")((!MI->memoperands_empty() && "Expecting memory operands" ) ? static_cast<void> (0) : __assert_fail ("!MI->memoperands_empty() && \"Expecting memory operands\"" , "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 146, __PRETTY_FUNCTION__)); |
147 | return **MI->memoperands_begin(); |
148 | } |
149 | |
150 | // Filtering function: any stores whose opcodes are not "approved" of by |
151 | // this function will not be subjected to widening. |
152 | inline bool HexagonStoreWidening::handledStoreType(const MachineInstr *MI) { |
153 | // For now, only handle stores of immediate values. |
154 | // Also, reject stores to stack slots. |
155 | unsigned Opc = MI->getOpcode(); |
156 | switch (Opc) { |
157 | case Hexagon::S4_storeirb_io: |
158 | case Hexagon::S4_storeirh_io: |
159 | case Hexagon::S4_storeiri_io: |
160 | // Base address must be a register. (Implement FI later.) |
161 | return MI->getOperand(0).isReg(); |
162 | default: |
163 | return false; |
164 | } |
165 | } |
166 | |
167 | // Check if the machine memory operand MMO is aliased with any of the |
168 | // stores in the store group Stores. |
169 | bool HexagonStoreWidening::instrAliased(InstrGroup &Stores, |
170 | const MachineMemOperand &MMO) { |
171 | if (!MMO.getValue()) |
172 | return true; |
173 | |
174 | MemoryLocation L(MMO.getValue(), MMO.getSize(), MMO.getAAInfo()); |
175 | |
176 | for (auto SI : Stores) { |
177 | const MachineMemOperand &SMO = getStoreTarget(SI); |
178 | if (!SMO.getValue()) |
179 | return true; |
180 | |
181 | MemoryLocation SL(SMO.getValue(), SMO.getSize(), SMO.getAAInfo()); |
182 | if (AA->alias(L, SL)) |
183 | return true; |
184 | } |
185 | |
186 | return false; |
187 | } |
188 | |
189 | // Check if the machine instruction MI accesses any storage aliased with |
190 | // any store in the group Stores. |
191 | bool HexagonStoreWidening::instrAliased(InstrGroup &Stores, |
192 | const MachineInstr *MI) { |
193 | for (auto &I : MI->memoperands()) |
194 | if (instrAliased(Stores, *I)) |
195 | return true; |
196 | return false; |
197 | } |
198 | |
199 | // Inspect a machine basic block, and generate store groups out of stores |
200 | // encountered in the block. |
201 | // |
202 | // A store group is a group of stores that use the same base register, |
203 | // and which can be reordered within that group without altering the |
204 | // semantics of the program. A single store group could be widened as |
205 | // a whole, if there existed a single store instruction with the same |
206 | // semantics as the entire group. In many cases, a single store group |
207 | // may need more than one wide store. |
208 | void HexagonStoreWidening::createStoreGroups(MachineBasicBlock &MBB, |
209 | InstrGroupList &StoreGroups) { |
210 | InstrGroup AllInsns; |
211 | |
212 | // Copy all instruction pointers from the basic block to a temporary |
213 | // list. This will allow operating on the list, and modifying its |
214 | // elements without affecting the basic block. |
215 | for (auto &I : MBB) |
216 | AllInsns.push_back(&I); |
217 | |
218 | // Traverse all instructions in the AllInsns list, and if we encounter |
219 | // a store, then try to create a store group starting at that instruction |
220 | // i.e. a sequence of independent stores that can be widened. |
221 | for (auto I = AllInsns.begin(), E = AllInsns.end(); I != E; ++I) { |
222 | MachineInstr *MI = *I; |
223 | // Skip null pointers (processed instructions). |
224 | if (!MI || !handledStoreType(MI)) |
225 | continue; |
226 | |
227 | // Found a store. Try to create a store group. |
228 | InstrGroup G; |
229 | createStoreGroup(MI, I+1, E, G); |
230 | if (G.size() > 1) |
231 | StoreGroups.push_back(G); |
232 | } |
233 | } |
234 | |
235 | // Create a single store group. The stores need to be independent between |
236 | // themselves, and also there cannot be other instructions between them |
237 | // that could read or modify storage being stored into. |
238 | void HexagonStoreWidening::createStoreGroup(MachineInstr *BaseStore, |
239 | InstrGroup::iterator Begin, InstrGroup::iterator End, InstrGroup &Group) { |
240 | assert(handledStoreType(BaseStore) && "Unexpected instruction")((handledStoreType(BaseStore) && "Unexpected instruction" ) ? static_cast<void> (0) : __assert_fail ("handledStoreType(BaseStore) && \"Unexpected instruction\"" , "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 240, __PRETTY_FUNCTION__)); |
241 | unsigned BaseReg = getBaseAddressRegister(BaseStore); |
242 | InstrGroup Other; |
243 | |
244 | Group.push_back(BaseStore); |
245 | |
246 | for (auto I = Begin; I != End; ++I) { |
247 | MachineInstr *MI = *I; |
248 | if (!MI) |
249 | continue; |
250 | |
251 | if (handledStoreType(MI)) { |
252 | // If this store instruction is aliased with anything already in the |
253 | // group, terminate the group now. |
254 | if (instrAliased(Group, getStoreTarget(MI))) |
255 | return; |
256 | // If this store is aliased to any of the memory instructions we have |
257 | // seen so far (that are not a part of this group), terminate the group. |
258 | if (instrAliased(Other, getStoreTarget(MI))) |
259 | return; |
260 | |
261 | unsigned BR = getBaseAddressRegister(MI); |
262 | if (BR == BaseReg) { |
263 | Group.push_back(MI); |
264 | *I = nullptr; |
265 | continue; |
266 | } |
267 | } |
268 | |
269 | // Assume calls are aliased to everything. |
270 | if (MI->isCall() || MI->hasUnmodeledSideEffects()) |
271 | return; |
272 | |
273 | if (MI->mayLoad() || MI->mayStore()) { |
274 | if (MI->hasOrderedMemoryRef() || instrAliased(Group, MI)) |
275 | return; |
276 | Other.push_back(MI); |
277 | } |
278 | } // for |
279 | } |
280 | |
281 | // Check if store instructions S1 and S2 are adjacent. More precisely, |
282 | // S2 has to access memory immediately following that accessed by S1. |
283 | bool HexagonStoreWidening::storesAreAdjacent(const MachineInstr *S1, |
284 | const MachineInstr *S2) { |
285 | if (!handledStoreType(S1) || !handledStoreType(S2)) |
286 | return false; |
287 | |
288 | const MachineMemOperand &S1MO = getStoreTarget(S1); |
289 | |
290 | // Currently only handling immediate stores. |
291 | int Off1 = S1->getOperand(1).getImm(); |
292 | int Off2 = S2->getOperand(1).getImm(); |
293 | |
294 | return (Off1 >= 0) ? Off1+S1MO.getSize() == unsigned(Off2) |
295 | : int(Off1+S1MO.getSize()) == Off2; |
296 | } |
297 | |
298 | /// Given a sequence of adjacent stores, and a maximum size of a single wide |
299 | /// store, pick a group of stores that can be replaced by a single store |
300 | /// of size not exceeding MaxSize. The selected sequence will be recorded |
301 | /// in OG ("old group" of instructions). |
302 | /// OG should be empty on entry, and should be left empty if the function |
303 | /// fails. |
304 | bool HexagonStoreWidening::selectStores(InstrGroup::iterator Begin, |
305 | InstrGroup::iterator End, InstrGroup &OG, unsigned &TotalSize, |
306 | unsigned MaxSize) { |
307 | assert(Begin != End && "No instructions to analyze")((Begin != End && "No instructions to analyze") ? static_cast <void> (0) : __assert_fail ("Begin != End && \"No instructions to analyze\"" , "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 307, __PRETTY_FUNCTION__)); |
308 | assert(OG.empty() && "Old group not empty on entry")((OG.empty() && "Old group not empty on entry") ? static_cast <void> (0) : __assert_fail ("OG.empty() && \"Old group not empty on entry\"" , "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 308, __PRETTY_FUNCTION__)); |
309 | |
310 | if (std::distance(Begin, End) <= 1) |
311 | return false; |
312 | |
313 | MachineInstr *FirstMI = *Begin; |
314 | assert(!FirstMI->memoperands_empty() && "Expecting some memory operands")((!FirstMI->memoperands_empty() && "Expecting some memory operands" ) ? static_cast<void> (0) : __assert_fail ("!FirstMI->memoperands_empty() && \"Expecting some memory operands\"" , "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 314, __PRETTY_FUNCTION__)); |
315 | const MachineMemOperand &FirstMMO = getStoreTarget(FirstMI); |
316 | unsigned Alignment = FirstMMO.getAlignment(); |
317 | unsigned SizeAccum = FirstMMO.getSize(); |
318 | unsigned FirstOffset = getStoreOffset(FirstMI); |
319 | |
320 | // The initial value of SizeAccum should always be a power of 2. |
321 | assert(isPowerOf2_32(SizeAccum) && "First store size not a power of 2")((isPowerOf2_32(SizeAccum) && "First store size not a power of 2" ) ? static_cast<void> (0) : __assert_fail ("isPowerOf2_32(SizeAccum) && \"First store size not a power of 2\"" , "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 321, __PRETTY_FUNCTION__)); |
322 | |
323 | // If the size of the first store equals to or exceeds the limit, do nothing. |
324 | if (SizeAccum >= MaxSize) |
325 | return false; |
326 | |
327 | // If the size of the first store is greater than or equal to the address |
328 | // stored to, then the store cannot be made any wider. |
329 | if (SizeAccum >= Alignment) |
330 | return false; |
331 | |
332 | // The offset of a store will put restrictions on how wide the store can be. |
333 | // Offsets in stores of size 2^n bytes need to have the n lowest bits be 0. |
334 | // If the first store already exhausts the offset limits, quit. Test this |
335 | // by checking if the next wider size would exceed the limit. |
336 | if ((2*SizeAccum-1) & FirstOffset) |
337 | return false; |
338 | |
339 | OG.push_back(FirstMI); |
340 | MachineInstr *S1 = FirstMI, *S2 = *(Begin+1); |
Value stored to 'S2' during its initialization is never read | |
341 | InstrGroup::iterator I = Begin+1; |
342 | |
343 | // Pow2Num will be the largest number of elements in OG such that the sum |
344 | // of sizes of stores 0...Pow2Num-1 will be a power of 2. |
345 | unsigned Pow2Num = 1; |
346 | unsigned Pow2Size = SizeAccum; |
347 | |
348 | // Be greedy: keep accumulating stores as long as they are to adjacent |
349 | // memory locations, and as long as the total number of bytes stored |
350 | // does not exceed the limit (MaxSize). |
351 | // Keep track of when the total size covered is a power of 2, since |
352 | // this is a size a single store can cover. |
353 | while (I != End) { |
354 | S2 = *I; |
355 | // Stores are sorted, so if S1 and S2 are not adjacent, there won't be |
356 | // any other store to fill the "hole". |
357 | if (!storesAreAdjacent(S1, S2)) |
358 | break; |
359 | |
360 | unsigned S2Size = getStoreTarget(S2).getSize(); |
361 | if (SizeAccum + S2Size > std::min(MaxSize, Alignment)) |
362 | break; |
363 | |
364 | OG.push_back(S2); |
365 | SizeAccum += S2Size; |
366 | if (isPowerOf2_32(SizeAccum)) { |
367 | Pow2Num = OG.size(); |
368 | Pow2Size = SizeAccum; |
369 | } |
370 | if ((2*Pow2Size-1) & FirstOffset) |
371 | break; |
372 | |
373 | S1 = S2; |
374 | ++I; |
375 | } |
376 | |
377 | // The stores don't add up to anything that can be widened. Clean up. |
378 | if (Pow2Num <= 1) { |
379 | OG.clear(); |
380 | return false; |
381 | } |
382 | |
383 | // Only leave the stored being widened. |
384 | OG.resize(Pow2Num); |
385 | TotalSize = Pow2Size; |
386 | return true; |
387 | } |
388 | |
389 | /// Given an "old group" OG of stores, create a "new group" NG of instructions |
390 | /// to replace them. Ideally, NG would only have a single instruction in it, |
391 | /// but that may only be possible for store-immediate. |
392 | bool HexagonStoreWidening::createWideStores(InstrGroup &OG, InstrGroup &NG, |
393 | unsigned TotalSize) { |
394 | // XXX Current limitations: |
395 | // - only expect stores of immediate values in OG, |
396 | // - only handle a TotalSize of up to 4. |
397 | |
398 | if (TotalSize > 4) |
399 | return false; |
400 | |
401 | unsigned Acc = 0; // Value accumulator. |
402 | unsigned Shift = 0; |
403 | |
404 | for (InstrGroup::iterator I = OG.begin(), E = OG.end(); I != E; ++I) { |
405 | MachineInstr *MI = *I; |
406 | const MachineMemOperand &MMO = getStoreTarget(MI); |
407 | MachineOperand &SO = MI->getOperand(2); // Source. |
408 | assert(SO.isImm() && "Expecting an immediate operand")((SO.isImm() && "Expecting an immediate operand") ? static_cast <void> (0) : __assert_fail ("SO.isImm() && \"Expecting an immediate operand\"" , "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 408, __PRETTY_FUNCTION__)); |
409 | |
410 | unsigned NBits = MMO.getSize()*8; |
411 | unsigned Mask = (0xFFFFFFFFU >> (32-NBits)); |
412 | unsigned Val = (SO.getImm() & Mask) << Shift; |
413 | Acc |= Val; |
414 | Shift += NBits; |
415 | } |
416 | |
417 | MachineInstr *FirstSt = OG.front(); |
418 | DebugLoc DL = OG.back()->getDebugLoc(); |
419 | const MachineMemOperand &OldM = getStoreTarget(FirstSt); |
420 | MachineMemOperand *NewM = |
421 | MF->getMachineMemOperand(OldM.getPointerInfo(), OldM.getFlags(), |
422 | TotalSize, OldM.getAlignment(), |
423 | OldM.getAAInfo()); |
424 | |
425 | if (Acc < 0x10000) { |
426 | // Create mem[hw] = #Acc |
427 | unsigned WOpc = (TotalSize == 2) ? Hexagon::S4_storeirh_io : |
428 | (TotalSize == 4) ? Hexagon::S4_storeiri_io : 0; |
429 | assert(WOpc && "Unexpected size")((WOpc && "Unexpected size") ? static_cast<void> (0) : __assert_fail ("WOpc && \"Unexpected size\"", "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 429, __PRETTY_FUNCTION__)); |
430 | |
431 | int Val = (TotalSize == 2) ? int16_t(Acc) : int(Acc); |
432 | const MCInstrDesc &StD = TII->get(WOpc); |
433 | MachineOperand &MR = FirstSt->getOperand(0); |
434 | int64_t Off = FirstSt->getOperand(1).getImm(); |
435 | MachineInstr *StI = |
436 | BuildMI(*MF, DL, StD) |
437 | .addReg(MR.getReg(), getKillRegState(MR.isKill()), MR.getSubReg()) |
438 | .addImm(Off) |
439 | .addImm(Val); |
440 | StI->addMemOperand(*MF, NewM); |
441 | NG.push_back(StI); |
442 | } else { |
443 | // Create vreg = A2_tfrsi #Acc; mem[hw] = vreg |
444 | const MCInstrDesc &TfrD = TII->get(Hexagon::A2_tfrsi); |
445 | const TargetRegisterClass *RC = TII->getRegClass(TfrD, 0, TRI, *MF); |
446 | unsigned VReg = MF->getRegInfo().createVirtualRegister(RC); |
447 | MachineInstr *TfrI = BuildMI(*MF, DL, TfrD, VReg) |
448 | .addImm(int(Acc)); |
449 | NG.push_back(TfrI); |
450 | |
451 | unsigned WOpc = (TotalSize == 2) ? Hexagon::S2_storerh_io : |
452 | (TotalSize == 4) ? Hexagon::S2_storeri_io : 0; |
453 | assert(WOpc && "Unexpected size")((WOpc && "Unexpected size") ? static_cast<void> (0) : __assert_fail ("WOpc && \"Unexpected size\"", "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 453, __PRETTY_FUNCTION__)); |
454 | |
455 | const MCInstrDesc &StD = TII->get(WOpc); |
456 | MachineOperand &MR = FirstSt->getOperand(0); |
457 | int64_t Off = FirstSt->getOperand(1).getImm(); |
458 | MachineInstr *StI = |
459 | BuildMI(*MF, DL, StD) |
460 | .addReg(MR.getReg(), getKillRegState(MR.isKill()), MR.getSubReg()) |
461 | .addImm(Off) |
462 | .addReg(VReg, RegState::Kill); |
463 | StI->addMemOperand(*MF, NewM); |
464 | NG.push_back(StI); |
465 | } |
466 | |
467 | return true; |
468 | } |
469 | |
470 | // Replace instructions from the old group OG with instructions from the |
471 | // new group NG. Conceptually, remove all instructions in OG, and then |
472 | // insert all instructions in NG, starting at where the first instruction |
473 | // from OG was (in the order in which they appeared in the basic block). |
474 | // (The ordering in OG does not have to match the order in the basic block.) |
475 | bool HexagonStoreWidening::replaceStores(InstrGroup &OG, InstrGroup &NG) { |
476 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("hexagon-widen-stores")) { { dbgs() << "Replacing:\n"; for (auto I : OG) dbgs() << " " << *I; dbgs() << "with\n"; for (auto I : NG) dbgs() << " " << *I ; }; } } while (false) |
477 | dbgs() << "Replacing:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("hexagon-widen-stores")) { { dbgs() << "Replacing:\n"; for (auto I : OG) dbgs() << " " << *I; dbgs() << "with\n"; for (auto I : NG) dbgs() << " " << *I ; }; } } while (false) |
478 | for (auto I : OG)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("hexagon-widen-stores")) { { dbgs() << "Replacing:\n"; for (auto I : OG) dbgs() << " " << *I; dbgs() << "with\n"; for (auto I : NG) dbgs() << " " << *I ; }; } } while (false) |
479 | dbgs() << " " << *I;do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("hexagon-widen-stores")) { { dbgs() << "Replacing:\n"; for (auto I : OG) dbgs() << " " << *I; dbgs() << "with\n"; for (auto I : NG) dbgs() << " " << *I ; }; } } while (false) |
480 | dbgs() << "with\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("hexagon-widen-stores")) { { dbgs() << "Replacing:\n"; for (auto I : OG) dbgs() << " " << *I; dbgs() << "with\n"; for (auto I : NG) dbgs() << " " << *I ; }; } } while (false) |
481 | for (auto I : NG)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("hexagon-widen-stores")) { { dbgs() << "Replacing:\n"; for (auto I : OG) dbgs() << " " << *I; dbgs() << "with\n"; for (auto I : NG) dbgs() << " " << *I ; }; } } while (false) |
482 | dbgs() << " " << *I;do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("hexagon-widen-stores")) { { dbgs() << "Replacing:\n"; for (auto I : OG) dbgs() << " " << *I; dbgs() << "with\n"; for (auto I : NG) dbgs() << " " << *I ; }; } } while (false) |
483 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("hexagon-widen-stores")) { { dbgs() << "Replacing:\n"; for (auto I : OG) dbgs() << " " << *I; dbgs() << "with\n"; for (auto I : NG) dbgs() << " " << *I ; }; } } while (false); |
484 | |
485 | MachineBasicBlock *MBB = OG.back()->getParent(); |
486 | MachineBasicBlock::iterator InsertAt = MBB->end(); |
487 | |
488 | // Need to establish the insertion point. The best one is right before |
489 | // the first store in the OG, but in the order in which the stores occur |
490 | // in the program list. Since the ordering in OG does not correspond |
491 | // to the order in the program list, we need to do some work to find |
492 | // the insertion point. |
493 | |
494 | // Create a set of all instructions in OG (for quick lookup). |
495 | SmallPtrSet<MachineInstr*, 4> InstrSet; |
496 | for (auto I : OG) |
497 | InstrSet.insert(I); |
498 | |
499 | // Traverse the block, until we hit an instruction from OG. |
500 | for (auto &I : *MBB) { |
501 | if (InstrSet.count(&I)) { |
502 | InsertAt = I; |
503 | break; |
504 | } |
505 | } |
506 | |
507 | assert((InsertAt != MBB->end()) && "Cannot locate any store from the group")(((InsertAt != MBB->end()) && "Cannot locate any store from the group" ) ? static_cast<void> (0) : __assert_fail ("(InsertAt != MBB->end()) && \"Cannot locate any store from the group\"" , "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 507, __PRETTY_FUNCTION__)); |
508 | |
509 | bool AtBBStart = false; |
510 | |
511 | // InsertAt points at the first instruction that will be removed. We need |
512 | // to move it out of the way, so it remains valid after removing all the |
513 | // old stores, and so we are able to recover it back to the proper insertion |
514 | // position. |
515 | if (InsertAt != MBB->begin()) |
516 | --InsertAt; |
517 | else |
518 | AtBBStart = true; |
519 | |
520 | for (auto I : OG) |
521 | I->eraseFromParent(); |
522 | |
523 | if (!AtBBStart) |
524 | ++InsertAt; |
525 | else |
526 | InsertAt = MBB->begin(); |
527 | |
528 | for (auto I : NG) |
529 | MBB->insert(InsertAt, I); |
530 | |
531 | return true; |
532 | } |
533 | |
534 | // Break up the group into smaller groups, each of which can be replaced by |
535 | // a single wide store. Widen each such smaller group and replace the old |
536 | // instructions with the widened ones. |
537 | bool HexagonStoreWidening::processStoreGroup(InstrGroup &Group) { |
538 | bool Changed = false; |
539 | InstrGroup::iterator I = Group.begin(), E = Group.end(); |
540 | InstrGroup OG, NG; // Old and new groups. |
541 | unsigned CollectedSize; |
542 | |
543 | while (I != E) { |
544 | OG.clear(); |
545 | NG.clear(); |
546 | |
547 | bool Succ = selectStores(I++, E, OG, CollectedSize, MaxWideSize) && |
548 | createWideStores(OG, NG, CollectedSize) && |
549 | replaceStores(OG, NG); |
550 | if (!Succ) |
551 | continue; |
552 | |
553 | assert(OG.size() > 1 && "Created invalid group")((OG.size() > 1 && "Created invalid group") ? static_cast <void> (0) : __assert_fail ("OG.size() > 1 && \"Created invalid group\"" , "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 553, __PRETTY_FUNCTION__)); |
554 | assert(distance(I, E)+1 >= int(OG.size()) && "Too many elements")((distance(I, E)+1 >= int(OG.size()) && "Too many elements" ) ? static_cast<void> (0) : __assert_fail ("distance(I, E)+1 >= int(OG.size()) && \"Too many elements\"" , "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 554, __PRETTY_FUNCTION__)); |
555 | I += OG.size()-1; |
556 | |
557 | Changed = true; |
558 | } |
559 | |
560 | return Changed; |
561 | } |
562 | |
563 | // Process a single basic block: create the store groups, and replace them |
564 | // with the widened stores, if possible. Processing of each basic block |
565 | // is independent from processing of any other basic block. This transfor- |
566 | // mation could be stopped after having processed any basic block without |
567 | // any ill effects (other than not having performed widening in the unpro- |
568 | // cessed blocks). Also, the basic blocks can be processed in any order. |
569 | bool HexagonStoreWidening::processBasicBlock(MachineBasicBlock &MBB) { |
570 | InstrGroupList SGs; |
571 | bool Changed = false; |
572 | |
573 | createStoreGroups(MBB, SGs); |
574 | |
575 | auto Less = [] (const MachineInstr *A, const MachineInstr *B) -> bool { |
576 | return getStoreOffset(A) < getStoreOffset(B); |
577 | }; |
578 | for (auto &G : SGs) { |
579 | assert(G.size() > 1 && "Store group with fewer than 2 elements")((G.size() > 1 && "Store group with fewer than 2 elements" ) ? static_cast<void> (0) : __assert_fail ("G.size() > 1 && \"Store group with fewer than 2 elements\"" , "/build/llvm-toolchain-snapshot-9~svn359999/lib/Target/Hexagon/HexagonStoreWidening.cpp" , 579, __PRETTY_FUNCTION__)); |
580 | llvm::sort(G, Less); |
581 | |
582 | Changed |= processStoreGroup(G); |
583 | } |
584 | |
585 | return Changed; |
586 | } |
587 | |
588 | bool HexagonStoreWidening::runOnMachineFunction(MachineFunction &MFn) { |
589 | if (skipFunction(MFn.getFunction())) |
590 | return false; |
591 | |
592 | MF = &MFn; |
593 | auto &ST = MFn.getSubtarget<HexagonSubtarget>(); |
594 | TII = ST.getInstrInfo(); |
595 | TRI = ST.getRegisterInfo(); |
596 | MRI = &MFn.getRegInfo(); |
597 | AA = &getAnalysis<AAResultsWrapperPass>().getAAResults(); |
598 | |
599 | bool Changed = false; |
600 | |
601 | for (auto &B : MFn) |
602 | Changed |= processBasicBlock(B); |
603 | |
604 | return Changed; |
605 | } |
606 | |
607 | FunctionPass *llvm::createHexagonStoreWidening() { |
608 | return new HexagonStoreWidening(); |
609 | } |