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 eliminateUnusedAllocas();
33 void eliminateUnitializedLoads();
35 static bool isLoad(const Ice::Inst &instruction);
36 static bool isStore(const Ice::Inst &instruction);
37 static Ice::Operand *storeAddress(const Ice::Inst *instruction);
38 static Ice::Operand *loadAddress(const Ice::Inst *instruction);
41 Ice::GlobalContext *context;
43 struct Uses : std::vector<Ice::Inst*>
45 bool areOnlyLoadStore() const;
46 void insert(Ice::Operand *value, Ice::Inst *instruction);
47 void erase(Ice::Inst *instruction);
49 std::vector<Ice::Inst*> loads;
50 std::vector<Ice::Inst*> stores;
53 std::map<Ice::Operand*, Uses> uses;
56 void Optimizer::run(Ice::Cfg *function)
58 this->function = function;
59 this->context = function->getContext();
61 analyzeUses(function);
63 eliminateUnusedAllocas();
64 eliminateUnitializedLoads();
67 void Optimizer::eliminateUnusedAllocas()
69 Ice::CfgNode *entryBlock = function->getEntryNode();
71 for(Ice::Inst &alloca : entryBlock->getInsts())
73 if(!llvm::isa<Ice::InstAlloca>(alloca))
75 return; // Allocas are all at the top
78 Ice::Operand *address = alloca.getDest();
80 if(uses[address].empty())
87 void Optimizer::eliminateUnitializedLoads()
89 Ice::CfgNode *entryBlock = function->getEntryNode();
91 for(Ice::Inst &alloca : entryBlock->getInsts())
93 if(alloca.isDeleted())
98 if(!llvm::isa<Ice::InstAlloca>(alloca))
100 return; // Allocas are all at the top
103 Ice::Operand *address = alloca.getDest();
104 const auto &addressEntry = uses.find(address);
105 const auto &addressUses = addressEntry->second;
107 if(!addressUses.areOnlyLoadStore())
112 if(addressUses.stores.empty())
114 for(Ice::Inst *load : addressUses.loads)
116 Ice::Variable *loadData = load->getDest();
118 for(Ice::Inst *use : uses[loadData])
120 for(int i = 0; i < use->getSrcSize(); i++)
122 if(use->getSrc(i) == loadData)
124 auto *undef = context->getConstantUndef(loadData->getType());
126 use->replaceSource(i, undef);
131 uses.erase(loadData);
137 uses.erase(addressEntry);
142 void Optimizer::analyzeUses(Ice::Cfg *function)
146 for(Ice::CfgNode *basicBlock : function->getNodes())
148 for(Ice::Inst &instruction : basicBlock->getInsts())
150 if(instruction.isDeleted())
155 for(int i = 0; i < instruction.getSrcSize(); i++)
158 for(; unique < i; unique++)
160 if(instruction.getSrc(i) == instruction.getSrc(unique))
168 Ice::Operand *src = instruction.getSrc(i);
169 uses[src].insert(src, &instruction);
176 bool Optimizer::isLoad(const Ice::Inst &instruction)
178 if(llvm::isa<Ice::InstLoad>(&instruction))
183 if(auto intrinsicCall = llvm::dyn_cast<Ice::InstIntrinsicCall>(&instruction))
185 return intrinsicCall->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector;
191 bool Optimizer::isStore(const Ice::Inst &instruction)
193 if(llvm::isa<Ice::InstStore>(&instruction))
198 if(auto intrinsicCall = llvm::dyn_cast<Ice::InstIntrinsicCall>(&instruction))
200 return intrinsicCall->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector;
206 Ice::Operand *Optimizer::storeAddress(const Ice::Inst *instruction)
208 assert(isStore(*instruction));
210 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
212 return store->getAddr();
215 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
217 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector)
219 return instrinsic->getSrc(2);
226 Ice::Operand *Optimizer::loadAddress(const Ice::Inst *instruction)
228 assert(isLoad(*instruction));
230 if(auto *load = llvm::dyn_cast<Ice::InstLoad>(instruction))
232 return load->getSourceAddress();
235 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
237 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector)
239 return instrinsic->getSrc(1);
246 bool Optimizer::Uses::areOnlyLoadStore() const
248 return size() == (loads.size() + stores.size());
251 void Optimizer::Uses::insert(Ice::Operand *value, Ice::Inst *instruction)
253 push_back(instruction);
255 if(isLoad(*instruction))
257 if(value == loadAddress(instruction))
259 loads.push_back(instruction);
262 else if(isStore(*instruction))
264 if(value == storeAddress(instruction))
266 stores.push_back(instruction);
271 void Optimizer::Uses::erase(Ice::Inst *instruction)
275 for(int i = 0; i < uses.size(); i++)
277 if(uses[i] == instruction)
282 for(int i = 0; i < loads.size(); i++)
284 if(loads[i] == instruction)
286 loads[i] = loads.back();
292 for(int i = 0; i < stores.size(); i++)
294 if(stores[i] == instruction)
296 stores[i] = stores.back();
310 void optimize(Ice::Cfg *function)
314 optimizer.run(function);