1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include "Optimizer.hpp"
17 #include "src/IceCfg.h"
18 #include "src/IceCfgNode.h"
28 void run(Ice::Cfg *function);
31 void analyzeUses(Ice::Cfg *function);
32 void eliminateDeadCode();
33 void eliminateUnitializedLoads();
34 void eliminateLoadsFollowingSingleStore();
35 void optimizeStoresInSingleBasicBlock();
37 void replace(Ice::Inst *instruction, Ice::Operand *newValue);
38 void deleteInstruction(Ice::Inst *instruction);
39 bool isDead(Ice::Inst *instruction);
41 static bool isLoad(const Ice::Inst &instruction);
42 static bool isStore(const Ice::Inst &instruction);
43 static Ice::Operand *storeAddress(const Ice::Inst *instruction);
44 static Ice::Operand *loadAddress(const Ice::Inst *instruction);
45 static Ice::Operand *storeData(const Ice::Inst *instruction);
48 Ice::GlobalContext *context;
50 struct Uses : std::vector<Ice::Inst*>
52 bool areOnlyLoadStore() const;
53 void insert(Ice::Operand *value, Ice::Inst *instruction);
54 void erase(Ice::Inst *instruction);
56 std::vector<Ice::Inst*> loads;
57 std::vector<Ice::Inst*> stores;
60 std::map<Ice::Operand*, Uses> uses;
61 std::map<Ice::Inst*, Ice::CfgNode*> node;
62 std::map<Ice::Variable*, Ice::Inst*> definition;
65 void Optimizer::run(Ice::Cfg *function)
67 this->function = function;
68 this->context = function->getContext();
70 analyzeUses(function);
73 eliminateUnitializedLoads();
74 eliminateLoadsFollowingSingleStore();
75 optimizeStoresInSingleBasicBlock();
79 void Optimizer::eliminateDeadCode()
85 for(Ice::CfgNode *basicBlock : function->getNodes())
87 for(Ice::Inst &inst : Ice::reverse_range(basicBlock->getInsts()))
96 deleteInstruction(&inst);
105 void Optimizer::eliminateUnitializedLoads()
107 Ice::CfgNode *entryBlock = function->getEntryNode();
109 for(Ice::Inst &alloca : entryBlock->getInsts())
111 if(alloca.isDeleted())
116 if(!llvm::isa<Ice::InstAlloca>(alloca))
118 return; // Allocas are all at the top
121 Ice::Operand *address = alloca.getDest();
122 const auto &addressEntry = uses.find(address);
123 const auto &addressUses = addressEntry->second;
125 if(!addressUses.areOnlyLoadStore())
130 if(addressUses.stores.empty())
132 for(Ice::Inst *load : addressUses.loads)
134 Ice::Variable *loadData = load->getDest();
136 for(Ice::Inst *use : uses[loadData])
138 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
140 if(use->getSrc(i) == loadData)
142 auto *undef = context->getConstantUndef(loadData->getType());
144 use->replaceSource(i, undef);
149 uses.erase(loadData);
155 uses.erase(addressEntry);
160 void Optimizer::eliminateLoadsFollowingSingleStore()
162 Ice::CfgNode *entryBlock = function->getEntryNode();
164 for(Ice::Inst &alloca : entryBlock->getInsts())
166 if(alloca.isDeleted())
171 if(!llvm::isa<Ice::InstAlloca>(alloca))
173 return; // Allocas are all at the top
176 Ice::Operand *address = alloca.getDest();
177 const auto &addressEntry = uses.find(address);
178 auto &addressUses = addressEntry->second;
180 if(!addressUses.areOnlyLoadStore())
185 if(addressUses.stores.size() == 1)
187 Ice::Inst *store = addressUses.stores[0];
188 Ice::Operand *storeValue = storeData(store);
190 for(Ice::Inst *load = &*++store->getIterator(), *next = nullptr; load != next; next = load, load = &*++store->getIterator())
192 if(load->isDeleted() || !isLoad(*load))
197 if(loadAddress(load) != address)
202 replace(load, storeValue);
204 for(size_t i = 0; i < addressUses.loads.size(); i++)
206 if(addressUses.loads[i] == load)
208 addressUses.loads[i] = addressUses.loads.back();
209 addressUses.loads.pop_back();
214 for(size_t i = 0; i < addressUses.size(); i++)
216 if(addressUses[i] == load)
218 addressUses[i] = addressUses.back();
219 addressUses.pop_back();
224 if(addressUses.size() == 1)
226 assert(addressUses[0] == store);
232 auto &valueUses = uses[storeValue];
234 for(size_t i = 0; i < valueUses.size(); i++)
236 if(valueUses[i] == store)
238 valueUses[i] = valueUses.back();
239 valueUses.pop_back();
244 if(valueUses.empty())
246 uses.erase(storeValue);
256 void Optimizer::optimizeStoresInSingleBasicBlock()
258 Ice::CfgNode *entryBlock = function->getEntryNode();
260 for(Ice::Inst &alloca : entryBlock->getInsts())
262 if(alloca.isDeleted())
267 if(!llvm::isa<Ice::InstAlloca>(alloca))
269 return; // Allocas are all at the top
272 Ice::Operand *address = alloca.getDest();
273 const auto &addressEntry = uses.find(address);
274 const auto &addressUses = addressEntry->second;
276 if(!addressUses.areOnlyLoadStore())
281 Ice::CfgNode *singleBasicBlock = node[addressUses.stores[0]];
283 for(size_t i = 1; i < addressUses.stores.size(); i++)
285 Ice::Inst *store = addressUses.stores[i];
286 if(node[store] != singleBasicBlock)
288 singleBasicBlock = nullptr;
295 auto &insts = singleBasicBlock->getInsts();
296 Ice::Inst *store = nullptr;
297 Ice::Operand *storeValue = nullptr;
299 for(Ice::Inst &inst : insts)
308 if(storeAddress(&inst) != address)
313 // New store found. If we had a previous one, eliminate it.
316 deleteInstruction(store);
320 storeValue = storeData(store);
322 else if(isLoad(inst))
324 Ice::Inst *load = &inst;
326 if(loadAddress(load) != address)
333 replace(load, storeValue);
341 void Optimizer::analyzeUses(Ice::Cfg *function)
347 for(Ice::CfgNode *basicBlock : function->getNodes())
349 for(Ice::Inst &instruction : basicBlock->getInsts())
351 if(instruction.isDeleted())
356 node[&instruction] = basicBlock;
357 definition[instruction.getDest()] = &instruction;
359 for(Ice::SizeT i = 0; i < instruction.getSrcSize(); i++)
361 Ice::SizeT unique = 0;
362 for(; unique < i; unique++)
364 if(instruction.getSrc(i) == instruction.getSrc(unique))
372 Ice::Operand *src = instruction.getSrc(i);
373 uses[src].insert(src, &instruction);
380 void Optimizer::replace(Ice::Inst *instruction, Ice::Operand *newValue)
382 Ice::Variable *oldValue = instruction->getDest();
386 newValue = context->getConstantUndef(oldValue->getType());
389 for(Ice::Inst *use : uses[oldValue])
391 assert(!use->isDeleted()); // Should have been removed from uses already
393 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
395 if(use->getSrc(i) == oldValue)
397 use->replaceSource(i, newValue);
401 uses[newValue].insert(newValue, use);
404 uses.erase(oldValue);
406 deleteInstruction(instruction);
409 void Optimizer::deleteInstruction(Ice::Inst *instruction)
411 if(!instruction || instruction->isDeleted())
416 instruction->setDeleted();
418 for(Ice::SizeT i = 0; i < instruction->getSrcSize(); i++)
420 Ice::Operand *src = instruction->getSrc(i);
422 const auto &srcEntry = uses.find(src);
424 if(srcEntry != uses.end())
426 auto &srcUses = srcEntry->second;
428 srcUses.erase(instruction);
432 uses.erase(srcEntry);
434 if(Ice::Variable *var = llvm::dyn_cast<Ice::Variable>(src))
436 deleteInstruction(definition[var]);
443 bool Optimizer::isDead(Ice::Inst *instruction)
445 Ice::Variable *dest = instruction->getDest();
449 return uses[dest].empty() && !instruction->hasSideEffects();
451 else if(isStore(*instruction))
453 if(Ice::Variable *address = llvm::dyn_cast<Ice::Variable>(storeAddress(instruction)))
455 Ice::Inst *def = definition[address];
457 if(!def || llvm::isa<Ice::InstAlloca>(def))
459 return uses[address].size() == 1; // Dead if this store is the only use
467 bool Optimizer::isLoad(const Ice::Inst &instruction)
469 if(llvm::isa<Ice::InstLoad>(&instruction))
474 if(auto intrinsicCall = llvm::dyn_cast<Ice::InstIntrinsicCall>(&instruction))
476 return intrinsicCall->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector;
482 bool Optimizer::isStore(const Ice::Inst &instruction)
484 if(llvm::isa<Ice::InstStore>(&instruction))
489 if(auto intrinsicCall = llvm::dyn_cast<Ice::InstIntrinsicCall>(&instruction))
491 return intrinsicCall->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector;
497 Ice::Operand *Optimizer::storeAddress(const Ice::Inst *instruction)
499 assert(isStore(*instruction));
501 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
503 return store->getAddr();
506 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
508 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector)
510 return instrinsic->getSrc(2);
517 Ice::Operand *Optimizer::loadAddress(const Ice::Inst *instruction)
519 assert(isLoad(*instruction));
521 if(auto *load = llvm::dyn_cast<Ice::InstLoad>(instruction))
523 return load->getSourceAddress();
526 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
528 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector)
530 return instrinsic->getSrc(1);
537 Ice::Operand *Optimizer::storeData(const Ice::Inst *instruction)
539 assert(isStore(*instruction));
541 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
543 return store->getData();
546 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
548 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector)
550 return instrinsic->getSrc(1);
557 bool Optimizer::Uses::areOnlyLoadStore() const
559 return size() == (loads.size() + stores.size());
562 void Optimizer::Uses::insert(Ice::Operand *value, Ice::Inst *instruction)
564 push_back(instruction);
566 if(isLoad(*instruction))
568 if(value == loadAddress(instruction))
570 loads.push_back(instruction);
573 else if(isStore(*instruction))
575 if(value == storeAddress(instruction))
577 stores.push_back(instruction);
582 void Optimizer::Uses::erase(Ice::Inst *instruction)
586 for(size_t i = 0; i < uses.size(); i++)
588 if(uses[i] == instruction)
593 for(size_t i = 0; i < loads.size(); i++)
595 if(loads[i] == instruction)
597 loads[i] = loads.back();
603 for(size_t i = 0; i < stores.size(); i++)
605 if(stores[i] == instruction)
607 stores[i] = stores.back();
621 void optimize(Ice::Cfg *function)
625 optimizer.run(function);