1 // 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
20 #include <vector>
21
22 namespace {
23
24 class Optimizer
25 {
26 public:
27 void run(Ice::Cfg *function);
28
29 private:
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
53 struct Uses : std::vector<Ice::Inst *>
54 {
55 bool areOnlyLoadStore() const;
56 void insert(Ice::Operand *value, Ice::Inst *instruction);
57 void erase(Ice::Inst *instruction);
58
59 std::vector<Ice::Inst *> loads;
60 std::vector<Ice::Inst *> stores;
61 };
62
63 struct LoadStoreInst
64 {
LoadStoreInst__anonf32511bb0111::Optimizer::LoadStoreInst65 LoadStoreInst(Ice::Inst *inst, bool isStore)
66 : inst(inst)
67 , address(isStore ? storeAddress(inst) : loadAddress(inst))
68 , isStore(isStore)
69 {
70 }
71
72 Ice::Inst *inst;
73 Ice::Operand *address;
74 bool isStore;
75 };
76
77 Optimizer::Uses *getUses(Ice::Operand *);
78 void setUses(Ice::Operand *, Optimizer::Uses *);
79 bool hasUses(Ice::Operand *) const;
80
81 Ice::CfgNode *getNode(Ice::Inst *);
82 void setNode(Ice::Inst *, Ice::CfgNode *);
83
84 Ice::Inst *getDefinition(Ice::Variable *);
85 void setDefinition(Ice::Variable *, Ice::Inst *);
86
87 const std::vector<LoadStoreInst> &getLoadStoreInsts(Ice::CfgNode *);
88 void setLoadStoreInsts(Ice::CfgNode *, std::vector<LoadStoreInst> *);
89 bool hasLoadStoreInsts(Ice::CfgNode *node) const;
90
91 std::vector<Ice::Operand *> operandsWithUses;
92 };
93
run(Ice::Cfg * function)94 void 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 operand : operandsWithUses)
108 {
109 // Deletes the Uses instance on the operand
110 setUses(operand, nullptr);
111 }
112 operandsWithUses.clear();
113 }
114
eliminateDeadCode()115 void Optimizer::eliminateDeadCode()
116 {
117 bool modified;
118 do
119 {
120 modified = false;
121 for(Ice::CfgNode *basicBlock : function->getNodes())
122 {
123 for(Ice::Inst &inst : Ice::reverse_range(basicBlock->getInsts()))
124 {
125 if(inst.isDeleted())
126 {
127 continue;
128 }
129
130 if(isDead(&inst))
131 {
132 deleteInstruction(&inst);
133 modified = true;
134 }
135 }
136 }
137 } while(modified);
138 }
139
eliminateUnitializedLoads()140 void Optimizer::eliminateUnitializedLoads()
141 {
142 Ice::CfgNode *entryBlock = function->getEntryNode();
143
144 for(Ice::Inst &alloca : entryBlock->getInsts())
145 {
146 if(alloca.isDeleted())
147 {
148 continue;
149 }
150
151 if(!llvm::isa<Ice::InstAlloca>(alloca))
152 {
153 break; // Allocas are all at the top
154 }
155
156 Ice::Operand *address = alloca.getDest();
157
158 if(!hasUses(address))
159 {
160 continue;
161 }
162
163 const auto &addressUses = *getUses(address);
164
165 if(!addressUses.areOnlyLoadStore())
166 {
167 continue;
168 }
169
170 if(addressUses.stores.empty())
171 {
172 for(Ice::Inst *load : addressUses.loads)
173 {
174 Ice::Variable *loadData = load->getDest();
175
176 if(hasUses(loadData))
177 {
178 for(Ice::Inst *use : *getUses(loadData))
179 {
180 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
181 {
182 if(use->getSrc(i) == loadData)
183 {
184 auto *undef = context->getConstantUndef(loadData->getType());
185
186 use->replaceSource(i, undef);
187 }
188 }
189 }
190
191 setUses(loadData, nullptr);
192 }
193
194 load->setDeleted();
195 }
196
197 alloca.setDeleted();
198 setUses(address, nullptr);
199 }
200 }
201 }
202
eliminateLoadsFollowingSingleStore()203 void Optimizer::eliminateLoadsFollowingSingleStore()
204 {
205 Ice::CfgNode *entryBlock = function->getEntryNode();
206
207 for(Ice::Inst &alloca : entryBlock->getInsts())
208 {
209 if(alloca.isDeleted())
210 {
211 continue;
212 }
213
214 if(!llvm::isa<Ice::InstAlloca>(alloca))
215 {
216 break; // Allocas are all at the top
217 }
218
219 Ice::Operand *address = alloca.getDest();
220
221 if(!hasUses(address))
222 {
223 continue;
224 }
225
226 auto &addressUses = *getUses(address);
227
228 if(!addressUses.areOnlyLoadStore())
229 {
230 continue;
231 }
232
233 if(addressUses.stores.size() == 1)
234 {
235 Ice::Inst *store = addressUses.stores[0];
236 Ice::Operand *storeValue = storeData(store);
237
238 for(Ice::Inst *load = &*++store->getIterator(), *next = nullptr; load != next; next = load, load = &*++store->getIterator())
239 {
240 if(load->isDeleted() || !isLoad(*load))
241 {
242 continue;
243 }
244
245 if(loadAddress(load) != address)
246 {
247 continue;
248 }
249
250 if(!loadTypeMatchesStore(load, store))
251 {
252 continue;
253 }
254
255 // TODO(b/148272103): InstLoad assumes that a constant ptr is an offset, rather than an
256 // absolute address. We need to make sure we don't replace a variable with a constant
257 // on this load.
258 if(llvm::isa<Ice::Constant>(storeValue))
259 {
260 continue;
261 }
262
263 replace(load, storeValue);
264
265 for(size_t i = 0; i < addressUses.loads.size(); i++)
266 {
267 if(addressUses.loads[i] == load)
268 {
269 addressUses.loads[i] = addressUses.loads.back();
270 addressUses.loads.pop_back();
271 break;
272 }
273 }
274
275 for(size_t i = 0; i < addressUses.size(); i++)
276 {
277 if(addressUses[i] == load)
278 {
279 addressUses[i] = addressUses.back();
280 addressUses.pop_back();
281 break;
282 }
283 }
284
285 if(addressUses.size() == 1)
286 {
287 assert(addressUses[0] == store);
288
289 alloca.setDeleted();
290 store->setDeleted();
291 setUses(address, nullptr);
292
293 if(hasUses(storeValue))
294 {
295 auto &valueUses = *getUses(storeValue);
296
297 for(size_t i = 0; i < valueUses.size(); i++)
298 {
299 if(valueUses[i] == store)
300 {
301 valueUses[i] = valueUses.back();
302 valueUses.pop_back();
303 break;
304 }
305 }
306
307 if(valueUses.empty())
308 {
309 setUses(storeValue, nullptr);
310 }
311 }
312
313 break;
314 }
315 }
316 }
317 }
318 }
319
optimizeStoresInSingleBasicBlock()320 void Optimizer::optimizeStoresInSingleBasicBlock()
321 {
322 Ice::CfgNode *entryBlock = function->getEntryNode();
323
324 std::vector<std::vector<LoadStoreInst> *> allocatedVectors;
325
326 for(Ice::Inst &alloca : entryBlock->getInsts())
327 {
328 if(alloca.isDeleted())
329 {
330 continue;
331 }
332
333 if(!llvm::isa<Ice::InstAlloca>(alloca))
334 {
335 break; // Allocas are all at the top
336 }
337
338 Ice::Operand *address = alloca.getDest();
339
340 if(!hasUses(address))
341 {
342 continue;
343 }
344
345 const auto &addressUses = *getUses(address);
346
347 if(!addressUses.areOnlyLoadStore())
348 {
349 continue;
350 }
351
352 Ice::CfgNode *singleBasicBlock = getNode(addressUses.stores[0]);
353
354 for(size_t i = 1; i < addressUses.stores.size(); i++)
355 {
356 Ice::Inst *store = addressUses.stores[i];
357 if(getNode(store) != singleBasicBlock)
358 {
359 singleBasicBlock = nullptr;
360 break;
361 }
362 }
363
364 if(singleBasicBlock)
365 {
366 if(!hasLoadStoreInsts(singleBasicBlock))
367 {
368 std::vector<LoadStoreInst> *loadStoreInstVector = new std::vector<LoadStoreInst>();
369 setLoadStoreInsts(singleBasicBlock, loadStoreInstVector);
370 allocatedVectors.push_back(loadStoreInstVector);
371 for(Ice::Inst &inst : singleBasicBlock->getInsts())
372 {
373 if(inst.isDeleted())
374 {
375 continue;
376 }
377
378 bool isStoreInst = isStore(inst);
379 bool isLoadInst = isLoad(inst);
380
381 if(isStoreInst || isLoadInst)
382 {
383 loadStoreInstVector->push_back(LoadStoreInst(&inst, isStoreInst));
384 }
385 }
386 }
387
388 Ice::Inst *store = nullptr;
389 Ice::Operand *storeValue = nullptr;
390 bool unmatchedLoads = false;
391
392 for(auto &loadStoreInst : getLoadStoreInsts(singleBasicBlock))
393 {
394 Ice::Inst *inst = loadStoreInst.inst;
395
396 if((loadStoreInst.address != address) || inst->isDeleted())
397 {
398 continue;
399 }
400
401 if(loadStoreInst.isStore)
402 {
403 // New store found. If we had a previous one, try to eliminate it.
404 if(store && !unmatchedLoads)
405 {
406 // If the previous store is wider than the new one, we can't eliminate it
407 // because there could be a wide load reading its non-overwritten data.
408 if(storeSize(inst) >= storeSize(store))
409 {
410 deleteInstruction(store);
411 }
412 }
413
414 store = inst;
415 storeValue = storeData(store);
416 unmatchedLoads = false;
417 }
418 else
419 {
420 if(!loadTypeMatchesStore(inst, store))
421 {
422 unmatchedLoads = true;
423 continue;
424 }
425
426 // TODO(b/148272103): InstLoad assumes that a constant ptr is an offset, rather than an
427 // absolute address. We need to make sure we don't replace a variable with a constant
428 // on this load.
429 if(llvm::isa<Ice::Constant>(storeValue))
430 {
431 unmatchedLoads = true;
432 continue;
433 }
434
435 replace(inst, storeValue);
436 }
437 }
438 }
439 }
440
441 for(auto loadStoreInstVector : allocatedVectors)
442 {
443 delete loadStoreInstVector;
444 }
445 }
446
analyzeUses(Ice::Cfg * function)447 void Optimizer::analyzeUses(Ice::Cfg *function)
448 {
449 for(Ice::CfgNode *basicBlock : function->getNodes())
450 {
451 for(Ice::Inst &instruction : basicBlock->getInsts())
452 {
453 if(instruction.isDeleted())
454 {
455 continue;
456 }
457
458 setNode(&instruction, basicBlock);
459 if(instruction.getDest())
460 {
461 setDefinition(instruction.getDest(), &instruction);
462 }
463
464 for(Ice::SizeT i = 0; i < instruction.getSrcSize(); i++)
465 {
466 Ice::SizeT unique = 0;
467 for(; unique < i; unique++)
468 {
469 if(instruction.getSrc(i) == instruction.getSrc(unique))
470 {
471 break;
472 }
473 }
474
475 if(i == unique)
476 {
477 Ice::Operand *src = instruction.getSrc(i);
478 getUses(src)->insert(src, &instruction);
479 }
480 }
481 }
482 }
483 }
484
replace(Ice::Inst * instruction,Ice::Operand * newValue)485 void Optimizer::replace(Ice::Inst *instruction, Ice::Operand *newValue)
486 {
487 Ice::Variable *oldValue = instruction->getDest();
488
489 if(!newValue)
490 {
491 newValue = context->getConstantUndef(oldValue->getType());
492 }
493
494 if(hasUses(oldValue))
495 {
496 for(Ice::Inst *use : *getUses(oldValue))
497 {
498 assert(!use->isDeleted()); // Should have been removed from uses already
499
500 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
501 {
502 if(use->getSrc(i) == oldValue)
503 {
504 use->replaceSource(i, newValue);
505 }
506 }
507
508 getUses(newValue)->insert(newValue, use);
509 }
510
511 setUses(oldValue, nullptr);
512 }
513
514 deleteInstruction(instruction);
515 }
516
deleteInstruction(Ice::Inst * instruction)517 void Optimizer::deleteInstruction(Ice::Inst *instruction)
518 {
519 if(!instruction || instruction->isDeleted())
520 {
521 return;
522 }
523
524 instruction->setDeleted();
525
526 for(Ice::SizeT i = 0; i < instruction->getSrcSize(); i++)
527 {
528 Ice::Operand *src = instruction->getSrc(i);
529
530 if(hasUses(src))
531 {
532 auto &srcUses = *getUses(src);
533
534 srcUses.erase(instruction);
535
536 if(srcUses.empty())
537 {
538 setUses(src, nullptr);
539
540 if(Ice::Variable *var = llvm::dyn_cast<Ice::Variable>(src))
541 {
542 deleteInstruction(getDefinition(var));
543 }
544 }
545 }
546 }
547 }
548
isDead(Ice::Inst * instruction)549 bool Optimizer::isDead(Ice::Inst *instruction)
550 {
551 Ice::Variable *dest = instruction->getDest();
552
553 if(dest)
554 {
555 return (!hasUses(dest) || getUses(dest)->empty()) && !instruction->hasSideEffects();
556 }
557 else if(isStore(*instruction))
558 {
559 if(Ice::Variable *address = llvm::dyn_cast<Ice::Variable>(storeAddress(instruction)))
560 {
561 Ice::Inst *def = getDefinition(address);
562
563 if(def && llvm::isa<Ice::InstAlloca>(def))
564 {
565 if(hasUses(address))
566 {
567 Optimizer::Uses *uses = getUses(address);
568 return uses->size() == uses->stores.size(); // Dead if all uses are stores
569 }
570 else
571 {
572 return true; // No uses
573 }
574 }
575 }
576 }
577
578 return false;
579 }
580
asLoadSubVector(const Ice::Inst * instruction)581 const Ice::InstIntrinsicCall *Optimizer::asLoadSubVector(const Ice::Inst *instruction)
582 {
583 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
584 {
585 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector)
586 {
587 return instrinsic;
588 }
589 }
590
591 return nullptr;
592 }
593
asStoreSubVector(const Ice::Inst * instruction)594 const Ice::InstIntrinsicCall *Optimizer::asStoreSubVector(const Ice::Inst *instruction)
595 {
596 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
597 {
598 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector)
599 {
600 return instrinsic;
601 }
602 }
603
604 return nullptr;
605 }
606
isLoad(const Ice::Inst & instruction)607 bool Optimizer::isLoad(const Ice::Inst &instruction)
608 {
609 if(llvm::isa<Ice::InstLoad>(&instruction))
610 {
611 return true;
612 }
613
614 return asLoadSubVector(&instruction) != nullptr;
615 }
616
isStore(const Ice::Inst & instruction)617 bool Optimizer::isStore(const Ice::Inst &instruction)
618 {
619 if(llvm::isa<Ice::InstStore>(&instruction))
620 {
621 return true;
622 }
623
624 return asStoreSubVector(&instruction) != nullptr;
625 }
626
storeAddress(const Ice::Inst * instruction)627 Ice::Operand *Optimizer::storeAddress(const Ice::Inst *instruction)
628 {
629 assert(isStore(*instruction));
630
631 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
632 {
633 return store->getAddr();
634 }
635
636 if(auto *storeSubVector = asStoreSubVector(instruction))
637 {
638 return storeSubVector->getSrc(2);
639 }
640
641 return nullptr;
642 }
643
loadAddress(const Ice::Inst * instruction)644 Ice::Operand *Optimizer::loadAddress(const Ice::Inst *instruction)
645 {
646 assert(isLoad(*instruction));
647
648 if(auto *load = llvm::dyn_cast<Ice::InstLoad>(instruction))
649 {
650 return load->getSourceAddress();
651 }
652
653 if(auto *loadSubVector = asLoadSubVector(instruction))
654 {
655 return loadSubVector->getSrc(1);
656 }
657
658 return nullptr;
659 }
660
storeData(const Ice::Inst * instruction)661 Ice::Operand *Optimizer::storeData(const Ice::Inst *instruction)
662 {
663 assert(isStore(*instruction));
664
665 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
666 {
667 return store->getData();
668 }
669
670 if(auto *storeSubVector = asStoreSubVector(instruction))
671 {
672 return storeSubVector->getSrc(1);
673 }
674
675 return nullptr;
676 }
677
storeSize(const Ice::Inst * store)678 std::size_t Optimizer::storeSize(const Ice::Inst *store)
679 {
680 assert(isStore(*store));
681
682 if(auto *instStore = llvm::dyn_cast<Ice::InstStore>(store))
683 {
684 return Ice::typeWidthInBytes(instStore->getData()->getType());
685 }
686
687 if(auto *storeSubVector = asStoreSubVector(store))
688 {
689 return llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(3))->getValue();
690 }
691
692 return 0;
693 }
694
loadTypeMatchesStore(const Ice::Inst * load,const Ice::Inst * store)695 bool Optimizer::loadTypeMatchesStore(const Ice::Inst *load, const Ice::Inst *store)
696 {
697 if(!load || !store)
698 {
699 return false;
700 }
701
702 assert(isLoad(*load) && isStore(*store));
703 assert(loadAddress(load) == storeAddress(store));
704
705 if(auto *instStore = llvm::dyn_cast<Ice::InstStore>(store))
706 {
707 if(auto *instLoad = llvm::dyn_cast<Ice::InstLoad>(load))
708 {
709 return instStore->getData()->getType() == instLoad->getDest()->getType();
710 }
711 }
712
713 if(auto *storeSubVector = asStoreSubVector(store))
714 {
715 if(auto *loadSubVector = asLoadSubVector(load))
716 {
717 // Check for matching type and sub-vector width.
718 return storeSubVector->getSrc(1)->getType() == loadSubVector->getDest()->getType() &&
719 llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(3))->getValue() ==
720 llvm::cast<Ice::ConstantInteger32>(loadSubVector->getSrc(2))->getValue();
721 }
722 }
723
724 return false;
725 }
726
getUses(Ice::Operand * operand)727 Optimizer::Uses *Optimizer::getUses(Ice::Operand *operand)
728 {
729 Optimizer::Uses *uses = (Optimizer::Uses *)operand->Ice::Operand::getExternalData();
730 if(!uses)
731 {
732 uses = new Optimizer::Uses;
733 setUses(operand, uses);
734 operandsWithUses.push_back(operand);
735 }
736 return uses;
737 }
738
setUses(Ice::Operand * operand,Optimizer::Uses * uses)739 void Optimizer::setUses(Ice::Operand *operand, Optimizer::Uses *uses)
740 {
741 if(auto *oldUses = reinterpret_cast<Optimizer::Uses *>(operand->Ice::Operand::getExternalData()))
742 {
743 delete oldUses;
744 }
745
746 operand->Ice::Operand::setExternalData(uses);
747 }
748
hasUses(Ice::Operand * operand) const749 bool Optimizer::hasUses(Ice::Operand *operand) const
750 {
751 return operand->Ice::Operand::getExternalData() != nullptr;
752 }
753
getNode(Ice::Inst * inst)754 Ice::CfgNode *Optimizer::getNode(Ice::Inst *inst)
755 {
756 return (Ice::CfgNode *)inst->Ice::Inst::getExternalData();
757 }
758
setNode(Ice::Inst * inst,Ice::CfgNode * node)759 void Optimizer::setNode(Ice::Inst *inst, Ice::CfgNode *node)
760 {
761 inst->Ice::Inst::setExternalData(node);
762 }
763
getDefinition(Ice::Variable * var)764 Ice::Inst *Optimizer::getDefinition(Ice::Variable *var)
765 {
766 return (Ice::Inst *)var->Ice::Variable::getExternalData();
767 }
768
setDefinition(Ice::Variable * var,Ice::Inst * inst)769 void Optimizer::setDefinition(Ice::Variable *var, Ice::Inst *inst)
770 {
771 var->Ice::Variable::setExternalData(inst);
772 }
773
getLoadStoreInsts(Ice::CfgNode * node)774 const std::vector<Optimizer::LoadStoreInst> &Optimizer::getLoadStoreInsts(Ice::CfgNode *node)
775 {
776 return *((const std::vector<LoadStoreInst> *)node->Ice::CfgNode::getExternalData());
777 }
778
setLoadStoreInsts(Ice::CfgNode * node,std::vector<LoadStoreInst> * insts)779 void Optimizer::setLoadStoreInsts(Ice::CfgNode *node, std::vector<LoadStoreInst> *insts)
780 {
781 node->Ice::CfgNode::setExternalData(insts);
782 }
783
hasLoadStoreInsts(Ice::CfgNode * node) const784 bool Optimizer::hasLoadStoreInsts(Ice::CfgNode *node) const
785 {
786 return node->Ice::CfgNode::getExternalData() != nullptr;
787 }
788
areOnlyLoadStore() const789 bool Optimizer::Uses::areOnlyLoadStore() const
790 {
791 return size() == (loads.size() + stores.size());
792 }
793
insert(Ice::Operand * value,Ice::Inst * instruction)794 void Optimizer::Uses::insert(Ice::Operand *value, Ice::Inst *instruction)
795 {
796 push_back(instruction);
797
798 if(isLoad(*instruction))
799 {
800 if(value == loadAddress(instruction))
801 {
802 loads.push_back(instruction);
803 }
804 }
805 else if(isStore(*instruction))
806 {
807 if(value == storeAddress(instruction))
808 {
809 stores.push_back(instruction);
810 }
811 }
812 }
813
erase(Ice::Inst * instruction)814 void Optimizer::Uses::erase(Ice::Inst *instruction)
815 {
816 auto &uses = *this;
817
818 for(size_t i = 0; i < uses.size(); i++)
819 {
820 if(uses[i] == instruction)
821 {
822 uses[i] = back();
823 pop_back();
824
825 for(size_t i = 0; i < loads.size(); i++)
826 {
827 if(loads[i] == instruction)
828 {
829 loads[i] = loads.back();
830 loads.pop_back();
831 break;
832 }
833 }
834
835 for(size_t i = 0; i < stores.size(); i++)
836 {
837 if(stores[i] == instruction)
838 {
839 stores[i] = stores.back();
840 stores.pop_back();
841 break;
842 }
843 }
844
845 break;
846 }
847 }
848 }
849
850 } // anonymous namespace
851
852 namespace rr {
853
optimize(Ice::Cfg * function)854 void optimize(Ice::Cfg *function)
855 {
856 Optimizer optimizer;
857
858 optimizer.run(function);
859 }
860
861 } // namespace rr
862