blob: 4ac06de0a3cc844c4d5fe50337fda63b18284616 [file] [log] [blame]
Nicolas Capens2ae9d742016-11-24 14:43:05 -05001// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "Optimizer.hpp"
16
17#include "src/IceCfg.h"
18#include "src/IceCfgNode.h"
19
Nicolas Capens2ae9d742016-11-24 14:43:05 -050020#include <vector>
21
Nicolas Capens157ba262019-12-10 17:49:14 -050022namespace {
23
24class Optimizer
Nicolas Capens2ae9d742016-11-24 14:43:05 -050025{
Nicolas Capens157ba262019-12-10 17:49:14 -050026public:
27 void run(Ice::Cfg *function);
28
29private:
30 void analyzeUses(Ice::Cfg *function);
31 void eliminateDeadCode();
32 void eliminateUnitializedLoads();
33 void eliminateLoadsFollowingSingleStore();
34 void optimizeStoresInSingleBasicBlock();
35
36 void replace(Ice::Inst *instruction, Ice::Operand *newValue);
37 void deleteInstruction(Ice::Inst *instruction);
38 bool isDead(Ice::Inst *instruction);
39
Nicolas Capens33a77f72021-02-08 15:04:38 -050040 static const Ice::InstIntrinsic *asLoadSubVector(const Ice::Inst *instruction);
41 static const Ice::InstIntrinsic *asStoreSubVector(const Ice::Inst *instruction);
Nicolas Capens157ba262019-12-10 17:49:14 -050042 static bool isLoad(const Ice::Inst &instruction);
43 static bool isStore(const Ice::Inst &instruction);
Nicolas Capens157ba262019-12-10 17:49:14 -050044 static std::size_t storeSize(const Ice::Inst *instruction);
45 static bool loadTypeMatchesStore(const Ice::Inst *load, const Ice::Inst *store);
46
47 Ice::Cfg *function;
48 Ice::GlobalContext *context;
49
Ben Clayton713b8d32019-12-17 20:37:56 +000050 struct Uses : std::vector<Ice::Inst *>
Nicolas Capens2ae9d742016-11-24 14:43:05 -050051 {
Nicolas Capens157ba262019-12-10 17:49:14 -050052 bool areOnlyLoadStore() const;
53 void insert(Ice::Operand *value, Ice::Inst *instruction);
54 void erase(Ice::Inst *instruction);
Nicolas Capens2ae9d742016-11-24 14:43:05 -050055
Ben Clayton713b8d32019-12-17 20:37:56 +000056 std::vector<Ice::Inst *> loads;
57 std::vector<Ice::Inst *> stores;
Nicolas Capens2ae9d742016-11-24 14:43:05 -050058 };
59
Nicolas Capens157ba262019-12-10 17:49:14 -050060 struct LoadStoreInst
Nicolas Capens2ae9d742016-11-24 14:43:05 -050061 {
Ben Clayton713b8d32019-12-17 20:37:56 +000062 LoadStoreInst(Ice::Inst *inst, bool isStore)
63 : inst(inst)
Nicolas Capens673a7fe2021-02-05 15:03:22 -050064 , address(isStore ? inst->getStoreAddress() : inst->getLoadAddress())
Ben Clayton713b8d32019-12-17 20:37:56 +000065 , isStore(isStore)
Alexis Hetu932640b2018-06-20 15:35:53 -040066 {
Alexis Hetu932640b2018-06-20 15:35:53 -040067 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -050068
Ben Clayton713b8d32019-12-17 20:37:56 +000069 Ice::Inst *inst;
Nicolas Capens157ba262019-12-10 17:49:14 -050070 Ice::Operand *address;
71 bool isStore;
72 };
73
Ben Clayton713b8d32019-12-17 20:37:56 +000074 Optimizer::Uses *getUses(Ice::Operand *);
75 void setUses(Ice::Operand *, Optimizer::Uses *);
76 bool hasUses(Ice::Operand *) const;
Nicolas Capens157ba262019-12-10 17:49:14 -050077
Ben Clayton713b8d32019-12-17 20:37:56 +000078 Ice::CfgNode *getNode(Ice::Inst *);
79 void setNode(Ice::Inst *, Ice::CfgNode *);
Nicolas Capens157ba262019-12-10 17:49:14 -050080
Ben Clayton713b8d32019-12-17 20:37:56 +000081 Ice::Inst *getDefinition(Ice::Variable *);
82 void setDefinition(Ice::Variable *, Ice::Inst *);
Nicolas Capens157ba262019-12-10 17:49:14 -050083
Ben Clayton713b8d32019-12-17 20:37:56 +000084 const std::vector<LoadStoreInst> &getLoadStoreInsts(Ice::CfgNode *);
85 void setLoadStoreInsts(Ice::CfgNode *, std::vector<LoadStoreInst> *);
86 bool hasLoadStoreInsts(Ice::CfgNode *node) const;
Nicolas Capens157ba262019-12-10 17:49:14 -050087
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -050088 std::vector<Ice::Operand *> operandsWithUses;
Nicolas Capens157ba262019-12-10 17:49:14 -050089};
90
91void Optimizer::run(Ice::Cfg *function)
92{
93 this->function = function;
94 this->context = function->getContext();
95
96 analyzeUses(function);
97
98 eliminateDeadCode();
99 eliminateUnitializedLoads();
100 eliminateLoadsFollowingSingleStore();
101 optimizeStoresInSingleBasicBlock();
102 eliminateDeadCode();
103
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500104 for(auto operand : operandsWithUses)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500105 {
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500106 // Deletes the Uses instance on the operand
107 setUses(operand, nullptr);
Nicolas Capens157ba262019-12-10 17:49:14 -0500108 }
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500109 operandsWithUses.clear();
Nicolas Capens157ba262019-12-10 17:49:14 -0500110}
111
112void Optimizer::eliminateDeadCode()
113{
114 bool modified;
115 do
116 {
117 modified = false;
118 for(Ice::CfgNode *basicBlock : function->getNodes())
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500119 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500120 for(Ice::Inst &inst : Ice::reverse_range(basicBlock->getInsts()))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500121 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500122 if(inst.isDeleted())
123 {
124 continue;
125 }
126
127 if(isDead(&inst))
128 {
129 deleteInstruction(&inst);
130 modified = true;
131 }
132 }
133 }
Ben Clayton713b8d32019-12-17 20:37:56 +0000134 } while(modified);
Nicolas Capens157ba262019-12-10 17:49:14 -0500135}
136
137void Optimizer::eliminateUnitializedLoads()
138{
139 Ice::CfgNode *entryBlock = function->getEntryNode();
140
141 for(Ice::Inst &alloca : entryBlock->getInsts())
142 {
143 if(alloca.isDeleted())
144 {
145 continue;
146 }
147
148 if(!llvm::isa<Ice::InstAlloca>(alloca))
149 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000150 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500151 }
152
153 Ice::Operand *address = alloca.getDest();
154
155 if(!hasUses(address))
156 {
157 continue;
158 }
159
160 const auto &addressUses = *getUses(address);
161
162 if(!addressUses.areOnlyLoadStore())
163 {
164 continue;
165 }
166
167 if(addressUses.stores.empty())
168 {
169 for(Ice::Inst *load : addressUses.loads)
170 {
171 Ice::Variable *loadData = load->getDest();
172
173 if(hasUses(loadData))
174 {
175 for(Ice::Inst *use : *getUses(loadData))
176 {
177 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
178 {
179 if(use->getSrc(i) == loadData)
180 {
181 auto *undef = context->getConstantUndef(loadData->getType());
182
183 use->replaceSource(i, undef);
184 }
185 }
186 }
187
188 setUses(loadData, nullptr);
189 }
190
191 load->setDeleted();
192 }
193
194 alloca.setDeleted();
195 setUses(address, nullptr);
196 }
197 }
198}
199
200void Optimizer::eliminateLoadsFollowingSingleStore()
201{
202 Ice::CfgNode *entryBlock = function->getEntryNode();
203
204 for(Ice::Inst &alloca : entryBlock->getInsts())
205 {
206 if(alloca.isDeleted())
207 {
208 continue;
209 }
210
211 if(!llvm::isa<Ice::InstAlloca>(alloca))
212 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000213 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500214 }
215
216 Ice::Operand *address = alloca.getDest();
217
218 if(!hasUses(address))
219 {
220 continue;
221 }
222
223 auto &addressUses = *getUses(address);
224
225 if(!addressUses.areOnlyLoadStore())
226 {
227 continue;
228 }
229
230 if(addressUses.stores.size() == 1)
231 {
232 Ice::Inst *store = addressUses.stores[0];
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500233 Ice::Operand *storeValue = store->getData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500234
235 for(Ice::Inst *load = &*++store->getIterator(), *next = nullptr; load != next; next = load, load = &*++store->getIterator())
236 {
237 if(load->isDeleted() || !isLoad(*load))
238 {
239 continue;
240 }
241
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500242 if(load->getLoadAddress() != address)
Nicolas Capens157ba262019-12-10 17:49:14 -0500243 {
244 continue;
245 }
246
247 if(!loadTypeMatchesStore(load, store))
248 {
249 continue;
250 }
251
Antonio Maioranob3d9a2a2020-02-14 14:38:04 -0500252 // TODO(b/148272103): InstLoad assumes that a constant ptr is an offset, rather than an
253 // absolute address. We need to make sure we don't replace a variable with a constant
254 // on this load.
255 if(llvm::isa<Ice::Constant>(storeValue))
256 {
257 continue;
258 }
259
Nicolas Capens157ba262019-12-10 17:49:14 -0500260 replace(load, storeValue);
261
262 for(size_t i = 0; i < addressUses.loads.size(); i++)
263 {
264 if(addressUses.loads[i] == load)
265 {
266 addressUses.loads[i] = addressUses.loads.back();
267 addressUses.loads.pop_back();
268 break;
269 }
270 }
271
272 for(size_t i = 0; i < addressUses.size(); i++)
273 {
274 if(addressUses[i] == load)
275 {
276 addressUses[i] = addressUses.back();
277 addressUses.pop_back();
278 break;
279 }
280 }
281
282 if(addressUses.size() == 1)
283 {
284 assert(addressUses[0] == store);
285
286 alloca.setDeleted();
287 store->setDeleted();
288 setUses(address, nullptr);
289
290 if(hasUses(storeValue))
291 {
292 auto &valueUses = *getUses(storeValue);
293
294 for(size_t i = 0; i < valueUses.size(); i++)
295 {
296 if(valueUses[i] == store)
297 {
298 valueUses[i] = valueUses.back();
299 valueUses.pop_back();
300 break;
301 }
302 }
303
304 if(valueUses.empty())
305 {
306 setUses(storeValue, nullptr);
307 }
308 }
309
310 break;
311 }
312 }
313 }
314 }
315}
316
317void Optimizer::optimizeStoresInSingleBasicBlock()
318{
319 Ice::CfgNode *entryBlock = function->getEntryNode();
320
Ben Clayton713b8d32019-12-17 20:37:56 +0000321 std::vector<std::vector<LoadStoreInst> *> allocatedVectors;
Nicolas Capens157ba262019-12-10 17:49:14 -0500322
323 for(Ice::Inst &alloca : entryBlock->getInsts())
324 {
325 if(alloca.isDeleted())
326 {
327 continue;
328 }
329
330 if(!llvm::isa<Ice::InstAlloca>(alloca))
331 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000332 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500333 }
334
335 Ice::Operand *address = alloca.getDest();
336
337 if(!hasUses(address))
338 {
339 continue;
340 }
341
342 const auto &addressUses = *getUses(address);
343
344 if(!addressUses.areOnlyLoadStore())
345 {
346 continue;
347 }
348
349 Ice::CfgNode *singleBasicBlock = getNode(addressUses.stores[0]);
350
351 for(size_t i = 1; i < addressUses.stores.size(); i++)
352 {
353 Ice::Inst *store = addressUses.stores[i];
354 if(getNode(store) != singleBasicBlock)
355 {
356 singleBasicBlock = nullptr;
357 break;
358 }
359 }
360
361 if(singleBasicBlock)
362 {
363 if(!hasLoadStoreInsts(singleBasicBlock))
364 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000365 std::vector<LoadStoreInst> *loadStoreInstVector = new std::vector<LoadStoreInst>();
Nicolas Capens157ba262019-12-10 17:49:14 -0500366 setLoadStoreInsts(singleBasicBlock, loadStoreInstVector);
367 allocatedVectors.push_back(loadStoreInstVector);
368 for(Ice::Inst &inst : singleBasicBlock->getInsts())
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500369 {
370 if(inst.isDeleted())
371 {
372 continue;
373 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500374
Nicolas Capens157ba262019-12-10 17:49:14 -0500375 bool isStoreInst = isStore(inst);
376 bool isLoadInst = isLoad(inst);
377
378 if(isStoreInst || isLoadInst)
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500379 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500380 loadStoreInstVector->push_back(LoadStoreInst(&inst, isStoreInst));
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500381 }
382 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500383 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500384
Nicolas Capens157ba262019-12-10 17:49:14 -0500385 Ice::Inst *store = nullptr;
386 Ice::Operand *storeValue = nullptr;
387 bool unmatchedLoads = false;
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500388
Ben Clayton713b8d32019-12-17 20:37:56 +0000389 for(auto &loadStoreInst : getLoadStoreInsts(singleBasicBlock))
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500390 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000391 Ice::Inst *inst = loadStoreInst.inst;
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500392
Nicolas Capens157ba262019-12-10 17:49:14 -0500393 if((loadStoreInst.address != address) || inst->isDeleted())
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500394 {
395 continue;
396 }
397
Nicolas Capens157ba262019-12-10 17:49:14 -0500398 if(loadStoreInst.isStore)
Alexis Hetu932640b2018-06-20 15:35:53 -0400399 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500400 // New store found. If we had a previous one, try to eliminate it.
401 if(store && !unmatchedLoads)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500402 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500403 // If the previous store is wider than the new one, we can't eliminate it
404 // because there could be a wide load reading its non-overwritten data.
405 if(storeSize(inst) >= storeSize(store))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500406 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500407 deleteInstruction(store);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500408 }
409 }
410
Nicolas Capens157ba262019-12-10 17:49:14 -0500411 store = inst;
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500412 storeValue = store->getData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500413 unmatchedLoads = false;
414 }
415 else
416 {
417 if(!loadTypeMatchesStore(inst, store))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500418 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500419 unmatchedLoads = true;
420 continue;
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500421 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500422
Antonio Maioranob3d9a2a2020-02-14 14:38:04 -0500423 // TODO(b/148272103): InstLoad assumes that a constant ptr is an offset, rather than an
424 // absolute address. We need to make sure we don't replace a variable with a constant
425 // on this load.
426 if(llvm::isa<Ice::Constant>(storeValue))
427 {
Antonio Maiorano5ff1de52020-03-03 19:53:13 -0500428 unmatchedLoads = true;
Antonio Maioranob3d9a2a2020-02-14 14:38:04 -0500429 continue;
430 }
431
Nicolas Capens157ba262019-12-10 17:49:14 -0500432 replace(inst, storeValue);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500433 }
434 }
435 }
436 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500437
Nicolas Capens157ba262019-12-10 17:49:14 -0500438 for(auto loadStoreInstVector : allocatedVectors)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500439 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500440 delete loadStoreInstVector;
441 }
442}
Nicolas Capense205c3d2016-11-30 15:14:28 -0500443
Nicolas Capens157ba262019-12-10 17:49:14 -0500444void Optimizer::analyzeUses(Ice::Cfg *function)
445{
446 for(Ice::CfgNode *basicBlock : function->getNodes())
447 {
448 for(Ice::Inst &instruction : basicBlock->getInsts())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500449 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500450 if(instruction.isDeleted())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500451 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500452 continue;
453 }
Alexis Hetu932640b2018-06-20 15:35:53 -0400454
Nicolas Capens157ba262019-12-10 17:49:14 -0500455 setNode(&instruction, basicBlock);
456 if(instruction.getDest())
457 {
458 setDefinition(instruction.getDest(), &instruction);
459 }
460
461 for(Ice::SizeT i = 0; i < instruction.getSrcSize(); i++)
462 {
463 Ice::SizeT unique = 0;
464 for(; unique < i; unique++)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500465 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500466 if(instruction.getSrc(i) == instruction.getSrc(unique))
Alexis Hetu932640b2018-06-20 15:35:53 -0400467 {
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500468 break;
469 }
470 }
471
Nicolas Capens157ba262019-12-10 17:49:14 -0500472 if(i == unique)
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500473 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500474 Ice::Operand *src = instruction.getSrc(i);
475 getUses(src)->insert(src, &instruction);
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500476 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500477 }
478 }
479 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500480}
481
Nicolas Capens157ba262019-12-10 17:49:14 -0500482void Optimizer::replace(Ice::Inst *instruction, Ice::Operand *newValue)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500483{
Nicolas Capens157ba262019-12-10 17:49:14 -0500484 Ice::Variable *oldValue = instruction->getDest();
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500485
Nicolas Capens157ba262019-12-10 17:49:14 -0500486 if(!newValue)
487 {
488 newValue = context->getConstantUndef(oldValue->getType());
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500489 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500490
491 if(hasUses(oldValue))
492 {
493 for(Ice::Inst *use : *getUses(oldValue))
494 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000495 assert(!use->isDeleted()); // Should have been removed from uses already
Nicolas Capens157ba262019-12-10 17:49:14 -0500496
497 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
498 {
499 if(use->getSrc(i) == oldValue)
500 {
501 use->replaceSource(i, newValue);
502 }
503 }
504
505 getUses(newValue)->insert(newValue, use);
506 }
507
508 setUses(oldValue, nullptr);
509 }
510
511 deleteInstruction(instruction);
512}
513
514void Optimizer::deleteInstruction(Ice::Inst *instruction)
515{
516 if(!instruction || instruction->isDeleted())
517 {
518 return;
519 }
520
521 instruction->setDeleted();
522
523 for(Ice::SizeT i = 0; i < instruction->getSrcSize(); i++)
524 {
525 Ice::Operand *src = instruction->getSrc(i);
526
527 if(hasUses(src))
528 {
529 auto &srcUses = *getUses(src);
530
531 srcUses.erase(instruction);
532
533 if(srcUses.empty())
534 {
535 setUses(src, nullptr);
536
537 if(Ice::Variable *var = llvm::dyn_cast<Ice::Variable>(src))
538 {
539 deleteInstruction(getDefinition(var));
540 }
541 }
542 }
543 }
544}
545
546bool Optimizer::isDead(Ice::Inst *instruction)
547{
548 Ice::Variable *dest = instruction->getDest();
549
550 if(dest)
551 {
552 return (!hasUses(dest) || getUses(dest)->empty()) && !instruction->hasSideEffects();
553 }
554 else if(isStore(*instruction))
555 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500556 if(Ice::Variable *address = llvm::dyn_cast<Ice::Variable>(instruction->getStoreAddress()))
Nicolas Capens157ba262019-12-10 17:49:14 -0500557 {
558 Ice::Inst *def = getDefinition(address);
559
560 if(def && llvm::isa<Ice::InstAlloca>(def))
561 {
562 if(hasUses(address))
563 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000564 Optimizer::Uses *uses = getUses(address);
565 return uses->size() == uses->stores.size(); // Dead if all uses are stores
Nicolas Capens157ba262019-12-10 17:49:14 -0500566 }
567 else
568 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000569 return true; // No uses
Nicolas Capens157ba262019-12-10 17:49:14 -0500570 }
571 }
572 }
573 }
574
575 return false;
576}
577
Nicolas Capens33a77f72021-02-08 15:04:38 -0500578const Ice::InstIntrinsic *Optimizer::asLoadSubVector(const Ice::Inst *instruction)
Nicolas Capens157ba262019-12-10 17:49:14 -0500579{
Nicolas Capens33a77f72021-02-08 15:04:38 -0500580 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsic>(instruction))
Nicolas Capens157ba262019-12-10 17:49:14 -0500581 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500582 if(instrinsic->getIntrinsicID() == Ice::Intrinsics::LoadSubVector)
Nicolas Capens157ba262019-12-10 17:49:14 -0500583 {
584 return instrinsic;
585 }
586 }
587
588 return nullptr;
589}
590
Nicolas Capens33a77f72021-02-08 15:04:38 -0500591const Ice::InstIntrinsic *Optimizer::asStoreSubVector(const Ice::Inst *instruction)
Nicolas Capens157ba262019-12-10 17:49:14 -0500592{
Nicolas Capens33a77f72021-02-08 15:04:38 -0500593 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsic>(instruction))
Nicolas Capens157ba262019-12-10 17:49:14 -0500594 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500595 if(instrinsic->getIntrinsicID() == Ice::Intrinsics::StoreSubVector)
Nicolas Capens157ba262019-12-10 17:49:14 -0500596 {
597 return instrinsic;
598 }
599 }
600
601 return nullptr;
602}
603
604bool Optimizer::isLoad(const Ice::Inst &instruction)
605{
606 if(llvm::isa<Ice::InstLoad>(&instruction))
607 {
608 return true;
609 }
610
611 return asLoadSubVector(&instruction) != nullptr;
612}
613
614bool Optimizer::isStore(const Ice::Inst &instruction)
615{
616 if(llvm::isa<Ice::InstStore>(&instruction))
617 {
618 return true;
619 }
620
621 return asStoreSubVector(&instruction) != nullptr;
622}
623
Nicolas Capens157ba262019-12-10 17:49:14 -0500624std::size_t Optimizer::storeSize(const Ice::Inst *store)
625{
626 assert(isStore(*store));
627
628 if(auto *instStore = llvm::dyn_cast<Ice::InstStore>(store))
629 {
630 return Ice::typeWidthInBytes(instStore->getData()->getType());
631 }
632
633 if(auto *storeSubVector = asStoreSubVector(store))
634 {
635 return llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(3))->getValue();
636 }
637
638 return 0;
639}
640
641bool Optimizer::loadTypeMatchesStore(const Ice::Inst *load, const Ice::Inst *store)
642{
643 if(!load || !store)
644 {
645 return false;
646 }
647
648 assert(isLoad(*load) && isStore(*store));
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500649 assert(load->getLoadAddress() == store->getStoreAddress());
Nicolas Capens157ba262019-12-10 17:49:14 -0500650
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500651 if(store->getData()->getType() != load->getDest()->getType())
Nicolas Capens157ba262019-12-10 17:49:14 -0500652 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500653 return false;
Nicolas Capens157ba262019-12-10 17:49:14 -0500654 }
655
656 if(auto *storeSubVector = asStoreSubVector(store))
657 {
658 if(auto *loadSubVector = asLoadSubVector(load))
659 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500660 // Check for matching sub-vector width.
661 return llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(2))->getValue() ==
662 llvm::cast<Ice::ConstantInteger32>(loadSubVector->getSrc(1))->getValue();
Nicolas Capens157ba262019-12-10 17:49:14 -0500663 }
664 }
665
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500666 return true;
Nicolas Capens157ba262019-12-10 17:49:14 -0500667}
668
Ben Clayton713b8d32019-12-17 20:37:56 +0000669Optimizer::Uses *Optimizer::getUses(Ice::Operand *operand)
Nicolas Capens157ba262019-12-10 17:49:14 -0500670{
Ben Clayton713b8d32019-12-17 20:37:56 +0000671 Optimizer::Uses *uses = (Optimizer::Uses *)operand->Ice::Operand::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500672 if(!uses)
673 {
674 uses = new Optimizer::Uses;
675 setUses(operand, uses);
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500676 operandsWithUses.push_back(operand);
Nicolas Capens157ba262019-12-10 17:49:14 -0500677 }
678 return uses;
679}
680
Ben Clayton713b8d32019-12-17 20:37:56 +0000681void Optimizer::setUses(Ice::Operand *operand, Optimizer::Uses *uses)
Nicolas Capens157ba262019-12-10 17:49:14 -0500682{
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500683 if(auto *oldUses = reinterpret_cast<Optimizer::Uses *>(operand->Ice::Operand::getExternalData()))
684 {
685 delete oldUses;
686 }
687
Nicolas Capens157ba262019-12-10 17:49:14 -0500688 operand->Ice::Operand::setExternalData(uses);
689}
690
Ben Clayton713b8d32019-12-17 20:37:56 +0000691bool Optimizer::hasUses(Ice::Operand *operand) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500692{
693 return operand->Ice::Operand::getExternalData() != nullptr;
694}
695
Ben Clayton713b8d32019-12-17 20:37:56 +0000696Ice::CfgNode *Optimizer::getNode(Ice::Inst *inst)
Nicolas Capens157ba262019-12-10 17:49:14 -0500697{
Ben Clayton713b8d32019-12-17 20:37:56 +0000698 return (Ice::CfgNode *)inst->Ice::Inst::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500699}
700
Ben Clayton713b8d32019-12-17 20:37:56 +0000701void Optimizer::setNode(Ice::Inst *inst, Ice::CfgNode *node)
Nicolas Capens157ba262019-12-10 17:49:14 -0500702{
703 inst->Ice::Inst::setExternalData(node);
704}
705
Ben Clayton713b8d32019-12-17 20:37:56 +0000706Ice::Inst *Optimizer::getDefinition(Ice::Variable *var)
Nicolas Capens157ba262019-12-10 17:49:14 -0500707{
Ben Clayton713b8d32019-12-17 20:37:56 +0000708 return (Ice::Inst *)var->Ice::Variable::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500709}
710
Ben Clayton713b8d32019-12-17 20:37:56 +0000711void Optimizer::setDefinition(Ice::Variable *var, Ice::Inst *inst)
Nicolas Capens157ba262019-12-10 17:49:14 -0500712{
713 var->Ice::Variable::setExternalData(inst);
714}
715
Ben Clayton713b8d32019-12-17 20:37:56 +0000716const std::vector<Optimizer::LoadStoreInst> &Optimizer::getLoadStoreInsts(Ice::CfgNode *node)
Nicolas Capens157ba262019-12-10 17:49:14 -0500717{
Ben Clayton713b8d32019-12-17 20:37:56 +0000718 return *((const std::vector<LoadStoreInst> *)node->Ice::CfgNode::getExternalData());
Nicolas Capens157ba262019-12-10 17:49:14 -0500719}
720
Ben Clayton713b8d32019-12-17 20:37:56 +0000721void Optimizer::setLoadStoreInsts(Ice::CfgNode *node, std::vector<LoadStoreInst> *insts)
Nicolas Capens157ba262019-12-10 17:49:14 -0500722{
723 node->Ice::CfgNode::setExternalData(insts);
724}
725
Ben Clayton713b8d32019-12-17 20:37:56 +0000726bool Optimizer::hasLoadStoreInsts(Ice::CfgNode *node) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500727{
728 return node->Ice::CfgNode::getExternalData() != nullptr;
729}
730
731bool Optimizer::Uses::areOnlyLoadStore() const
732{
733 return size() == (loads.size() + stores.size());
734}
735
736void Optimizer::Uses::insert(Ice::Operand *value, Ice::Inst *instruction)
737{
738 push_back(instruction);
739
740 if(isLoad(*instruction))
741 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500742 if(value == instruction->getLoadAddress())
Nicolas Capens157ba262019-12-10 17:49:14 -0500743 {
744 loads.push_back(instruction);
745 }
746 }
747 else if(isStore(*instruction))
748 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500749 if(value == instruction->getStoreAddress())
Nicolas Capens157ba262019-12-10 17:49:14 -0500750 {
751 stores.push_back(instruction);
752 }
753 }
754}
755
756void Optimizer::Uses::erase(Ice::Inst *instruction)
757{
758 auto &uses = *this;
759
760 for(size_t i = 0; i < uses.size(); i++)
761 {
762 if(uses[i] == instruction)
763 {
764 uses[i] = back();
765 pop_back();
766
767 for(size_t i = 0; i < loads.size(); i++)
768 {
769 if(loads[i] == instruction)
770 {
771 loads[i] = loads.back();
772 loads.pop_back();
773 break;
774 }
775 }
776
777 for(size_t i = 0; i < stores.size(); i++)
778 {
779 if(stores[i] == instruction)
780 {
781 stores[i] = stores.back();
782 stores.pop_back();
783 break;
784 }
785 }
786
787 break;
788 }
789 }
790}
791
Ben Clayton713b8d32019-12-17 20:37:56 +0000792} // anonymous namespace
Nicolas Capens157ba262019-12-10 17:49:14 -0500793
794namespace rr {
795
796void optimize(Ice::Cfg *function)
797{
798 Optimizer optimizer;
799
800 optimizer.run(function);
801}
802
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500803} // namespace rr