blob: 184ac750f7223ad23f53717e96b4c3a2582b2e11 [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
Nicolas Capens157ba262019-12-10 17:49:14 -050022namespace {
23
24class Optimizer
Nicolas Capens2ae9d742016-11-24 14:43:05 -050025{
Nicolas Capens157ba262019-12-10 17:49:14 -050026public:
27 void run(Ice::Cfg *function);
28
29private:
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
Ben Clayton713b8d32019-12-17 20:37:56 +000053 struct Uses : std::vector<Ice::Inst *>
Nicolas Capens2ae9d742016-11-24 14:43:05 -050054 {
Nicolas Capens157ba262019-12-10 17:49:14 -050055 bool areOnlyLoadStore() const;
56 void insert(Ice::Operand *value, Ice::Inst *instruction);
57 void erase(Ice::Inst *instruction);
Nicolas Capens2ae9d742016-11-24 14:43:05 -050058
Ben Clayton713b8d32019-12-17 20:37:56 +000059 std::vector<Ice::Inst *> loads;
60 std::vector<Ice::Inst *> stores;
Nicolas Capens2ae9d742016-11-24 14:43:05 -050061 };
62
Nicolas Capens157ba262019-12-10 17:49:14 -050063 struct LoadStoreInst
Nicolas Capens2ae9d742016-11-24 14:43:05 -050064 {
Ben Clayton713b8d32019-12-17 20:37:56 +000065 LoadStoreInst(Ice::Inst *inst, bool isStore)
66 : inst(inst)
67 , address(isStore ? storeAddress(inst) : loadAddress(inst))
68 , isStore(isStore)
Alexis Hetu932640b2018-06-20 15:35:53 -040069 {
Alexis Hetu932640b2018-06-20 15:35:53 -040070 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -050071
Ben Clayton713b8d32019-12-17 20:37:56 +000072 Ice::Inst *inst;
Nicolas Capens157ba262019-12-10 17:49:14 -050073 Ice::Operand *address;
74 bool isStore;
75 };
76
Ben Clayton713b8d32019-12-17 20:37:56 +000077 Optimizer::Uses *getUses(Ice::Operand *);
78 void setUses(Ice::Operand *, Optimizer::Uses *);
79 bool hasUses(Ice::Operand *) const;
Nicolas Capens157ba262019-12-10 17:49:14 -050080
Ben Clayton713b8d32019-12-17 20:37:56 +000081 Ice::CfgNode *getNode(Ice::Inst *);
82 void setNode(Ice::Inst *, Ice::CfgNode *);
Nicolas Capens157ba262019-12-10 17:49:14 -050083
Ben Clayton713b8d32019-12-17 20:37:56 +000084 Ice::Inst *getDefinition(Ice::Variable *);
85 void setDefinition(Ice::Variable *, Ice::Inst *);
Nicolas Capens157ba262019-12-10 17:49:14 -050086
Ben Clayton713b8d32019-12-17 20:37:56 +000087 const std::vector<LoadStoreInst> &getLoadStoreInsts(Ice::CfgNode *);
88 void setLoadStoreInsts(Ice::CfgNode *, std::vector<LoadStoreInst> *);
89 bool hasLoadStoreInsts(Ice::CfgNode *node) const;
Nicolas Capens157ba262019-12-10 17:49:14 -050090
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -050091 std::vector<Ice::Operand *> operandsWithUses;
Nicolas Capens157ba262019-12-10 17:49:14 -050092};
93
94void 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
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500107 for(auto operand : operandsWithUses)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500108 {
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500109 // Deletes the Uses instance on the operand
110 setUses(operand, nullptr);
Nicolas Capens157ba262019-12-10 17:49:14 -0500111 }
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500112 operandsWithUses.clear();
Nicolas Capens157ba262019-12-10 17:49:14 -0500113}
114
115void Optimizer::eliminateDeadCode()
116{
117 bool modified;
118 do
119 {
120 modified = false;
121 for(Ice::CfgNode *basicBlock : function->getNodes())
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500122 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500123 for(Ice::Inst &inst : Ice::reverse_range(basicBlock->getInsts()))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500124 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500125 if(inst.isDeleted())
126 {
127 continue;
128 }
129
130 if(isDead(&inst))
131 {
132 deleteInstruction(&inst);
133 modified = true;
134 }
135 }
136 }
Ben Clayton713b8d32019-12-17 20:37:56 +0000137 } while(modified);
Nicolas Capens157ba262019-12-10 17:49:14 -0500138}
139
140void 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 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000153 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500154 }
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
203void 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 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000216 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500217 }
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
Antonio Maioranob3d9a2a2020-02-14 14:38:04 -0500255 // 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
Nicolas Capens157ba262019-12-10 17:49:14 -0500263 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
320void Optimizer::optimizeStoresInSingleBasicBlock()
321{
322 Ice::CfgNode *entryBlock = function->getEntryNode();
323
Ben Clayton713b8d32019-12-17 20:37:56 +0000324 std::vector<std::vector<LoadStoreInst> *> allocatedVectors;
Nicolas Capens157ba262019-12-10 17:49:14 -0500325
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 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000335 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500336 }
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 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000368 std::vector<LoadStoreInst> *loadStoreInstVector = new std::vector<LoadStoreInst>();
Nicolas Capens157ba262019-12-10 17:49:14 -0500369 setLoadStoreInsts(singleBasicBlock, loadStoreInstVector);
370 allocatedVectors.push_back(loadStoreInstVector);
371 for(Ice::Inst &inst : singleBasicBlock->getInsts())
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500372 {
373 if(inst.isDeleted())
374 {
375 continue;
376 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500377
Nicolas Capens157ba262019-12-10 17:49:14 -0500378 bool isStoreInst = isStore(inst);
379 bool isLoadInst = isLoad(inst);
380
381 if(isStoreInst || isLoadInst)
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500382 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500383 loadStoreInstVector->push_back(LoadStoreInst(&inst, isStoreInst));
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500384 }
385 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500386 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500387
Nicolas Capens157ba262019-12-10 17:49:14 -0500388 Ice::Inst *store = nullptr;
389 Ice::Operand *storeValue = nullptr;
390 bool unmatchedLoads = false;
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500391
Ben Clayton713b8d32019-12-17 20:37:56 +0000392 for(auto &loadStoreInst : getLoadStoreInsts(singleBasicBlock))
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500393 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000394 Ice::Inst *inst = loadStoreInst.inst;
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500395
Nicolas Capens157ba262019-12-10 17:49:14 -0500396 if((loadStoreInst.address != address) || inst->isDeleted())
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500397 {
398 continue;
399 }
400
Nicolas Capens157ba262019-12-10 17:49:14 -0500401 if(loadStoreInst.isStore)
Alexis Hetu932640b2018-06-20 15:35:53 -0400402 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500403 // New store found. If we had a previous one, try to eliminate it.
404 if(store && !unmatchedLoads)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500405 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500406 // 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))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500409 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500410 deleteInstruction(store);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500411 }
412 }
413
Nicolas Capens157ba262019-12-10 17:49:14 -0500414 store = inst;
415 storeValue = storeData(store);
416 unmatchedLoads = false;
417 }
418 else
419 {
420 if(!loadTypeMatchesStore(inst, store))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500421 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500422 unmatchedLoads = true;
423 continue;
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500424 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500425
Antonio Maioranob3d9a2a2020-02-14 14:38:04 -0500426 // 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 continue;
432 }
433
Nicolas Capens157ba262019-12-10 17:49:14 -0500434 replace(inst, storeValue);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500435 }
436 }
437 }
438 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500439
Nicolas Capens157ba262019-12-10 17:49:14 -0500440 for(auto loadStoreInstVector : allocatedVectors)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500441 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500442 delete loadStoreInstVector;
443 }
444}
Nicolas Capense205c3d2016-11-30 15:14:28 -0500445
Nicolas Capens157ba262019-12-10 17:49:14 -0500446void Optimizer::analyzeUses(Ice::Cfg *function)
447{
448 for(Ice::CfgNode *basicBlock : function->getNodes())
449 {
450 for(Ice::Inst &instruction : basicBlock->getInsts())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500451 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500452 if(instruction.isDeleted())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500453 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500454 continue;
455 }
Alexis Hetu932640b2018-06-20 15:35:53 -0400456
Nicolas Capens157ba262019-12-10 17:49:14 -0500457 setNode(&instruction, basicBlock);
458 if(instruction.getDest())
459 {
460 setDefinition(instruction.getDest(), &instruction);
461 }
462
463 for(Ice::SizeT i = 0; i < instruction.getSrcSize(); i++)
464 {
465 Ice::SizeT unique = 0;
466 for(; unique < i; unique++)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500467 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500468 if(instruction.getSrc(i) == instruction.getSrc(unique))
Alexis Hetu932640b2018-06-20 15:35:53 -0400469 {
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500470 break;
471 }
472 }
473
Nicolas Capens157ba262019-12-10 17:49:14 -0500474 if(i == unique)
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500475 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500476 Ice::Operand *src = instruction.getSrc(i);
477 getUses(src)->insert(src, &instruction);
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500478 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500479 }
480 }
481 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500482}
483
Nicolas Capens157ba262019-12-10 17:49:14 -0500484void Optimizer::replace(Ice::Inst *instruction, Ice::Operand *newValue)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500485{
Nicolas Capens157ba262019-12-10 17:49:14 -0500486 Ice::Variable *oldValue = instruction->getDest();
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500487
Nicolas Capens157ba262019-12-10 17:49:14 -0500488 if(!newValue)
489 {
490 newValue = context->getConstantUndef(oldValue->getType());
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500491 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500492
493 if(hasUses(oldValue))
494 {
495 for(Ice::Inst *use : *getUses(oldValue))
496 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000497 assert(!use->isDeleted()); // Should have been removed from uses already
Nicolas Capens157ba262019-12-10 17:49:14 -0500498
499 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
500 {
501 if(use->getSrc(i) == oldValue)
502 {
503 use->replaceSource(i, newValue);
504 }
505 }
506
507 getUses(newValue)->insert(newValue, use);
508 }
509
510 setUses(oldValue, nullptr);
511 }
512
513 deleteInstruction(instruction);
514}
515
516void Optimizer::deleteInstruction(Ice::Inst *instruction)
517{
518 if(!instruction || instruction->isDeleted())
519 {
520 return;
521 }
522
523 instruction->setDeleted();
524
525 for(Ice::SizeT i = 0; i < instruction->getSrcSize(); i++)
526 {
527 Ice::Operand *src = instruction->getSrc(i);
528
529 if(hasUses(src))
530 {
531 auto &srcUses = *getUses(src);
532
533 srcUses.erase(instruction);
534
535 if(srcUses.empty())
536 {
537 setUses(src, nullptr);
538
539 if(Ice::Variable *var = llvm::dyn_cast<Ice::Variable>(src))
540 {
541 deleteInstruction(getDefinition(var));
542 }
543 }
544 }
545 }
546}
547
548bool Optimizer::isDead(Ice::Inst *instruction)
549{
550 Ice::Variable *dest = instruction->getDest();
551
552 if(dest)
553 {
554 return (!hasUses(dest) || getUses(dest)->empty()) && !instruction->hasSideEffects();
555 }
556 else if(isStore(*instruction))
557 {
558 if(Ice::Variable *address = llvm::dyn_cast<Ice::Variable>(storeAddress(instruction)))
559 {
560 Ice::Inst *def = getDefinition(address);
561
562 if(def && llvm::isa<Ice::InstAlloca>(def))
563 {
564 if(hasUses(address))
565 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000566 Optimizer::Uses *uses = getUses(address);
567 return uses->size() == uses->stores.size(); // Dead if all uses are stores
Nicolas Capens157ba262019-12-10 17:49:14 -0500568 }
569 else
570 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000571 return true; // No uses
Nicolas Capens157ba262019-12-10 17:49:14 -0500572 }
573 }
574 }
575 }
576
577 return false;
578}
579
580const Ice::InstIntrinsicCall *Optimizer::asLoadSubVector(const Ice::Inst *instruction)
581{
582 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
583 {
584 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector)
585 {
586 return instrinsic;
587 }
588 }
589
590 return nullptr;
591}
592
593const Ice::InstIntrinsicCall *Optimizer::asStoreSubVector(const Ice::Inst *instruction)
594{
595 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
596 {
597 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector)
598 {
599 return instrinsic;
600 }
601 }
602
603 return nullptr;
604}
605
606bool Optimizer::isLoad(const Ice::Inst &instruction)
607{
608 if(llvm::isa<Ice::InstLoad>(&instruction))
609 {
610 return true;
611 }
612
613 return asLoadSubVector(&instruction) != nullptr;
614}
615
616bool Optimizer::isStore(const Ice::Inst &instruction)
617{
618 if(llvm::isa<Ice::InstStore>(&instruction))
619 {
620 return true;
621 }
622
623 return asStoreSubVector(&instruction) != nullptr;
624}
625
626Ice::Operand *Optimizer::storeAddress(const Ice::Inst *instruction)
627{
628 assert(isStore(*instruction));
629
630 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
631 {
632 return store->getAddr();
633 }
634
635 if(auto *storeSubVector = asStoreSubVector(instruction))
636 {
637 return storeSubVector->getSrc(2);
638 }
639
640 return nullptr;
641}
642
643Ice::Operand *Optimizer::loadAddress(const Ice::Inst *instruction)
644{
645 assert(isLoad(*instruction));
646
647 if(auto *load = llvm::dyn_cast<Ice::InstLoad>(instruction))
648 {
649 return load->getSourceAddress();
650 }
651
652 if(auto *loadSubVector = asLoadSubVector(instruction))
653 {
654 return loadSubVector->getSrc(1);
655 }
656
657 return nullptr;
658}
659
660Ice::Operand *Optimizer::storeData(const Ice::Inst *instruction)
661{
662 assert(isStore(*instruction));
663
664 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
665 {
666 return store->getData();
667 }
668
669 if(auto *storeSubVector = asStoreSubVector(instruction))
670 {
671 return storeSubVector->getSrc(1);
672 }
673
674 return nullptr;
675}
676
677std::size_t Optimizer::storeSize(const Ice::Inst *store)
678{
679 assert(isStore(*store));
680
681 if(auto *instStore = llvm::dyn_cast<Ice::InstStore>(store))
682 {
683 return Ice::typeWidthInBytes(instStore->getData()->getType());
684 }
685
686 if(auto *storeSubVector = asStoreSubVector(store))
687 {
688 return llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(3))->getValue();
689 }
690
691 return 0;
692}
693
694bool Optimizer::loadTypeMatchesStore(const Ice::Inst *load, const Ice::Inst *store)
695{
696 if(!load || !store)
697 {
698 return false;
699 }
700
701 assert(isLoad(*load) && isStore(*store));
702 assert(loadAddress(load) == storeAddress(store));
703
704 if(auto *instStore = llvm::dyn_cast<Ice::InstStore>(store))
705 {
706 if(auto *instLoad = llvm::dyn_cast<Ice::InstLoad>(load))
707 {
708 return instStore->getData()->getType() == instLoad->getDest()->getType();
709 }
710 }
711
712 if(auto *storeSubVector = asStoreSubVector(store))
713 {
714 if(auto *loadSubVector = asLoadSubVector(load))
715 {
716 // Check for matching type and sub-vector width.
717 return storeSubVector->getSrc(1)->getType() == loadSubVector->getDest()->getType() &&
718 llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(3))->getValue() ==
Ben Clayton713b8d32019-12-17 20:37:56 +0000719 llvm::cast<Ice::ConstantInteger32>(loadSubVector->getSrc(2))->getValue();
Nicolas Capens157ba262019-12-10 17:49:14 -0500720 }
721 }
722
723 return false;
724}
725
Ben Clayton713b8d32019-12-17 20:37:56 +0000726Optimizer::Uses *Optimizer::getUses(Ice::Operand *operand)
Nicolas Capens157ba262019-12-10 17:49:14 -0500727{
Ben Clayton713b8d32019-12-17 20:37:56 +0000728 Optimizer::Uses *uses = (Optimizer::Uses *)operand->Ice::Operand::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500729 if(!uses)
730 {
731 uses = new Optimizer::Uses;
732 setUses(operand, uses);
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500733 operandsWithUses.push_back(operand);
Nicolas Capens157ba262019-12-10 17:49:14 -0500734 }
735 return uses;
736}
737
Ben Clayton713b8d32019-12-17 20:37:56 +0000738void Optimizer::setUses(Ice::Operand *operand, Optimizer::Uses *uses)
Nicolas Capens157ba262019-12-10 17:49:14 -0500739{
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500740 if(auto *oldUses = reinterpret_cast<Optimizer::Uses *>(operand->Ice::Operand::getExternalData()))
741 {
742 delete oldUses;
743 }
744
Nicolas Capens157ba262019-12-10 17:49:14 -0500745 operand->Ice::Operand::setExternalData(uses);
746}
747
Ben Clayton713b8d32019-12-17 20:37:56 +0000748bool Optimizer::hasUses(Ice::Operand *operand) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500749{
750 return operand->Ice::Operand::getExternalData() != nullptr;
751}
752
Ben Clayton713b8d32019-12-17 20:37:56 +0000753Ice::CfgNode *Optimizer::getNode(Ice::Inst *inst)
Nicolas Capens157ba262019-12-10 17:49:14 -0500754{
Ben Clayton713b8d32019-12-17 20:37:56 +0000755 return (Ice::CfgNode *)inst->Ice::Inst::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500756}
757
Ben Clayton713b8d32019-12-17 20:37:56 +0000758void Optimizer::setNode(Ice::Inst *inst, Ice::CfgNode *node)
Nicolas Capens157ba262019-12-10 17:49:14 -0500759{
760 inst->Ice::Inst::setExternalData(node);
761}
762
Ben Clayton713b8d32019-12-17 20:37:56 +0000763Ice::Inst *Optimizer::getDefinition(Ice::Variable *var)
Nicolas Capens157ba262019-12-10 17:49:14 -0500764{
Ben Clayton713b8d32019-12-17 20:37:56 +0000765 return (Ice::Inst *)var->Ice::Variable::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500766}
767
Ben Clayton713b8d32019-12-17 20:37:56 +0000768void Optimizer::setDefinition(Ice::Variable *var, Ice::Inst *inst)
Nicolas Capens157ba262019-12-10 17:49:14 -0500769{
770 var->Ice::Variable::setExternalData(inst);
771}
772
Ben Clayton713b8d32019-12-17 20:37:56 +0000773const std::vector<Optimizer::LoadStoreInst> &Optimizer::getLoadStoreInsts(Ice::CfgNode *node)
Nicolas Capens157ba262019-12-10 17:49:14 -0500774{
Ben Clayton713b8d32019-12-17 20:37:56 +0000775 return *((const std::vector<LoadStoreInst> *)node->Ice::CfgNode::getExternalData());
Nicolas Capens157ba262019-12-10 17:49:14 -0500776}
777
Ben Clayton713b8d32019-12-17 20:37:56 +0000778void Optimizer::setLoadStoreInsts(Ice::CfgNode *node, std::vector<LoadStoreInst> *insts)
Nicolas Capens157ba262019-12-10 17:49:14 -0500779{
780 node->Ice::CfgNode::setExternalData(insts);
781}
782
Ben Clayton713b8d32019-12-17 20:37:56 +0000783bool Optimizer::hasLoadStoreInsts(Ice::CfgNode *node) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500784{
785 return node->Ice::CfgNode::getExternalData() != nullptr;
786}
787
788bool Optimizer::Uses::areOnlyLoadStore() const
789{
790 return size() == (loads.size() + stores.size());
791}
792
793void Optimizer::Uses::insert(Ice::Operand *value, Ice::Inst *instruction)
794{
795 push_back(instruction);
796
797 if(isLoad(*instruction))
798 {
799 if(value == loadAddress(instruction))
800 {
801 loads.push_back(instruction);
802 }
803 }
804 else if(isStore(*instruction))
805 {
806 if(value == storeAddress(instruction))
807 {
808 stores.push_back(instruction);
809 }
810 }
811}
812
813void Optimizer::Uses::erase(Ice::Inst *instruction)
814{
815 auto &uses = *this;
816
817 for(size_t i = 0; i < uses.size(); i++)
818 {
819 if(uses[i] == instruction)
820 {
821 uses[i] = back();
822 pop_back();
823
824 for(size_t i = 0; i < loads.size(); i++)
825 {
826 if(loads[i] == instruction)
827 {
828 loads[i] = loads.back();
829 loads.pop_back();
830 break;
831 }
832 }
833
834 for(size_t i = 0; i < stores.size(); i++)
835 {
836 if(stores[i] == instruction)
837 {
838 stores[i] = stores.back();
839 stores.pop_back();
840 break;
841 }
842 }
843
844 break;
845 }
846 }
847}
848
Ben Clayton713b8d32019-12-17 20:37:56 +0000849} // anonymous namespace
Nicolas Capens157ba262019-12-10 17:49:14 -0500850
851namespace rr {
852
853void optimize(Ice::Cfg *function)
854{
855 Optimizer optimizer;
856
857 optimizer.run(function);
858}
859
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500860} // namespace rr