blob: ffd29bb789fe652e4d90e61246618dbcfb12729b [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
20#include <map>
21#include <vector>
22
23namespace
24{
25 class Optimizer
26 {
27 public:
28 void run(Ice::Cfg *function);
29
30 private:
31 void analyzeUses(Ice::Cfg *function);
Nicolas Capensc9d70d52016-12-12 15:07:39 -050032 void eliminateDeadCode();
Nicolas Capensf4452fc2016-12-12 13:08:06 -050033 void eliminateUnitializedLoads();
Nicolas Capense205c3d2016-11-30 15:14:28 -050034 void eliminateLoadsFollowingSingleStore();
Nicolas Capens16252ab2016-11-30 16:15:28 -050035 void optimizeStoresInSingleBasicBlock();
Nicolas Capense205c3d2016-11-30 15:14:28 -050036
37 void replace(Ice::Inst *instruction, Ice::Operand *newValue);
38 void deleteInstruction(Ice::Inst *instruction);
Nicolas Capensc9d70d52016-12-12 15:07:39 -050039 bool isDead(Ice::Inst *instruction);
Nicolas Capensf4452fc2016-12-12 13:08:06 -050040
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);
Nicolas Capense205c3d2016-11-30 15:14:28 -050045 static Ice::Operand *storeData(const Ice::Inst *instruction);
Nicolas Capens2ae9d742016-11-24 14:43:05 -050046
47 Ice::Cfg *function;
Nicolas Capensf4452fc2016-12-12 13:08:06 -050048 Ice::GlobalContext *context;
Nicolas Capens2ae9d742016-11-24 14:43:05 -050049
Nicolas Capensf4452fc2016-12-12 13:08:06 -050050 struct Uses : std::vector<Ice::Inst*>
51 {
52 bool areOnlyLoadStore() const;
53 void insert(Ice::Operand *value, Ice::Inst *instruction);
54 void erase(Ice::Inst *instruction);
55
56 std::vector<Ice::Inst*> loads;
57 std::vector<Ice::Inst*> stores;
58 };
59
60 std::map<Ice::Operand*, Uses> uses;
Nicolas Capense205c3d2016-11-30 15:14:28 -050061 std::map<Ice::Inst*, Ice::CfgNode*> node;
62 std::map<Ice::Variable*, Ice::Inst*> definition;
Nicolas Capens2ae9d742016-11-24 14:43:05 -050063 };
64
65 void Optimizer::run(Ice::Cfg *function)
66 {
67 this->function = function;
Nicolas Capensf4452fc2016-12-12 13:08:06 -050068 this->context = function->getContext();
Nicolas Capens2ae9d742016-11-24 14:43:05 -050069
70 analyzeUses(function);
71
Nicolas Capensc9d70d52016-12-12 15:07:39 -050072 eliminateDeadCode();
Nicolas Capensf4452fc2016-12-12 13:08:06 -050073 eliminateUnitializedLoads();
Nicolas Capense205c3d2016-11-30 15:14:28 -050074 eliminateLoadsFollowingSingleStore();
Nicolas Capens16252ab2016-11-30 16:15:28 -050075 optimizeStoresInSingleBasicBlock();
Nicolas Capensc9d70d52016-12-12 15:07:39 -050076 eliminateDeadCode();
Nicolas Capens2ae9d742016-11-24 14:43:05 -050077 }
78
Nicolas Capensc9d70d52016-12-12 15:07:39 -050079 void Optimizer::eliminateDeadCode()
Nicolas Capens2ae9d742016-11-24 14:43:05 -050080 {
Nicolas Capensc9d70d52016-12-12 15:07:39 -050081 bool modified;
82 do
Nicolas Capens2ae9d742016-11-24 14:43:05 -050083 {
Nicolas Capensc9d70d52016-12-12 15:07:39 -050084 modified = false;
85 for(Ice::CfgNode *basicBlock : function->getNodes())
Nicolas Capens2ae9d742016-11-24 14:43:05 -050086 {
Nicolas Capensc9d70d52016-12-12 15:07:39 -050087 for(Ice::Inst &inst : Ice::reverse_range(basicBlock->getInsts()))
88 {
89 if(inst.isDeleted())
90 {
91 continue;
92 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -050093
Nicolas Capensc9d70d52016-12-12 15:07:39 -050094 if(isDead(&inst))
95 {
96 deleteInstruction(&inst);
97 modified = true;
98 }
99 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500100 }
101 }
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500102 while(modified);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500103 }
104
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500105 void Optimizer::eliminateUnitializedLoads()
106 {
107 Ice::CfgNode *entryBlock = function->getEntryNode();
108
109 for(Ice::Inst &alloca : entryBlock->getInsts())
110 {
111 if(alloca.isDeleted())
112 {
113 continue;
114 }
115
116 if(!llvm::isa<Ice::InstAlloca>(alloca))
117 {
118 return; // Allocas are all at the top
119 }
120
121 Ice::Operand *address = alloca.getDest();
122 const auto &addressEntry = uses.find(address);
123 const auto &addressUses = addressEntry->second;
124
125 if(!addressUses.areOnlyLoadStore())
126 {
127 continue;
128 }
129
130 if(addressUses.stores.empty())
131 {
132 for(Ice::Inst *load : addressUses.loads)
133 {
134 Ice::Variable *loadData = load->getDest();
135
136 for(Ice::Inst *use : uses[loadData])
137 {
138 for(int i = 0; i < use->getSrcSize(); i++)
139 {
140 if(use->getSrc(i) == loadData)
141 {
142 auto *undef = context->getConstantUndef(loadData->getType());
143
144 use->replaceSource(i, undef);
145 }
146 }
147 }
148
149 uses.erase(loadData);
150
151 load->setDeleted();
152 }
153
154 alloca.setDeleted();
155 uses.erase(addressEntry);
156 }
157 }
158 }
159
Nicolas Capense205c3d2016-11-30 15:14:28 -0500160 void Optimizer::eliminateLoadsFollowingSingleStore()
161 {
162 Ice::CfgNode *entryBlock = function->getEntryNode();
163
164 for(Ice::Inst &alloca : entryBlock->getInsts())
165 {
166 if(alloca.isDeleted())
167 {
168 continue;
169 }
170
171 if(!llvm::isa<Ice::InstAlloca>(alloca))
172 {
173 return; // Allocas are all at the top
174 }
175
176 Ice::Operand *address = alloca.getDest();
177 const auto &addressEntry = uses.find(address);
178 auto &addressUses = addressEntry->second;
179
180 if(!addressUses.areOnlyLoadStore())
181 {
182 continue;
183 }
184
185 if(addressUses.stores.size() == 1)
186 {
187 Ice::Inst *store = addressUses.stores[0];
188 Ice::Operand *storeValue = storeData(store);
189
190 for(Ice::Inst *load = &*++store->getIterator(), *next = nullptr; load != next; next = load, load = &*++store->getIterator())
191 {
192 if(load->isDeleted() || !isLoad(*load))
193 {
194 continue;
195 }
196
197 if(loadAddress(load) != address)
198 {
199 continue;
200 }
201
202 replace(load, storeValue);
203
204 for(int i = 0; i < addressUses.loads.size(); i++)
205 {
206 if(addressUses.loads[i] == load)
207 {
208 addressUses.loads[i] = addressUses.loads.back();
209 addressUses.loads.pop_back();
210 break;
211 }
212 }
213
214 for(int i = 0; i < addressUses.size(); i++)
215 {
216 if(addressUses[i] == load)
217 {
218 addressUses[i] = addressUses.back();
219 addressUses.pop_back();
220 break;
221 }
222 }
223
224 if(addressUses.size() == 1)
225 {
226 assert(addressUses[0] == store);
227
228 alloca.setDeleted();
229 store->setDeleted();
230 uses.erase(address);
231
232 auto &valueUses = uses[storeValue];
233
234 for(int i = 0; i < valueUses.size(); i++)
235 {
236 if(valueUses[i] == store)
237 {
238 valueUses[i] = valueUses.back();
239 valueUses.pop_back();
240 break;
241 }
242 }
243
244 if(valueUses.empty())
245 {
246 uses.erase(storeValue);
247 }
248
249 break;
250 }
251 }
252 }
253 }
254 }
255
Nicolas Capens16252ab2016-11-30 16:15:28 -0500256 void Optimizer::optimizeStoresInSingleBasicBlock()
257 {
258 Ice::CfgNode *entryBlock = function->getEntryNode();
259
260 for(Ice::Inst &alloca : entryBlock->getInsts())
261 {
262 if(alloca.isDeleted())
263 {
264 continue;
265 }
266
267 if(!llvm::isa<Ice::InstAlloca>(alloca))
268 {
269 return; // Allocas are all at the top
270 }
271
272 Ice::Operand *address = alloca.getDest();
273 const auto &addressEntry = uses.find(address);
274 const auto &addressUses = addressEntry->second;
275
276 if(!addressUses.areOnlyLoadStore())
277 {
278 continue;
279 }
280
281 Ice::CfgNode *singleBasicBlock = node[addressUses.stores[0]];
282
283 for(int i = 1; i < addressUses.stores.size(); i++)
284 {
285 Ice::Inst *store = addressUses.stores[i];
286 if(node[store] != singleBasicBlock)
287 {
288 singleBasicBlock = nullptr;
289 break;
290 }
291 }
292
293 if(singleBasicBlock)
294 {
295 auto &insts = singleBasicBlock->getInsts();
296 Ice::Inst *store = nullptr;
297 Ice::Operand *storeValue = nullptr;
298
299 for(Ice::Inst &inst : insts)
300 {
301 if(inst.isDeleted())
302 {
303 continue;
304 }
305
306 if(isStore(inst))
307 {
308 if(storeAddress(&inst) != address)
309 {
310 continue;
311 }
312
313 // New store found. If we had a previous one, eliminate it.
314 if(store)
315 {
316 deleteInstruction(store);
317 }
318
319 store = &inst;
320 storeValue = storeData(store);
321 }
322 else if(isLoad(inst))
323 {
324 Ice::Inst *load = &inst;
325
326 if(loadAddress(load) != address)
327 {
328 continue;
329 }
330
331 replace(load, storeValue);
332 }
333 }
334 }
335 }
336 }
337
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500338 void Optimizer::analyzeUses(Ice::Cfg *function)
339 {
340 uses.clear();
Nicolas Capense205c3d2016-11-30 15:14:28 -0500341 node.clear();
342 definition.clear();
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500343
344 for(Ice::CfgNode *basicBlock : function->getNodes())
345 {
346 for(Ice::Inst &instruction : basicBlock->getInsts())
347 {
348 if(instruction.isDeleted())
349 {
350 continue;
351 }
352
Nicolas Capense205c3d2016-11-30 15:14:28 -0500353 node[&instruction] = basicBlock;
354 definition[instruction.getDest()] = &instruction;
355
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500356 for(int i = 0; i < instruction.getSrcSize(); i++)
357 {
358 int unique = 0;
359 for(; unique < i; unique++)
360 {
361 if(instruction.getSrc(i) == instruction.getSrc(unique))
362 {
363 break;
364 }
365 }
366
367 if(i == unique)
368 {
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500369 Ice::Operand *src = instruction.getSrc(i);
370 uses[src].insert(src, &instruction);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500371 }
372 }
373 }
374 }
375 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500376
Nicolas Capense205c3d2016-11-30 15:14:28 -0500377 void Optimizer::replace(Ice::Inst *instruction, Ice::Operand *newValue)
378 {
379 Ice::Variable *oldValue = instruction->getDest();
380
381 if(!newValue)
382 {
383 newValue = context->getConstantUndef(oldValue->getType());
384 }
385
386 for(Ice::Inst *use : uses[oldValue])
387 {
388 assert(!use->isDeleted()); // Should have been removed from uses already
389
390 for(int i = 0; i < use->getSrcSize(); i++)
391 {
392 if(use->getSrc(i) == oldValue)
393 {
394 use->replaceSource(i, newValue);
395 }
396 }
397
398 uses[newValue].insert(newValue, use);
399 }
400
401 uses.erase(oldValue);
402
403 deleteInstruction(instruction);
404 }
405
406 void Optimizer::deleteInstruction(Ice::Inst *instruction)
407 {
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500408 if(!instruction || instruction->isDeleted())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500409 {
410 return;
411 }
412
413 instruction->setDeleted();
414
415 for(int i = 0; i < instruction->getSrcSize(); i++)
416 {
417 Ice::Operand *src = instruction->getSrc(i);
418
419 const auto &srcEntry = uses.find(src);
420
421 if(srcEntry != uses.end())
422 {
423 auto &srcUses = srcEntry->second;
424
425 srcUses.erase(instruction);
426
427 if(srcUses.empty())
428 {
429 uses.erase(srcEntry);
430
431 if(Ice::Variable *var = llvm::dyn_cast<Ice::Variable>(src))
432 {
433 deleteInstruction(definition[var]);
434 }
435 }
436 }
437 }
438 }
439
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500440 bool Optimizer::isDead(Ice::Inst *instruction)
441 {
442 Ice::Variable *dest = instruction->getDest();
443
444 if(dest)
445 {
446 return uses[dest].empty() && !instruction->hasSideEffects();
447 }
448 else if(isStore(*instruction))
449 {
450 if(Ice::Variable *address = llvm::dyn_cast<Ice::Variable>(storeAddress(instruction)))
451 {
452 Ice::Inst *def = definition[address];
453
454 if(!def || llvm::isa<Ice::InstAlloca>(def))
455 {
456 return uses[address].size() == 1; // Dead if this store is the only use
457 }
458 }
459 }
460
461 return false;
462 }
463
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500464 bool Optimizer::isLoad(const Ice::Inst &instruction)
465 {
466 if(llvm::isa<Ice::InstLoad>(&instruction))
467 {
468 return true;
469 }
470
471 if(auto intrinsicCall = llvm::dyn_cast<Ice::InstIntrinsicCall>(&instruction))
472 {
473 return intrinsicCall->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector;
474 }
475
476 return false;
477 }
478
479 bool Optimizer::isStore(const Ice::Inst &instruction)
480 {
481 if(llvm::isa<Ice::InstStore>(&instruction))
482 {
483 return true;
484 }
485
486 if(auto intrinsicCall = llvm::dyn_cast<Ice::InstIntrinsicCall>(&instruction))
487 {
488 return intrinsicCall->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector;
489 }
490
491 return false;
492 }
493
494 Ice::Operand *Optimizer::storeAddress(const Ice::Inst *instruction)
495 {
496 assert(isStore(*instruction));
497
498 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
499 {
500 return store->getAddr();
501 }
502
503 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
504 {
505 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector)
506 {
507 return instrinsic->getSrc(2);
508 }
509 }
510
511 return nullptr;
512 }
513
514 Ice::Operand *Optimizer::loadAddress(const Ice::Inst *instruction)
515 {
516 assert(isLoad(*instruction));
517
518 if(auto *load = llvm::dyn_cast<Ice::InstLoad>(instruction))
519 {
520 return load->getSourceAddress();
521 }
522
523 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
524 {
525 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector)
526 {
527 return instrinsic->getSrc(1);
528 }
529 }
530
531 return nullptr;
532 }
533
Nicolas Capense205c3d2016-11-30 15:14:28 -0500534 Ice::Operand *Optimizer::storeData(const Ice::Inst *instruction)
535 {
536 assert(isStore(*instruction));
537
538 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
539 {
540 return store->getData();
541 }
542
543 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
544 {
545 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector)
546 {
547 return instrinsic->getSrc(1);
548 }
549 }
550
551 return nullptr;
552 }
553
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500554 bool Optimizer::Uses::areOnlyLoadStore() const
555 {
556 return size() == (loads.size() + stores.size());
557 }
558
559 void Optimizer::Uses::insert(Ice::Operand *value, Ice::Inst *instruction)
560 {
561 push_back(instruction);
562
563 if(isLoad(*instruction))
564 {
565 if(value == loadAddress(instruction))
566 {
567 loads.push_back(instruction);
568 }
569 }
570 else if(isStore(*instruction))
571 {
572 if(value == storeAddress(instruction))
573 {
574 stores.push_back(instruction);
575 }
576 }
577 }
578
579 void Optimizer::Uses::erase(Ice::Inst *instruction)
580 {
581 auto &uses = *this;
582
583 for(int i = 0; i < uses.size(); i++)
584 {
585 if(uses[i] == instruction)
586 {
587 uses[i] = back();
588 pop_back();
589
590 for(int i = 0; i < loads.size(); i++)
591 {
592 if(loads[i] == instruction)
593 {
594 loads[i] = loads.back();
595 loads.pop_back();
596 break;
597 }
598 }
599
600 for(int i = 0; i < stores.size(); i++)
601 {
602 if(stores[i] == instruction)
603 {
604 stores[i] = stores.back();
605 stores.pop_back();
606 break;
607 }
608 }
609
610 break;
611 }
612 }
613 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500614}
615
616namespace sw
617{
618 void optimize(Ice::Cfg *function)
619 {
620 Optimizer optimizer;
621
622 optimizer.run(function);
623 }
624}