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