blob: 5d89878ef86d29e8c706cf5467cad8e8b53e83f6 [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
22namespace
23{
24 class Optimizer
25 {
26 public:
27 void run(Ice::Cfg *function);
28
29 private:
30 void analyzeUses(Ice::Cfg *function);
Nicolas Capensc9d70d52016-12-12 15:07:39 -050031 void eliminateDeadCode();
Nicolas Capensf4452fc2016-12-12 13:08:06 -050032 void eliminateUnitializedLoads();
Nicolas Capense205c3d2016-11-30 15:14:28 -050033 void eliminateLoadsFollowingSingleStore();
Nicolas Capens16252ab2016-11-30 16:15:28 -050034 void optimizeStoresInSingleBasicBlock();
Nicolas Capense205c3d2016-11-30 15:14:28 -050035
36 void replace(Ice::Inst *instruction, Ice::Operand *newValue);
37 void deleteInstruction(Ice::Inst *instruction);
Nicolas Capensc9d70d52016-12-12 15:07:39 -050038 bool isDead(Ice::Inst *instruction);
Nicolas Capensf4452fc2016-12-12 13:08:06 -050039
Nicolas Capens709f69b2017-07-26 11:30:33 -040040 static const Ice::InstIntrinsicCall *asLoadSubVector(const Ice::Inst *instruction);
41 static const Ice::InstIntrinsicCall *asStoreSubVector(const Ice::Inst *instruction);
Nicolas Capensf4452fc2016-12-12 13:08:06 -050042 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);
Nicolas Capense205c3d2016-11-30 15:14:28 -050046 static Ice::Operand *storeData(const Ice::Inst *instruction);
Nicolas Capensf2f5e962017-07-25 12:57:12 -040047 static std::size_t storeSize(const Ice::Inst *instruction);
Nicolas Capens87722022017-07-25 13:24:40 -040048 static bool loadTypeMatchesStore(const Ice::Inst *load, const Ice::Inst *store);
Nicolas Capens2ae9d742016-11-24 14:43:05 -050049
50 Ice::Cfg *function;
Nicolas Capensf4452fc2016-12-12 13:08:06 -050051 Ice::GlobalContext *context;
Nicolas Capens2ae9d742016-11-24 14:43:05 -050052
Nicolas Capensf4452fc2016-12-12 13:08:06 -050053 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
Alexis Hetu932640b2018-06-20 15:35:53 -040063 struct LoadStoreInst
64 {
65 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<Optimizer::Uses*> allocatedUses;
Nicolas Capens2ae9d742016-11-24 14:43:05 -050092 };
93
94 void Optimizer::run(Ice::Cfg *function)
95 {
96 this->function = function;
Nicolas Capensf4452fc2016-12-12 13:08:06 -050097 this->context = function->getContext();
Nicolas Capens2ae9d742016-11-24 14:43:05 -050098
99 analyzeUses(function);
100
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500101 eliminateDeadCode();
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500102 eliminateUnitializedLoads();
Nicolas Capense205c3d2016-11-30 15:14:28 -0500103 eliminateLoadsFollowingSingleStore();
Nicolas Capens16252ab2016-11-30 16:15:28 -0500104 optimizeStoresInSingleBasicBlock();
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500105 eliminateDeadCode();
Alexis Hetu932640b2018-06-20 15:35:53 -0400106
107 for(auto uses : allocatedUses)
108 {
109 delete uses;
110 }
111 allocatedUses.clear();
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500112 }
113
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500114 void Optimizer::eliminateDeadCode()
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500115 {
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500116 bool modified;
117 do
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500118 {
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500119 modified = false;
120 for(Ice::CfgNode *basicBlock : function->getNodes())
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500121 {
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500122 for(Ice::Inst &inst : Ice::reverse_range(basicBlock->getInsts()))
123 {
124 if(inst.isDeleted())
125 {
126 continue;
127 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500128
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500129 if(isDead(&inst))
130 {
131 deleteInstruction(&inst);
132 modified = true;
133 }
134 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500135 }
136 }
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500137 while(modified);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500138 }
139
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500140 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 {
Alexis Hetu41b77482018-06-22 16:02:55 -0400153 break; // Allocas are all at the top
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500154 }
155
156 Ice::Operand *address = alloca.getDest();
Alexis Hetu932640b2018-06-20 15:35:53 -0400157
158 if(!hasUses(address))
159 {
Alexis Hetu41b77482018-06-22 16:02:55 -0400160 continue;
Alexis Hetu932640b2018-06-20 15:35:53 -0400161 }
162
163 const auto &addressUses = *getUses(address);
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500164
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
Alexis Hetu932640b2018-06-20 15:35:53 -0400176 if(hasUses(loadData))
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500177 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400178 for(Ice::Inst *use : *getUses(loadData))
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500179 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400180 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500181 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400182 if(use->getSrc(i) == loadData)
183 {
184 auto *undef = context->getConstantUndef(loadData->getType());
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500185
Alexis Hetu932640b2018-06-20 15:35:53 -0400186 use->replaceSource(i, undef);
187 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500188 }
189 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500190
Alexis Hetu932640b2018-06-20 15:35:53 -0400191 setUses(loadData, nullptr);
192 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500193
194 load->setDeleted();
195 }
196
197 alloca.setDeleted();
Alexis Hetu932640b2018-06-20 15:35:53 -0400198 setUses(address, nullptr);
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500199 }
200 }
201 }
202
Nicolas Capense205c3d2016-11-30 15:14:28 -0500203 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 {
Alexis Hetu41b77482018-06-22 16:02:55 -0400216 break; // Allocas are all at the top
Nicolas Capense205c3d2016-11-30 15:14:28 -0500217 }
218
219 Ice::Operand *address = alloca.getDest();
Alexis Hetu932640b2018-06-20 15:35:53 -0400220
221 if(!hasUses(address))
222 {
Alexis Hetu41b77482018-06-22 16:02:55 -0400223 continue;
Alexis Hetu932640b2018-06-20 15:35:53 -0400224 }
225
226 auto &addressUses = *getUses(address);
Nicolas Capense205c3d2016-11-30 15:14:28 -0500227
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
Nicolas Capens87722022017-07-25 13:24:40 -0400250 if(!loadTypeMatchesStore(load, store))
251 {
252 continue;
253 }
254
Nicolas Capense205c3d2016-11-30 15:14:28 -0500255 replace(load, storeValue);
256
Alexis Hetu113e33a2017-01-19 10:49:19 -0500257 for(size_t i = 0; i < addressUses.loads.size(); i++)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500258 {
259 if(addressUses.loads[i] == load)
260 {
261 addressUses.loads[i] = addressUses.loads.back();
262 addressUses.loads.pop_back();
263 break;
264 }
265 }
266
Alexis Hetu113e33a2017-01-19 10:49:19 -0500267 for(size_t i = 0; i < addressUses.size(); i++)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500268 {
269 if(addressUses[i] == load)
270 {
271 addressUses[i] = addressUses.back();
272 addressUses.pop_back();
273 break;
274 }
275 }
276
277 if(addressUses.size() == 1)
278 {
279 assert(addressUses[0] == store);
280
281 alloca.setDeleted();
282 store->setDeleted();
Alexis Hetu932640b2018-06-20 15:35:53 -0400283 setUses(address, nullptr);
Nicolas Capense205c3d2016-11-30 15:14:28 -0500284
Alexis Hetu932640b2018-06-20 15:35:53 -0400285 if(hasUses(storeValue))
Nicolas Capense205c3d2016-11-30 15:14:28 -0500286 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400287 auto &valueUses = *getUses(storeValue);
288
289 for(size_t i = 0; i < valueUses.size(); i++)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500290 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400291 if(valueUses[i] == store)
292 {
293 valueUses[i] = valueUses.back();
294 valueUses.pop_back();
295 break;
296 }
Nicolas Capense205c3d2016-11-30 15:14:28 -0500297 }
Nicolas Capense205c3d2016-11-30 15:14:28 -0500298
Alexis Hetu932640b2018-06-20 15:35:53 -0400299 if(valueUses.empty())
300 {
301 setUses(storeValue, nullptr);
302 }
Nicolas Capense205c3d2016-11-30 15:14:28 -0500303 }
304
305 break;
306 }
307 }
308 }
309 }
310 }
311
Nicolas Capens16252ab2016-11-30 16:15:28 -0500312 void Optimizer::optimizeStoresInSingleBasicBlock()
313 {
314 Ice::CfgNode *entryBlock = function->getEntryNode();
315
Alexis Hetu932640b2018-06-20 15:35:53 -0400316 std::vector<std::vector<LoadStoreInst>* > allocatedVectors;
Alexis Hetua5ac6502018-06-13 16:21:34 -0400317
Nicolas Capens16252ab2016-11-30 16:15:28 -0500318 for(Ice::Inst &alloca : entryBlock->getInsts())
319 {
320 if(alloca.isDeleted())
321 {
322 continue;
323 }
324
325 if(!llvm::isa<Ice::InstAlloca>(alloca))
326 {
Alexis Hetu41b77482018-06-22 16:02:55 -0400327 break; // Allocas are all at the top
Nicolas Capens16252ab2016-11-30 16:15:28 -0500328 }
329
330 Ice::Operand *address = alloca.getDest();
Alexis Hetu932640b2018-06-20 15:35:53 -0400331
332 if(!hasUses(address))
333 {
Alexis Hetu41b77482018-06-22 16:02:55 -0400334 continue;
Alexis Hetu932640b2018-06-20 15:35:53 -0400335 }
336
337 const auto &addressUses = *getUses(address);
Nicolas Capens16252ab2016-11-30 16:15:28 -0500338
339 if(!addressUses.areOnlyLoadStore())
340 {
341 continue;
342 }
343
Alexis Hetu932640b2018-06-20 15:35:53 -0400344 Ice::CfgNode *singleBasicBlock = getNode(addressUses.stores[0]);
Nicolas Capens16252ab2016-11-30 16:15:28 -0500345
Alexis Hetu113e33a2017-01-19 10:49:19 -0500346 for(size_t i = 1; i < addressUses.stores.size(); i++)
Nicolas Capens16252ab2016-11-30 16:15:28 -0500347 {
348 Ice::Inst *store = addressUses.stores[i];
Alexis Hetu932640b2018-06-20 15:35:53 -0400349 if(getNode(store) != singleBasicBlock)
Nicolas Capens16252ab2016-11-30 16:15:28 -0500350 {
351 singleBasicBlock = nullptr;
352 break;
353 }
354 }
355
356 if(singleBasicBlock)
357 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400358 if(!hasLoadStoreInsts(singleBasicBlock))
Nicolas Capens16252ab2016-11-30 16:15:28 -0500359 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400360 std::vector<LoadStoreInst>* loadStoreInstVector = new std::vector<LoadStoreInst>();
361 setLoadStoreInsts(singleBasicBlock, loadStoreInstVector);
362 allocatedVectors.push_back(loadStoreInstVector);
Alexis Hetua5ac6502018-06-13 16:21:34 -0400363 for(Ice::Inst &inst : singleBasicBlock->getInsts())
Nicolas Capens16252ab2016-11-30 16:15:28 -0500364 {
Alexis Hetua5ac6502018-06-13 16:21:34 -0400365 if(inst.isDeleted())
Nicolas Capens16252ab2016-11-30 16:15:28 -0500366 {
367 continue;
368 }
369
Alexis Hetua5ac6502018-06-13 16:21:34 -0400370 bool isStoreInst = isStore(inst);
371 bool isLoadInst = isLoad(inst);
372
373 if(isStoreInst || isLoadInst)
374 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400375 loadStoreInstVector->push_back(LoadStoreInst(&inst, isStoreInst));
Alexis Hetua5ac6502018-06-13 16:21:34 -0400376 }
377 }
378 }
379
380 Ice::Inst *store = nullptr;
381 Ice::Operand *storeValue = nullptr;
382 bool unmatchedLoads = false;
383
Alexis Hetu932640b2018-06-20 15:35:53 -0400384 for (auto& loadStoreInst : getLoadStoreInsts(singleBasicBlock))
Alexis Hetua5ac6502018-06-13 16:21:34 -0400385 {
386 Ice::Inst* inst = loadStoreInst.inst;
387
388 if((loadStoreInst.address != address) || inst->isDeleted())
389 {
390 continue;
391 }
392
393 if(loadStoreInst.isStore)
394 {
Nicolas Capensf2f5e962017-07-25 12:57:12 -0400395 // New store found. If we had a previous one, try to eliminate it.
Nicolas Capens87722022017-07-25 13:24:40 -0400396 if(store && !unmatchedLoads)
Nicolas Capens16252ab2016-11-30 16:15:28 -0500397 {
Nicolas Capensf2f5e962017-07-25 12:57:12 -0400398 // If the previous store is wider than the new one, we can't eliminate it
399 // because there could be a wide load reading its non-overwritten data.
Alexis Hetua5ac6502018-06-13 16:21:34 -0400400 if(storeSize(inst) >= storeSize(store))
Nicolas Capensf2f5e962017-07-25 12:57:12 -0400401 {
402 deleteInstruction(store);
403 }
Nicolas Capens16252ab2016-11-30 16:15:28 -0500404 }
405
Alexis Hetua5ac6502018-06-13 16:21:34 -0400406 store = inst;
Nicolas Capens16252ab2016-11-30 16:15:28 -0500407 storeValue = storeData(store);
Nicolas Capens87722022017-07-25 13:24:40 -0400408 unmatchedLoads = false;
Nicolas Capens16252ab2016-11-30 16:15:28 -0500409 }
Alexis Hetua5ac6502018-06-13 16:21:34 -0400410 else
Nicolas Capens16252ab2016-11-30 16:15:28 -0500411 {
Alexis Hetua5ac6502018-06-13 16:21:34 -0400412 if(!loadTypeMatchesStore(inst, store))
Nicolas Capens22e18bc2017-01-18 10:18:03 -0500413 {
Nicolas Capens87722022017-07-25 13:24:40 -0400414 unmatchedLoads = true;
415 continue;
Nicolas Capens22e18bc2017-01-18 10:18:03 -0500416 }
Nicolas Capens87722022017-07-25 13:24:40 -0400417
Alexis Hetua5ac6502018-06-13 16:21:34 -0400418 replace(inst, storeValue);
Nicolas Capens16252ab2016-11-30 16:15:28 -0500419 }
420 }
421 }
422 }
Alexis Hetu932640b2018-06-20 15:35:53 -0400423
424 for(auto loadStoreInstVector : allocatedVectors)
425 {
426 delete loadStoreInstVector;
427 }
Nicolas Capens16252ab2016-11-30 16:15:28 -0500428 }
429
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500430 void Optimizer::analyzeUses(Ice::Cfg *function)
431 {
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500432 for(Ice::CfgNode *basicBlock : function->getNodes())
433 {
434 for(Ice::Inst &instruction : basicBlock->getInsts())
435 {
436 if(instruction.isDeleted())
437 {
438 continue;
439 }
440
Alexis Hetu932640b2018-06-20 15:35:53 -0400441 setNode(&instruction, basicBlock);
442 if(instruction.getDest())
443 {
444 setDefinition(instruction.getDest(), &instruction);
445 }
Nicolas Capense205c3d2016-11-30 15:14:28 -0500446
Alexis Hetu113e33a2017-01-19 10:49:19 -0500447 for(Ice::SizeT i = 0; i < instruction.getSrcSize(); i++)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500448 {
Alexis Hetu113e33a2017-01-19 10:49:19 -0500449 Ice::SizeT unique = 0;
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500450 for(; unique < i; unique++)
451 {
452 if(instruction.getSrc(i) == instruction.getSrc(unique))
453 {
454 break;
455 }
456 }
457
458 if(i == unique)
459 {
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500460 Ice::Operand *src = instruction.getSrc(i);
Alexis Hetu932640b2018-06-20 15:35:53 -0400461 getUses(src)->insert(src, &instruction);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500462 }
463 }
464 }
465 }
466 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500467
Nicolas Capense205c3d2016-11-30 15:14:28 -0500468 void Optimizer::replace(Ice::Inst *instruction, Ice::Operand *newValue)
469 {
470 Ice::Variable *oldValue = instruction->getDest();
471
472 if(!newValue)
473 {
474 newValue = context->getConstantUndef(oldValue->getType());
475 }
476
Alexis Hetu932640b2018-06-20 15:35:53 -0400477 if(hasUses(oldValue))
Nicolas Capense205c3d2016-11-30 15:14:28 -0500478 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400479 for(Ice::Inst *use : *getUses(oldValue))
Nicolas Capense205c3d2016-11-30 15:14:28 -0500480 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400481 assert(!use->isDeleted()); // Should have been removed from uses already
482
483 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500484 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400485 if(use->getSrc(i) == oldValue)
486 {
487 use->replaceSource(i, newValue);
488 }
Nicolas Capense205c3d2016-11-30 15:14:28 -0500489 }
Alexis Hetu932640b2018-06-20 15:35:53 -0400490
491 getUses(newValue)->insert(newValue, use);
Nicolas Capense205c3d2016-11-30 15:14:28 -0500492 }
493
Alexis Hetu932640b2018-06-20 15:35:53 -0400494 setUses(oldValue, nullptr);
Nicolas Capense205c3d2016-11-30 15:14:28 -0500495 }
496
Nicolas Capense205c3d2016-11-30 15:14:28 -0500497 deleteInstruction(instruction);
498 }
499
500 void Optimizer::deleteInstruction(Ice::Inst *instruction)
501 {
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500502 if(!instruction || instruction->isDeleted())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500503 {
504 return;
505 }
506
507 instruction->setDeleted();
508
Alexis Hetu113e33a2017-01-19 10:49:19 -0500509 for(Ice::SizeT i = 0; i < instruction->getSrcSize(); i++)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500510 {
511 Ice::Operand *src = instruction->getSrc(i);
512
Alexis Hetu932640b2018-06-20 15:35:53 -0400513 if(hasUses(src))
Nicolas Capense205c3d2016-11-30 15:14:28 -0500514 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400515 auto &srcUses = *getUses(src);
Nicolas Capense205c3d2016-11-30 15:14:28 -0500516
517 srcUses.erase(instruction);
518
519 if(srcUses.empty())
520 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400521 setUses(src, nullptr);
Nicolas Capense205c3d2016-11-30 15:14:28 -0500522
523 if(Ice::Variable *var = llvm::dyn_cast<Ice::Variable>(src))
524 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400525 deleteInstruction(getDefinition(var));
Nicolas Capense205c3d2016-11-30 15:14:28 -0500526 }
527 }
528 }
529 }
530 }
531
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500532 bool Optimizer::isDead(Ice::Inst *instruction)
533 {
534 Ice::Variable *dest = instruction->getDest();
535
536 if(dest)
537 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400538 return (!hasUses(dest) || getUses(dest)->empty()) && !instruction->hasSideEffects();
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500539 }
540 else if(isStore(*instruction))
541 {
542 if(Ice::Variable *address = llvm::dyn_cast<Ice::Variable>(storeAddress(instruction)))
543 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400544 Ice::Inst *def = getDefinition(address);
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500545
Nicolas Capensda721422017-01-27 02:26:12 -0800546 if(def && llvm::isa<Ice::InstAlloca>(def))
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500547 {
Alexis Hetu932640b2018-06-20 15:35:53 -0400548 if(hasUses(address))
549 {
550 Optimizer::Uses* uses = getUses(address);
551 return uses->size() == uses->stores.size(); // Dead if all uses are stores
552 }
553 else
554 {
555 return true; // No uses
556 }
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500557 }
558 }
559 }
560
561 return false;
562 }
563
Nicolas Capens709f69b2017-07-26 11:30:33 -0400564 const Ice::InstIntrinsicCall *Optimizer::asLoadSubVector(const Ice::Inst *instruction)
565 {
566 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
567 {
568 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector)
569 {
570 return instrinsic;
571 }
572 }
573
574 return nullptr;
575 }
576
577 const Ice::InstIntrinsicCall *Optimizer::asStoreSubVector(const Ice::Inst *instruction)
578 {
579 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
580 {
581 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector)
582 {
583 return instrinsic;
584 }
585 }
586
587 return nullptr;
588 }
589
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500590 bool Optimizer::isLoad(const Ice::Inst &instruction)
591 {
592 if(llvm::isa<Ice::InstLoad>(&instruction))
593 {
594 return true;
595 }
596
Nicolas Capens709f69b2017-07-26 11:30:33 -0400597 return asLoadSubVector(&instruction) != nullptr;
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500598 }
599
600 bool Optimizer::isStore(const Ice::Inst &instruction)
601 {
602 if(llvm::isa<Ice::InstStore>(&instruction))
603 {
604 return true;
605 }
606
Nicolas Capens709f69b2017-07-26 11:30:33 -0400607 return asStoreSubVector(&instruction) != nullptr;
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500608 }
609
610 Ice::Operand *Optimizer::storeAddress(const Ice::Inst *instruction)
611 {
612 assert(isStore(*instruction));
613
614 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
615 {
616 return store->getAddr();
617 }
618
Nicolas Capens709f69b2017-07-26 11:30:33 -0400619 if(auto *storeSubVector = asStoreSubVector(instruction))
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500620 {
Nicolas Capens709f69b2017-07-26 11:30:33 -0400621 return storeSubVector->getSrc(2);
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500622 }
623
624 return nullptr;
625 }
626
627 Ice::Operand *Optimizer::loadAddress(const Ice::Inst *instruction)
628 {
629 assert(isLoad(*instruction));
630
631 if(auto *load = llvm::dyn_cast<Ice::InstLoad>(instruction))
632 {
633 return load->getSourceAddress();
634 }
635
Nicolas Capens709f69b2017-07-26 11:30:33 -0400636 if(auto *loadSubVector = asLoadSubVector(instruction))
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500637 {
Nicolas Capens709f69b2017-07-26 11:30:33 -0400638 return loadSubVector->getSrc(1);
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500639 }
640
641 return nullptr;
642 }
643
Nicolas Capense205c3d2016-11-30 15:14:28 -0500644 Ice::Operand *Optimizer::storeData(const Ice::Inst *instruction)
645 {
646 assert(isStore(*instruction));
647
648 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
649 {
650 return store->getData();
651 }
652
Nicolas Capens709f69b2017-07-26 11:30:33 -0400653 if(auto *storeSubVector = asStoreSubVector(instruction))
Nicolas Capense205c3d2016-11-30 15:14:28 -0500654 {
Nicolas Capens709f69b2017-07-26 11:30:33 -0400655 return storeSubVector->getSrc(1);
Nicolas Capense205c3d2016-11-30 15:14:28 -0500656 }
657
658 return nullptr;
659 }
660
Nicolas Capensf2f5e962017-07-25 12:57:12 -0400661 std::size_t Optimizer::storeSize(const Ice::Inst *store)
662 {
663 assert(isStore(*store));
664
665 if(auto *instStore = llvm::dyn_cast<Ice::InstStore>(store))
666 {
667 return Ice::typeWidthInBytes(instStore->getData()->getType());
668 }
669
670 if(auto *storeSubVector = asStoreSubVector(store))
671 {
672 return llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(3))->getValue();
673 }
674
675 return 0;
676 }
677
Nicolas Capens87722022017-07-25 13:24:40 -0400678 bool Optimizer::loadTypeMatchesStore(const Ice::Inst *load, const Ice::Inst *store)
679 {
680 if(!load || !store)
681 {
682 return false;
683 }
684
685 assert(isLoad(*load) && isStore(*store));
686 assert(loadAddress(load) == storeAddress(store));
687
688 if(auto *instStore = llvm::dyn_cast<Ice::InstStore>(store))
689 {
690 if(auto *instLoad = llvm::dyn_cast<Ice::InstLoad>(load))
691 {
692 return instStore->getData()->getType() == instLoad->getDest()->getType();
693 }
694 }
695
696 if(auto *storeSubVector = asStoreSubVector(store))
697 {
698 if(auto *loadSubVector = asLoadSubVector(load))
699 {
700 // Check for matching type and sub-vector width.
701 return storeSubVector->getSrc(1)->getType() == loadSubVector->getDest()->getType() &&
702 llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(3))->getValue() ==
703 llvm::cast<Ice::ConstantInteger32>(loadSubVector->getSrc(2))->getValue();
704 }
705 }
706
707 return false;
708 }
709
Alexis Hetu932640b2018-06-20 15:35:53 -0400710 Optimizer::Uses* Optimizer::getUses(Ice::Operand* operand)
711 {
712 Optimizer::Uses* uses = (Optimizer::Uses*)operand->Ice::Operand::getExternalData();
713 if(!uses)
714 {
715 uses = new Optimizer::Uses;
716 setUses(operand, uses);
717 allocatedUses.push_back(uses);
718 }
719 return uses;
720 }
721
722 void Optimizer::setUses(Ice::Operand* operand, Optimizer::Uses* uses)
723 {
724 operand->Ice::Operand::setExternalData(uses);
725 }
726
727 bool Optimizer::hasUses(Ice::Operand* operand) const
728 {
729 return operand->Ice::Operand::getExternalData() != nullptr;
730 }
731
732 Ice::CfgNode* Optimizer::getNode(Ice::Inst* inst)
733 {
734 return (Ice::CfgNode*)inst->Ice::Inst::getExternalData();
735 }
736
737 void Optimizer::setNode(Ice::Inst* inst, Ice::CfgNode* node)
738 {
739 inst->Ice::Inst::setExternalData(node);
740 }
741
742 Ice::Inst* Optimizer::getDefinition(Ice::Variable* var)
743 {
744 return (Ice::Inst*)var->Ice::Variable::getExternalData();
745 }
746
747 void Optimizer::setDefinition(Ice::Variable* var, Ice::Inst* inst)
748 {
749 var->Ice::Variable::setExternalData(inst);
750 }
751
752 const std::vector<Optimizer::LoadStoreInst>& Optimizer::getLoadStoreInsts(Ice::CfgNode* node)
753 {
754 return *((const std::vector<LoadStoreInst>*)node->Ice::CfgNode::getExternalData());
755 }
756
757 void Optimizer::setLoadStoreInsts(Ice::CfgNode* node, std::vector<LoadStoreInst>* insts)
758 {
759 node->Ice::CfgNode::setExternalData(insts);
760 }
761
762 bool Optimizer::hasLoadStoreInsts(Ice::CfgNode* node) const
763 {
764 return node->Ice::CfgNode::getExternalData() != nullptr;
765 }
766
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500767 bool Optimizer::Uses::areOnlyLoadStore() const
768 {
769 return size() == (loads.size() + stores.size());
770 }
771
772 void Optimizer::Uses::insert(Ice::Operand *value, Ice::Inst *instruction)
773 {
774 push_back(instruction);
775
776 if(isLoad(*instruction))
777 {
778 if(value == loadAddress(instruction))
779 {
780 loads.push_back(instruction);
781 }
782 }
783 else if(isStore(*instruction))
784 {
785 if(value == storeAddress(instruction))
786 {
787 stores.push_back(instruction);
788 }
789 }
790 }
791
792 void Optimizer::Uses::erase(Ice::Inst *instruction)
793 {
794 auto &uses = *this;
795
Alexis Hetu113e33a2017-01-19 10:49:19 -0500796 for(size_t i = 0; i < uses.size(); i++)
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500797 {
798 if(uses[i] == instruction)
799 {
800 uses[i] = back();
801 pop_back();
802
Alexis Hetu113e33a2017-01-19 10:49:19 -0500803 for(size_t i = 0; i < loads.size(); i++)
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500804 {
805 if(loads[i] == instruction)
806 {
807 loads[i] = loads.back();
808 loads.pop_back();
809 break;
810 }
811 }
812
Alexis Hetu113e33a2017-01-19 10:49:19 -0500813 for(size_t i = 0; i < stores.size(); i++)
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500814 {
815 if(stores[i] == instruction)
816 {
817 stores[i] = stores.back();
818 stores.pop_back();
819 break;
820 }
821 }
822
823 break;
824 }
825 }
826 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500827}
828
Nicolas Capens48461502018-08-06 14:20:45 -0400829namespace rr
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500830{
831 void optimize(Ice::Cfg *function)
832 {
833 Optimizer optimizer;
834
835 optimizer.run(function);
836 }
837}