blob: 5e73519a399847f9978f583a90cf162aac26d412 [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 {
Antonio Maiorano5ff1de52020-03-03 19:53:13 -0500431 unmatchedLoads = true;
Antonio Maioranob3d9a2a2020-02-14 14:38:04 -0500432 continue;
433 }
434
Nicolas Capens157ba262019-12-10 17:49:14 -0500435 replace(inst, storeValue);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500436 }
437 }
438 }
439 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500440
Nicolas Capens157ba262019-12-10 17:49:14 -0500441 for(auto loadStoreInstVector : allocatedVectors)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500442 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500443 delete loadStoreInstVector;
444 }
445}
Nicolas Capense205c3d2016-11-30 15:14:28 -0500446
Nicolas Capens157ba262019-12-10 17:49:14 -0500447void Optimizer::analyzeUses(Ice::Cfg *function)
448{
449 for(Ice::CfgNode *basicBlock : function->getNodes())
450 {
451 for(Ice::Inst &instruction : basicBlock->getInsts())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500452 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500453 if(instruction.isDeleted())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500454 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500455 continue;
456 }
Alexis Hetu932640b2018-06-20 15:35:53 -0400457
Nicolas Capens157ba262019-12-10 17:49:14 -0500458 setNode(&instruction, basicBlock);
459 if(instruction.getDest())
460 {
461 setDefinition(instruction.getDest(), &instruction);
462 }
463
464 for(Ice::SizeT i = 0; i < instruction.getSrcSize(); i++)
465 {
466 Ice::SizeT unique = 0;
467 for(; unique < i; unique++)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500468 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500469 if(instruction.getSrc(i) == instruction.getSrc(unique))
Alexis Hetu932640b2018-06-20 15:35:53 -0400470 {
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500471 break;
472 }
473 }
474
Nicolas Capens157ba262019-12-10 17:49:14 -0500475 if(i == unique)
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500476 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500477 Ice::Operand *src = instruction.getSrc(i);
478 getUses(src)->insert(src, &instruction);
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500479 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500480 }
481 }
482 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500483}
484
Nicolas Capens157ba262019-12-10 17:49:14 -0500485void Optimizer::replace(Ice::Inst *instruction, Ice::Operand *newValue)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500486{
Nicolas Capens157ba262019-12-10 17:49:14 -0500487 Ice::Variable *oldValue = instruction->getDest();
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500488
Nicolas Capens157ba262019-12-10 17:49:14 -0500489 if(!newValue)
490 {
491 newValue = context->getConstantUndef(oldValue->getType());
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500492 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500493
494 if(hasUses(oldValue))
495 {
496 for(Ice::Inst *use : *getUses(oldValue))
497 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000498 assert(!use->isDeleted()); // Should have been removed from uses already
Nicolas Capens157ba262019-12-10 17:49:14 -0500499
500 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
501 {
502 if(use->getSrc(i) == oldValue)
503 {
504 use->replaceSource(i, newValue);
505 }
506 }
507
508 getUses(newValue)->insert(newValue, use);
509 }
510
511 setUses(oldValue, nullptr);
512 }
513
514 deleteInstruction(instruction);
515}
516
517void Optimizer::deleteInstruction(Ice::Inst *instruction)
518{
519 if(!instruction || instruction->isDeleted())
520 {
521 return;
522 }
523
524 instruction->setDeleted();
525
526 for(Ice::SizeT i = 0; i < instruction->getSrcSize(); i++)
527 {
528 Ice::Operand *src = instruction->getSrc(i);
529
530 if(hasUses(src))
531 {
532 auto &srcUses = *getUses(src);
533
534 srcUses.erase(instruction);
535
536 if(srcUses.empty())
537 {
538 setUses(src, nullptr);
539
540 if(Ice::Variable *var = llvm::dyn_cast<Ice::Variable>(src))
541 {
542 deleteInstruction(getDefinition(var));
543 }
544 }
545 }
546 }
547}
548
549bool Optimizer::isDead(Ice::Inst *instruction)
550{
551 Ice::Variable *dest = instruction->getDest();
552
553 if(dest)
554 {
555 return (!hasUses(dest) || getUses(dest)->empty()) && !instruction->hasSideEffects();
556 }
557 else if(isStore(*instruction))
558 {
559 if(Ice::Variable *address = llvm::dyn_cast<Ice::Variable>(storeAddress(instruction)))
560 {
561 Ice::Inst *def = getDefinition(address);
562
563 if(def && llvm::isa<Ice::InstAlloca>(def))
564 {
565 if(hasUses(address))
566 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000567 Optimizer::Uses *uses = getUses(address);
568 return uses->size() == uses->stores.size(); // Dead if all uses are stores
Nicolas Capens157ba262019-12-10 17:49:14 -0500569 }
570 else
571 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000572 return true; // No uses
Nicolas Capens157ba262019-12-10 17:49:14 -0500573 }
574 }
575 }
576 }
577
578 return false;
579}
580
581const Ice::InstIntrinsicCall *Optimizer::asLoadSubVector(const Ice::Inst *instruction)
582{
583 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
584 {
585 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector)
586 {
587 return instrinsic;
588 }
589 }
590
591 return nullptr;
592}
593
594const Ice::InstIntrinsicCall *Optimizer::asStoreSubVector(const Ice::Inst *instruction)
595{
596 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
597 {
598 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector)
599 {
600 return instrinsic;
601 }
602 }
603
604 return nullptr;
605}
606
607bool Optimizer::isLoad(const Ice::Inst &instruction)
608{
609 if(llvm::isa<Ice::InstLoad>(&instruction))
610 {
611 return true;
612 }
613
614 return asLoadSubVector(&instruction) != nullptr;
615}
616
617bool Optimizer::isStore(const Ice::Inst &instruction)
618{
619 if(llvm::isa<Ice::InstStore>(&instruction))
620 {
621 return true;
622 }
623
624 return asStoreSubVector(&instruction) != nullptr;
625}
626
627Ice::Operand *Optimizer::storeAddress(const Ice::Inst *instruction)
628{
629 assert(isStore(*instruction));
630
631 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
632 {
633 return store->getAddr();
634 }
635
636 if(auto *storeSubVector = asStoreSubVector(instruction))
637 {
638 return storeSubVector->getSrc(2);
639 }
640
641 return nullptr;
642}
643
644Ice::Operand *Optimizer::loadAddress(const Ice::Inst *instruction)
645{
646 assert(isLoad(*instruction));
647
648 if(auto *load = llvm::dyn_cast<Ice::InstLoad>(instruction))
649 {
650 return load->getSourceAddress();
651 }
652
653 if(auto *loadSubVector = asLoadSubVector(instruction))
654 {
655 return loadSubVector->getSrc(1);
656 }
657
658 return nullptr;
659}
660
661Ice::Operand *Optimizer::storeData(const Ice::Inst *instruction)
662{
663 assert(isStore(*instruction));
664
665 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
666 {
667 return store->getData();
668 }
669
670 if(auto *storeSubVector = asStoreSubVector(instruction))
671 {
672 return storeSubVector->getSrc(1);
673 }
674
675 return nullptr;
676}
677
678std::size_t Optimizer::storeSize(const Ice::Inst *store)
679{
680 assert(isStore(*store));
681
682 if(auto *instStore = llvm::dyn_cast<Ice::InstStore>(store))
683 {
684 return Ice::typeWidthInBytes(instStore->getData()->getType());
685 }
686
687 if(auto *storeSubVector = asStoreSubVector(store))
688 {
689 return llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(3))->getValue();
690 }
691
692 return 0;
693}
694
695bool Optimizer::loadTypeMatchesStore(const Ice::Inst *load, const Ice::Inst *store)
696{
697 if(!load || !store)
698 {
699 return false;
700 }
701
702 assert(isLoad(*load) && isStore(*store));
703 assert(loadAddress(load) == storeAddress(store));
704
705 if(auto *instStore = llvm::dyn_cast<Ice::InstStore>(store))
706 {
707 if(auto *instLoad = llvm::dyn_cast<Ice::InstLoad>(load))
708 {
709 return instStore->getData()->getType() == instLoad->getDest()->getType();
710 }
711 }
712
713 if(auto *storeSubVector = asStoreSubVector(store))
714 {
715 if(auto *loadSubVector = asLoadSubVector(load))
716 {
717 // Check for matching type and sub-vector width.
718 return storeSubVector->getSrc(1)->getType() == loadSubVector->getDest()->getType() &&
719 llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(3))->getValue() ==
Ben Clayton713b8d32019-12-17 20:37:56 +0000720 llvm::cast<Ice::ConstantInteger32>(loadSubVector->getSrc(2))->getValue();
Nicolas Capens157ba262019-12-10 17:49:14 -0500721 }
722 }
723
724 return false;
725}
726
Ben Clayton713b8d32019-12-17 20:37:56 +0000727Optimizer::Uses *Optimizer::getUses(Ice::Operand *operand)
Nicolas Capens157ba262019-12-10 17:49:14 -0500728{
Ben Clayton713b8d32019-12-17 20:37:56 +0000729 Optimizer::Uses *uses = (Optimizer::Uses *)operand->Ice::Operand::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500730 if(!uses)
731 {
732 uses = new Optimizer::Uses;
733 setUses(operand, uses);
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500734 operandsWithUses.push_back(operand);
Nicolas Capens157ba262019-12-10 17:49:14 -0500735 }
736 return uses;
737}
738
Ben Clayton713b8d32019-12-17 20:37:56 +0000739void Optimizer::setUses(Ice::Operand *operand, Optimizer::Uses *uses)
Nicolas Capens157ba262019-12-10 17:49:14 -0500740{
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500741 if(auto *oldUses = reinterpret_cast<Optimizer::Uses *>(operand->Ice::Operand::getExternalData()))
742 {
743 delete oldUses;
744 }
745
Nicolas Capens157ba262019-12-10 17:49:14 -0500746 operand->Ice::Operand::setExternalData(uses);
747}
748
Ben Clayton713b8d32019-12-17 20:37:56 +0000749bool Optimizer::hasUses(Ice::Operand *operand) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500750{
751 return operand->Ice::Operand::getExternalData() != nullptr;
752}
753
Ben Clayton713b8d32019-12-17 20:37:56 +0000754Ice::CfgNode *Optimizer::getNode(Ice::Inst *inst)
Nicolas Capens157ba262019-12-10 17:49:14 -0500755{
Ben Clayton713b8d32019-12-17 20:37:56 +0000756 return (Ice::CfgNode *)inst->Ice::Inst::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500757}
758
Ben Clayton713b8d32019-12-17 20:37:56 +0000759void Optimizer::setNode(Ice::Inst *inst, Ice::CfgNode *node)
Nicolas Capens157ba262019-12-10 17:49:14 -0500760{
761 inst->Ice::Inst::setExternalData(node);
762}
763
Ben Clayton713b8d32019-12-17 20:37:56 +0000764Ice::Inst *Optimizer::getDefinition(Ice::Variable *var)
Nicolas Capens157ba262019-12-10 17:49:14 -0500765{
Ben Clayton713b8d32019-12-17 20:37:56 +0000766 return (Ice::Inst *)var->Ice::Variable::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500767}
768
Ben Clayton713b8d32019-12-17 20:37:56 +0000769void Optimizer::setDefinition(Ice::Variable *var, Ice::Inst *inst)
Nicolas Capens157ba262019-12-10 17:49:14 -0500770{
771 var->Ice::Variable::setExternalData(inst);
772}
773
Ben Clayton713b8d32019-12-17 20:37:56 +0000774const std::vector<Optimizer::LoadStoreInst> &Optimizer::getLoadStoreInsts(Ice::CfgNode *node)
Nicolas Capens157ba262019-12-10 17:49:14 -0500775{
Ben Clayton713b8d32019-12-17 20:37:56 +0000776 return *((const std::vector<LoadStoreInst> *)node->Ice::CfgNode::getExternalData());
Nicolas Capens157ba262019-12-10 17:49:14 -0500777}
778
Ben Clayton713b8d32019-12-17 20:37:56 +0000779void Optimizer::setLoadStoreInsts(Ice::CfgNode *node, std::vector<LoadStoreInst> *insts)
Nicolas Capens157ba262019-12-10 17:49:14 -0500780{
781 node->Ice::CfgNode::setExternalData(insts);
782}
783
Ben Clayton713b8d32019-12-17 20:37:56 +0000784bool Optimizer::hasLoadStoreInsts(Ice::CfgNode *node) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500785{
786 return node->Ice::CfgNode::getExternalData() != nullptr;
787}
788
789bool Optimizer::Uses::areOnlyLoadStore() const
790{
791 return size() == (loads.size() + stores.size());
792}
793
794void Optimizer::Uses::insert(Ice::Operand *value, Ice::Inst *instruction)
795{
796 push_back(instruction);
797
798 if(isLoad(*instruction))
799 {
800 if(value == loadAddress(instruction))
801 {
802 loads.push_back(instruction);
803 }
804 }
805 else if(isStore(*instruction))
806 {
807 if(value == storeAddress(instruction))
808 {
809 stores.push_back(instruction);
810 }
811 }
812}
813
814void Optimizer::Uses::erase(Ice::Inst *instruction)
815{
816 auto &uses = *this;
817
818 for(size_t i = 0; i < uses.size(); i++)
819 {
820 if(uses[i] == instruction)
821 {
822 uses[i] = back();
823 pop_back();
824
825 for(size_t i = 0; i < loads.size(); i++)
826 {
827 if(loads[i] == instruction)
828 {
829 loads[i] = loads.back();
830 loads.pop_back();
831 break;
832 }
833 }
834
835 for(size_t i = 0; i < stores.size(); i++)
836 {
837 if(stores[i] == instruction)
838 {
839 stores[i] = stores.back();
840 stores.pop_back();
841 break;
842 }
843 }
844
845 break;
846 }
847 }
848}
849
Ben Clayton713b8d32019-12-17 20:37:56 +0000850} // anonymous namespace
Nicolas Capens157ba262019-12-10 17:49:14 -0500851
852namespace rr {
853
854void optimize(Ice::Cfg *function)
855{
856 Optimizer optimizer;
857
858 optimizer.run(function);
859}
860
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500861} // namespace rr