blob: 86cface59e5f51ea08c75c58bbe9d9c526bdaf41 [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
40 static const Ice::InstIntrinsicCall *asLoadSubVector(const Ice::Inst *instruction);
41 static const Ice::InstIntrinsicCall *asStoreSubVector(const Ice::Inst *instruction);
42 static bool isLoad(const Ice::Inst &instruction);
43 static bool isStore(const Ice::Inst &instruction);
44 static Ice::Operand *storeAddress(const Ice::Inst *instruction);
45 static Ice::Operand *loadAddress(const Ice::Inst *instruction);
46 static Ice::Operand *storeData(const Ice::Inst *instruction);
47 static std::size_t storeSize(const Ice::Inst *instruction);
48 static bool loadTypeMatchesStore(const Ice::Inst *load, const Ice::Inst *store);
49
50 Ice::Cfg *function;
51 Ice::GlobalContext *context;
52
Ben Clayton713b8d32019-12-17 20:37:56 +000053 struct Uses : std::vector<Ice::Inst *>
Nicolas Capens2ae9d742016-11-24 14:43:05 -050054 {
Nicolas Capens157ba262019-12-10 17:49:14 -050055 bool areOnlyLoadStore() const;
56 void insert(Ice::Operand *value, Ice::Inst *instruction);
57 void erase(Ice::Inst *instruction);
Nicolas Capens2ae9d742016-11-24 14:43:05 -050058
Ben Clayton713b8d32019-12-17 20:37:56 +000059 std::vector<Ice::Inst *> loads;
60 std::vector<Ice::Inst *> stores;
Nicolas Capens2ae9d742016-11-24 14:43:05 -050061 };
62
Nicolas Capens157ba262019-12-10 17:49:14 -050063 struct LoadStoreInst
Nicolas Capens2ae9d742016-11-24 14:43:05 -050064 {
Ben Clayton713b8d32019-12-17 20:37:56 +000065 LoadStoreInst(Ice::Inst *inst, bool isStore)
66 : inst(inst)
67 , address(isStore ? storeAddress(inst) : loadAddress(inst))
68 , isStore(isStore)
Alexis Hetu932640b2018-06-20 15:35:53 -040069 {
Alexis Hetu932640b2018-06-20 15:35:53 -040070 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -050071
Ben Clayton713b8d32019-12-17 20:37:56 +000072 Ice::Inst *inst;
Nicolas Capens157ba262019-12-10 17:49:14 -050073 Ice::Operand *address;
74 bool isStore;
75 };
76
Ben Clayton713b8d32019-12-17 20:37:56 +000077 Optimizer::Uses *getUses(Ice::Operand *);
78 void setUses(Ice::Operand *, Optimizer::Uses *);
79 bool hasUses(Ice::Operand *) const;
Nicolas Capens157ba262019-12-10 17:49:14 -050080
Ben Clayton713b8d32019-12-17 20:37:56 +000081 Ice::CfgNode *getNode(Ice::Inst *);
82 void setNode(Ice::Inst *, Ice::CfgNode *);
Nicolas Capens157ba262019-12-10 17:49:14 -050083
Ben Clayton713b8d32019-12-17 20:37:56 +000084 Ice::Inst *getDefinition(Ice::Variable *);
85 void setDefinition(Ice::Variable *, Ice::Inst *);
Nicolas Capens157ba262019-12-10 17:49:14 -050086
Ben Clayton713b8d32019-12-17 20:37:56 +000087 const std::vector<LoadStoreInst> &getLoadStoreInsts(Ice::CfgNode *);
88 void setLoadStoreInsts(Ice::CfgNode *, std::vector<LoadStoreInst> *);
89 bool hasLoadStoreInsts(Ice::CfgNode *node) const;
Nicolas Capens157ba262019-12-10 17:49:14 -050090
Ben Clayton713b8d32019-12-17 20:37:56 +000091 std::vector<Optimizer::Uses *> allocatedUses;
Nicolas Capens157ba262019-12-10 17:49:14 -050092};
93
94void Optimizer::run(Ice::Cfg *function)
95{
96 this->function = function;
97 this->context = function->getContext();
98
99 analyzeUses(function);
100
101 eliminateDeadCode();
102 eliminateUnitializedLoads();
103 eliminateLoadsFollowingSingleStore();
104 optimizeStoresInSingleBasicBlock();
105 eliminateDeadCode();
106
107 for(auto uses : allocatedUses)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500108 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500109 delete uses;
110 }
111 allocatedUses.clear();
112}
113
114void Optimizer::eliminateDeadCode()
115{
116 bool modified;
117 do
118 {
119 modified = false;
120 for(Ice::CfgNode *basicBlock : function->getNodes())
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500121 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500122 for(Ice::Inst &inst : Ice::reverse_range(basicBlock->getInsts()))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500123 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500124 if(inst.isDeleted())
125 {
126 continue;
127 }
128
129 if(isDead(&inst))
130 {
131 deleteInstruction(&inst);
132 modified = true;
133 }
134 }
135 }
Ben Clayton713b8d32019-12-17 20:37:56 +0000136 } while(modified);
Nicolas Capens157ba262019-12-10 17:49:14 -0500137}
138
139void Optimizer::eliminateUnitializedLoads()
140{
141 Ice::CfgNode *entryBlock = function->getEntryNode();
142
143 for(Ice::Inst &alloca : entryBlock->getInsts())
144 {
145 if(alloca.isDeleted())
146 {
147 continue;
148 }
149
150 if(!llvm::isa<Ice::InstAlloca>(alloca))
151 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000152 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500153 }
154
155 Ice::Operand *address = alloca.getDest();
156
157 if(!hasUses(address))
158 {
159 continue;
160 }
161
162 const auto &addressUses = *getUses(address);
163
164 if(!addressUses.areOnlyLoadStore())
165 {
166 continue;
167 }
168
169 if(addressUses.stores.empty())
170 {
171 for(Ice::Inst *load : addressUses.loads)
172 {
173 Ice::Variable *loadData = load->getDest();
174
175 if(hasUses(loadData))
176 {
177 for(Ice::Inst *use : *getUses(loadData))
178 {
179 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
180 {
181 if(use->getSrc(i) == loadData)
182 {
183 auto *undef = context->getConstantUndef(loadData->getType());
184
185 use->replaceSource(i, undef);
186 }
187 }
188 }
189
190 setUses(loadData, nullptr);
191 }
192
193 load->setDeleted();
194 }
195
196 alloca.setDeleted();
197 setUses(address, nullptr);
198 }
199 }
200}
201
202void Optimizer::eliminateLoadsFollowingSingleStore()
203{
204 Ice::CfgNode *entryBlock = function->getEntryNode();
205
206 for(Ice::Inst &alloca : entryBlock->getInsts())
207 {
208 if(alloca.isDeleted())
209 {
210 continue;
211 }
212
213 if(!llvm::isa<Ice::InstAlloca>(alloca))
214 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000215 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500216 }
217
218 Ice::Operand *address = alloca.getDest();
219
220 if(!hasUses(address))
221 {
222 continue;
223 }
224
225 auto &addressUses = *getUses(address);
226
227 if(!addressUses.areOnlyLoadStore())
228 {
229 continue;
230 }
231
232 if(addressUses.stores.size() == 1)
233 {
234 Ice::Inst *store = addressUses.stores[0];
235 Ice::Operand *storeValue = storeData(store);
236
237 for(Ice::Inst *load = &*++store->getIterator(), *next = nullptr; load != next; next = load, load = &*++store->getIterator())
238 {
239 if(load->isDeleted() || !isLoad(*load))
240 {
241 continue;
242 }
243
244 if(loadAddress(load) != address)
245 {
246 continue;
247 }
248
249 if(!loadTypeMatchesStore(load, store))
250 {
251 continue;
252 }
253
254 replace(load, storeValue);
255
256 for(size_t i = 0; i < addressUses.loads.size(); i++)
257 {
258 if(addressUses.loads[i] == load)
259 {
260 addressUses.loads[i] = addressUses.loads.back();
261 addressUses.loads.pop_back();
262 break;
263 }
264 }
265
266 for(size_t i = 0; i < addressUses.size(); i++)
267 {
268 if(addressUses[i] == load)
269 {
270 addressUses[i] = addressUses.back();
271 addressUses.pop_back();
272 break;
273 }
274 }
275
276 if(addressUses.size() == 1)
277 {
278 assert(addressUses[0] == store);
279
280 alloca.setDeleted();
281 store->setDeleted();
282 setUses(address, nullptr);
283
284 if(hasUses(storeValue))
285 {
286 auto &valueUses = *getUses(storeValue);
287
288 for(size_t i = 0; i < valueUses.size(); i++)
289 {
290 if(valueUses[i] == store)
291 {
292 valueUses[i] = valueUses.back();
293 valueUses.pop_back();
294 break;
295 }
296 }
297
298 if(valueUses.empty())
299 {
300 setUses(storeValue, nullptr);
301 }
302 }
303
304 break;
305 }
306 }
307 }
308 }
309}
310
311void Optimizer::optimizeStoresInSingleBasicBlock()
312{
313 Ice::CfgNode *entryBlock = function->getEntryNode();
314
Ben Clayton713b8d32019-12-17 20:37:56 +0000315 std::vector<std::vector<LoadStoreInst> *> allocatedVectors;
Nicolas Capens157ba262019-12-10 17:49:14 -0500316
317 for(Ice::Inst &alloca : entryBlock->getInsts())
318 {
319 if(alloca.isDeleted())
320 {
321 continue;
322 }
323
324 if(!llvm::isa<Ice::InstAlloca>(alloca))
325 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000326 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500327 }
328
329 Ice::Operand *address = alloca.getDest();
330
331 if(!hasUses(address))
332 {
333 continue;
334 }
335
336 const auto &addressUses = *getUses(address);
337
338 if(!addressUses.areOnlyLoadStore())
339 {
340 continue;
341 }
342
343 Ice::CfgNode *singleBasicBlock = getNode(addressUses.stores[0]);
344
345 for(size_t i = 1; i < addressUses.stores.size(); i++)
346 {
347 Ice::Inst *store = addressUses.stores[i];
348 if(getNode(store) != singleBasicBlock)
349 {
350 singleBasicBlock = nullptr;
351 break;
352 }
353 }
354
355 if(singleBasicBlock)
356 {
357 if(!hasLoadStoreInsts(singleBasicBlock))
358 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000359 std::vector<LoadStoreInst> *loadStoreInstVector = new std::vector<LoadStoreInst>();
Nicolas Capens157ba262019-12-10 17:49:14 -0500360 setLoadStoreInsts(singleBasicBlock, loadStoreInstVector);
361 allocatedVectors.push_back(loadStoreInstVector);
362 for(Ice::Inst &inst : singleBasicBlock->getInsts())
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500363 {
364 if(inst.isDeleted())
365 {
366 continue;
367 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500368
Nicolas Capens157ba262019-12-10 17:49:14 -0500369 bool isStoreInst = isStore(inst);
370 bool isLoadInst = isLoad(inst);
371
372 if(isStoreInst || isLoadInst)
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500373 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500374 loadStoreInstVector->push_back(LoadStoreInst(&inst, isStoreInst));
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500375 }
376 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500377 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500378
Nicolas Capens157ba262019-12-10 17:49:14 -0500379 Ice::Inst *store = nullptr;
380 Ice::Operand *storeValue = nullptr;
381 bool unmatchedLoads = false;
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500382
Ben Clayton713b8d32019-12-17 20:37:56 +0000383 for(auto &loadStoreInst : getLoadStoreInsts(singleBasicBlock))
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500384 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000385 Ice::Inst *inst = loadStoreInst.inst;
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500386
Nicolas Capens157ba262019-12-10 17:49:14 -0500387 if((loadStoreInst.address != address) || inst->isDeleted())
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500388 {
389 continue;
390 }
391
Nicolas Capens157ba262019-12-10 17:49:14 -0500392 if(loadStoreInst.isStore)
Alexis Hetu932640b2018-06-20 15:35:53 -0400393 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500394 // New store found. If we had a previous one, try to eliminate it.
395 if(store && !unmatchedLoads)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500396 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500397 // If the previous store is wider than the new one, we can't eliminate it
398 // because there could be a wide load reading its non-overwritten data.
399 if(storeSize(inst) >= storeSize(store))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500400 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500401 deleteInstruction(store);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500402 }
403 }
404
Nicolas Capens157ba262019-12-10 17:49:14 -0500405 store = inst;
406 storeValue = storeData(store);
407 unmatchedLoads = false;
408 }
409 else
410 {
411 if(!loadTypeMatchesStore(inst, store))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500412 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500413 unmatchedLoads = true;
414 continue;
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500415 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500416
417 replace(inst, storeValue);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500418 }
419 }
420 }
421 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500422
Nicolas Capens157ba262019-12-10 17:49:14 -0500423 for(auto loadStoreInstVector : allocatedVectors)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500424 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500425 delete loadStoreInstVector;
426 }
427}
Nicolas Capense205c3d2016-11-30 15:14:28 -0500428
Nicolas Capens157ba262019-12-10 17:49:14 -0500429void Optimizer::analyzeUses(Ice::Cfg *function)
430{
431 for(Ice::CfgNode *basicBlock : function->getNodes())
432 {
433 for(Ice::Inst &instruction : basicBlock->getInsts())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500434 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500435 if(instruction.isDeleted())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500436 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500437 continue;
438 }
Alexis Hetu932640b2018-06-20 15:35:53 -0400439
Nicolas Capens157ba262019-12-10 17:49:14 -0500440 setNode(&instruction, basicBlock);
441 if(instruction.getDest())
442 {
443 setDefinition(instruction.getDest(), &instruction);
444 }
445
446 for(Ice::SizeT i = 0; i < instruction.getSrcSize(); i++)
447 {
448 Ice::SizeT unique = 0;
449 for(; unique < i; unique++)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500450 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500451 if(instruction.getSrc(i) == instruction.getSrc(unique))
Alexis Hetu932640b2018-06-20 15:35:53 -0400452 {
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500453 break;
454 }
455 }
456
Nicolas Capens157ba262019-12-10 17:49:14 -0500457 if(i == unique)
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500458 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500459 Ice::Operand *src = instruction.getSrc(i);
460 getUses(src)->insert(src, &instruction);
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500461 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500462 }
463 }
464 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500465}
466
Nicolas Capens157ba262019-12-10 17:49:14 -0500467void Optimizer::replace(Ice::Inst *instruction, Ice::Operand *newValue)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500468{
Nicolas Capens157ba262019-12-10 17:49:14 -0500469 Ice::Variable *oldValue = instruction->getDest();
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500470
Nicolas Capens157ba262019-12-10 17:49:14 -0500471 if(!newValue)
472 {
473 newValue = context->getConstantUndef(oldValue->getType());
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500474 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500475
476 if(hasUses(oldValue))
477 {
478 for(Ice::Inst *use : *getUses(oldValue))
479 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000480 assert(!use->isDeleted()); // Should have been removed from uses already
Nicolas Capens157ba262019-12-10 17:49:14 -0500481
482 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
483 {
484 if(use->getSrc(i) == oldValue)
485 {
486 use->replaceSource(i, newValue);
487 }
488 }
489
490 getUses(newValue)->insert(newValue, use);
491 }
492
493 setUses(oldValue, nullptr);
494 }
495
496 deleteInstruction(instruction);
497}
498
499void Optimizer::deleteInstruction(Ice::Inst *instruction)
500{
501 if(!instruction || instruction->isDeleted())
502 {
503 return;
504 }
505
506 instruction->setDeleted();
507
508 for(Ice::SizeT i = 0; i < instruction->getSrcSize(); i++)
509 {
510 Ice::Operand *src = instruction->getSrc(i);
511
512 if(hasUses(src))
513 {
514 auto &srcUses = *getUses(src);
515
516 srcUses.erase(instruction);
517
518 if(srcUses.empty())
519 {
520 setUses(src, nullptr);
521
522 if(Ice::Variable *var = llvm::dyn_cast<Ice::Variable>(src))
523 {
524 deleteInstruction(getDefinition(var));
525 }
526 }
527 }
528 }
529}
530
531bool Optimizer::isDead(Ice::Inst *instruction)
532{
533 Ice::Variable *dest = instruction->getDest();
534
535 if(dest)
536 {
537 return (!hasUses(dest) || getUses(dest)->empty()) && !instruction->hasSideEffects();
538 }
539 else if(isStore(*instruction))
540 {
541 if(Ice::Variable *address = llvm::dyn_cast<Ice::Variable>(storeAddress(instruction)))
542 {
543 Ice::Inst *def = getDefinition(address);
544
545 if(def && llvm::isa<Ice::InstAlloca>(def))
546 {
547 if(hasUses(address))
548 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000549 Optimizer::Uses *uses = getUses(address);
550 return uses->size() == uses->stores.size(); // Dead if all uses are stores
Nicolas Capens157ba262019-12-10 17:49:14 -0500551 }
552 else
553 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000554 return true; // No uses
Nicolas Capens157ba262019-12-10 17:49:14 -0500555 }
556 }
557 }
558 }
559
560 return false;
561}
562
563const Ice::InstIntrinsicCall *Optimizer::asLoadSubVector(const Ice::Inst *instruction)
564{
565 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
566 {
567 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector)
568 {
569 return instrinsic;
570 }
571 }
572
573 return nullptr;
574}
575
576const Ice::InstIntrinsicCall *Optimizer::asStoreSubVector(const Ice::Inst *instruction)
577{
578 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
579 {
580 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector)
581 {
582 return instrinsic;
583 }
584 }
585
586 return nullptr;
587}
588
589bool Optimizer::isLoad(const Ice::Inst &instruction)
590{
591 if(llvm::isa<Ice::InstLoad>(&instruction))
592 {
593 return true;
594 }
595
596 return asLoadSubVector(&instruction) != nullptr;
597}
598
599bool Optimizer::isStore(const Ice::Inst &instruction)
600{
601 if(llvm::isa<Ice::InstStore>(&instruction))
602 {
603 return true;
604 }
605
606 return asStoreSubVector(&instruction) != nullptr;
607}
608
609Ice::Operand *Optimizer::storeAddress(const Ice::Inst *instruction)
610{
611 assert(isStore(*instruction));
612
613 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
614 {
615 return store->getAddr();
616 }
617
618 if(auto *storeSubVector = asStoreSubVector(instruction))
619 {
620 return storeSubVector->getSrc(2);
621 }
622
623 return nullptr;
624}
625
626Ice::Operand *Optimizer::loadAddress(const Ice::Inst *instruction)
627{
628 assert(isLoad(*instruction));
629
630 if(auto *load = llvm::dyn_cast<Ice::InstLoad>(instruction))
631 {
632 return load->getSourceAddress();
633 }
634
635 if(auto *loadSubVector = asLoadSubVector(instruction))
636 {
637 return loadSubVector->getSrc(1);
638 }
639
640 return nullptr;
641}
642
643Ice::Operand *Optimizer::storeData(const Ice::Inst *instruction)
644{
645 assert(isStore(*instruction));
646
647 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
648 {
649 return store->getData();
650 }
651
652 if(auto *storeSubVector = asStoreSubVector(instruction))
653 {
654 return storeSubVector->getSrc(1);
655 }
656
657 return nullptr;
658}
659
660std::size_t Optimizer::storeSize(const Ice::Inst *store)
661{
662 assert(isStore(*store));
663
664 if(auto *instStore = llvm::dyn_cast<Ice::InstStore>(store))
665 {
666 return Ice::typeWidthInBytes(instStore->getData()->getType());
667 }
668
669 if(auto *storeSubVector = asStoreSubVector(store))
670 {
671 return llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(3))->getValue();
672 }
673
674 return 0;
675}
676
677bool Optimizer::loadTypeMatchesStore(const Ice::Inst *load, const Ice::Inst *store)
678{
679 if(!load || !store)
680 {
681 return false;
682 }
683
684 assert(isLoad(*load) && isStore(*store));
685 assert(loadAddress(load) == storeAddress(store));
686
687 if(auto *instStore = llvm::dyn_cast<Ice::InstStore>(store))
688 {
689 if(auto *instLoad = llvm::dyn_cast<Ice::InstLoad>(load))
690 {
691 return instStore->getData()->getType() == instLoad->getDest()->getType();
692 }
693 }
694
695 if(auto *storeSubVector = asStoreSubVector(store))
696 {
697 if(auto *loadSubVector = asLoadSubVector(load))
698 {
699 // Check for matching type and sub-vector width.
700 return storeSubVector->getSrc(1)->getType() == loadSubVector->getDest()->getType() &&
701 llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(3))->getValue() ==
Ben Clayton713b8d32019-12-17 20:37:56 +0000702 llvm::cast<Ice::ConstantInteger32>(loadSubVector->getSrc(2))->getValue();
Nicolas Capens157ba262019-12-10 17:49:14 -0500703 }
704 }
705
706 return false;
707}
708
Ben Clayton713b8d32019-12-17 20:37:56 +0000709Optimizer::Uses *Optimizer::getUses(Ice::Operand *operand)
Nicolas Capens157ba262019-12-10 17:49:14 -0500710{
Ben Clayton713b8d32019-12-17 20:37:56 +0000711 Optimizer::Uses *uses = (Optimizer::Uses *)operand->Ice::Operand::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500712 if(!uses)
713 {
714 uses = new Optimizer::Uses;
715 setUses(operand, uses);
716 allocatedUses.push_back(uses);
717 }
718 return uses;
719}
720
Ben Clayton713b8d32019-12-17 20:37:56 +0000721void Optimizer::setUses(Ice::Operand *operand, Optimizer::Uses *uses)
Nicolas Capens157ba262019-12-10 17:49:14 -0500722{
723 operand->Ice::Operand::setExternalData(uses);
724}
725
Ben Clayton713b8d32019-12-17 20:37:56 +0000726bool Optimizer::hasUses(Ice::Operand *operand) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500727{
728 return operand->Ice::Operand::getExternalData() != nullptr;
729}
730
Ben Clayton713b8d32019-12-17 20:37:56 +0000731Ice::CfgNode *Optimizer::getNode(Ice::Inst *inst)
Nicolas Capens157ba262019-12-10 17:49:14 -0500732{
Ben Clayton713b8d32019-12-17 20:37:56 +0000733 return (Ice::CfgNode *)inst->Ice::Inst::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500734}
735
Ben Clayton713b8d32019-12-17 20:37:56 +0000736void Optimizer::setNode(Ice::Inst *inst, Ice::CfgNode *node)
Nicolas Capens157ba262019-12-10 17:49:14 -0500737{
738 inst->Ice::Inst::setExternalData(node);
739}
740
Ben Clayton713b8d32019-12-17 20:37:56 +0000741Ice::Inst *Optimizer::getDefinition(Ice::Variable *var)
Nicolas Capens157ba262019-12-10 17:49:14 -0500742{
Ben Clayton713b8d32019-12-17 20:37:56 +0000743 return (Ice::Inst *)var->Ice::Variable::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500744}
745
Ben Clayton713b8d32019-12-17 20:37:56 +0000746void Optimizer::setDefinition(Ice::Variable *var, Ice::Inst *inst)
Nicolas Capens157ba262019-12-10 17:49:14 -0500747{
748 var->Ice::Variable::setExternalData(inst);
749}
750
Ben Clayton713b8d32019-12-17 20:37:56 +0000751const std::vector<Optimizer::LoadStoreInst> &Optimizer::getLoadStoreInsts(Ice::CfgNode *node)
Nicolas Capens157ba262019-12-10 17:49:14 -0500752{
Ben Clayton713b8d32019-12-17 20:37:56 +0000753 return *((const std::vector<LoadStoreInst> *)node->Ice::CfgNode::getExternalData());
Nicolas Capens157ba262019-12-10 17:49:14 -0500754}
755
Ben Clayton713b8d32019-12-17 20:37:56 +0000756void Optimizer::setLoadStoreInsts(Ice::CfgNode *node, std::vector<LoadStoreInst> *insts)
Nicolas Capens157ba262019-12-10 17:49:14 -0500757{
758 node->Ice::CfgNode::setExternalData(insts);
759}
760
Ben Clayton713b8d32019-12-17 20:37:56 +0000761bool Optimizer::hasLoadStoreInsts(Ice::CfgNode *node) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500762{
763 return node->Ice::CfgNode::getExternalData() != nullptr;
764}
765
766bool Optimizer::Uses::areOnlyLoadStore() const
767{
768 return size() == (loads.size() + stores.size());
769}
770
771void Optimizer::Uses::insert(Ice::Operand *value, Ice::Inst *instruction)
772{
773 push_back(instruction);
774
775 if(isLoad(*instruction))
776 {
777 if(value == loadAddress(instruction))
778 {
779 loads.push_back(instruction);
780 }
781 }
782 else if(isStore(*instruction))
783 {
784 if(value == storeAddress(instruction))
785 {
786 stores.push_back(instruction);
787 }
788 }
789}
790
791void Optimizer::Uses::erase(Ice::Inst *instruction)
792{
793 auto &uses = *this;
794
795 for(size_t i = 0; i < uses.size(); i++)
796 {
797 if(uses[i] == instruction)
798 {
799 uses[i] = back();
800 pop_back();
801
802 for(size_t i = 0; i < loads.size(); i++)
803 {
804 if(loads[i] == instruction)
805 {
806 loads[i] = loads.back();
807 loads.pop_back();
808 break;
809 }
810 }
811
812 for(size_t i = 0; i < stores.size(); i++)
813 {
814 if(stores[i] == instruction)
815 {
816 stores[i] = stores.back();
817 stores.pop_back();
818 break;
819 }
820 }
821
822 break;
823 }
824 }
825}
826
Ben Clayton713b8d32019-12-17 20:37:56 +0000827} // anonymous namespace
Nicolas Capens157ba262019-12-10 17:49:14 -0500828
829namespace rr {
830
831void optimize(Ice::Cfg *function)
832{
833 Optimizer optimizer;
834
835 optimizer.run(function);
836}
837
838} // namespace rr