blob: 8ec7af1bbe3c3eef0d86e2cb9a958dc5ce10cf54 [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:
Nicolas Capens54313fb2021-02-19 14:26:27 -050027 Optimizer(rr::Nucleus::OptimizerReport *report)
28 : report(report)
29 {
30 }
31
Nicolas Capens157ba262019-12-10 17:49:14 -050032 void run(Ice::Cfg *function);
33
34private:
35 void analyzeUses(Ice::Cfg *function);
Nicolas Capens0b506e12021-02-04 17:00:08 -050036
Nicolas Capens157ba262019-12-10 17:49:14 -050037 void eliminateDeadCode();
Nicolas Capens0b506e12021-02-04 17:00:08 -050038 void propagateAlloca();
Nicolas Capens157ba262019-12-10 17:49:14 -050039 void eliminateUnitializedLoads();
40 void eliminateLoadsFollowingSingleStore();
41 void optimizeStoresInSingleBasicBlock();
42
43 void replace(Ice::Inst *instruction, Ice::Operand *newValue);
44 void deleteInstruction(Ice::Inst *instruction);
45 bool isDead(Ice::Inst *instruction);
46
Nicolas Capens33a77f72021-02-08 15:04:38 -050047 static const Ice::InstIntrinsic *asLoadSubVector(const Ice::Inst *instruction);
48 static const Ice::InstIntrinsic *asStoreSubVector(const Ice::Inst *instruction);
Nicolas Capens157ba262019-12-10 17:49:14 -050049 static bool isLoad(const Ice::Inst &instruction);
50 static bool isStore(const Ice::Inst &instruction);
Nicolas Capens157ba262019-12-10 17:49:14 -050051 static std::size_t storeSize(const Ice::Inst *instruction);
52 static bool loadTypeMatchesStore(const Ice::Inst *load, const Ice::Inst *store);
53
Nicolas Capens54313fb2021-02-19 14:26:27 -050054 void collectDiagnostics();
55
Nicolas Capens157ba262019-12-10 17:49:14 -050056 Ice::Cfg *function;
57 Ice::GlobalContext *context;
58
Ben Clayton713b8d32019-12-17 20:37:56 +000059 struct Uses : std::vector<Ice::Inst *>
Nicolas Capens2ae9d742016-11-24 14:43:05 -050060 {
Nicolas Capens157ba262019-12-10 17:49:14 -050061 bool areOnlyLoadStore() const;
62 void insert(Ice::Operand *value, Ice::Inst *instruction);
63 void erase(Ice::Inst *instruction);
Nicolas Capens2ae9d742016-11-24 14:43:05 -050064
Ben Clayton713b8d32019-12-17 20:37:56 +000065 std::vector<Ice::Inst *> loads;
66 std::vector<Ice::Inst *> stores;
Nicolas Capens2ae9d742016-11-24 14:43:05 -050067 };
68
Nicolas Capens157ba262019-12-10 17:49:14 -050069 struct LoadStoreInst
Nicolas Capens2ae9d742016-11-24 14:43:05 -050070 {
Ben Clayton713b8d32019-12-17 20:37:56 +000071 LoadStoreInst(Ice::Inst *inst, bool isStore)
72 : inst(inst)
Nicolas Capens673a7fe2021-02-05 15:03:22 -050073 , address(isStore ? inst->getStoreAddress() : inst->getLoadAddress())
Ben Clayton713b8d32019-12-17 20:37:56 +000074 , isStore(isStore)
Alexis Hetu932640b2018-06-20 15:35:53 -040075 {
Alexis Hetu932640b2018-06-20 15:35:53 -040076 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -050077
Ben Clayton713b8d32019-12-17 20:37:56 +000078 Ice::Inst *inst;
Nicolas Capens157ba262019-12-10 17:49:14 -050079 Ice::Operand *address;
80 bool isStore;
81 };
82
Ben Clayton713b8d32019-12-17 20:37:56 +000083 Optimizer::Uses *getUses(Ice::Operand *);
84 void setUses(Ice::Operand *, Optimizer::Uses *);
85 bool hasUses(Ice::Operand *) const;
Nicolas Capens157ba262019-12-10 17:49:14 -050086
Ben Clayton713b8d32019-12-17 20:37:56 +000087 Ice::CfgNode *getNode(Ice::Inst *);
88 void setNode(Ice::Inst *, Ice::CfgNode *);
Nicolas Capens157ba262019-12-10 17:49:14 -050089
Ben Clayton713b8d32019-12-17 20:37:56 +000090 Ice::Inst *getDefinition(Ice::Variable *);
91 void setDefinition(Ice::Variable *, Ice::Inst *);
Nicolas Capens157ba262019-12-10 17:49:14 -050092
Ben Clayton713b8d32019-12-17 20:37:56 +000093 const std::vector<LoadStoreInst> &getLoadStoreInsts(Ice::CfgNode *);
94 void setLoadStoreInsts(Ice::CfgNode *, std::vector<LoadStoreInst> *);
95 bool hasLoadStoreInsts(Ice::CfgNode *node) const;
Nicolas Capens157ba262019-12-10 17:49:14 -050096
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -050097 std::vector<Ice::Operand *> operandsWithUses;
Nicolas Capens54313fb2021-02-19 14:26:27 -050098
99 rr::Nucleus::OptimizerReport *report = nullptr;
Nicolas Capens157ba262019-12-10 17:49:14 -0500100};
101
102void Optimizer::run(Ice::Cfg *function)
103{
104 this->function = function;
105 this->context = function->getContext();
106
107 analyzeUses(function);
108
Nicolas Capens0b506e12021-02-04 17:00:08 -0500109 // Start by eliminating any dead code, to avoid redundant work for the
110 // subsequent optimization passes.
Nicolas Capens157ba262019-12-10 17:49:14 -0500111 eliminateDeadCode();
Nicolas Capens0b506e12021-02-04 17:00:08 -0500112
113 // Eliminate allocas which store the address of other allocas.
114 propagateAlloca();
115
Nicolas Capens157ba262019-12-10 17:49:14 -0500116 eliminateUnitializedLoads();
117 eliminateLoadsFollowingSingleStore();
118 optimizeStoresInSingleBasicBlock();
119 eliminateDeadCode();
120
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500121 for(auto operand : operandsWithUses)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500122 {
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500123 // Deletes the Uses instance on the operand
124 setUses(operand, nullptr);
Nicolas Capens157ba262019-12-10 17:49:14 -0500125 }
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500126 operandsWithUses.clear();
Nicolas Capens54313fb2021-02-19 14:26:27 -0500127
128 collectDiagnostics();
Nicolas Capens157ba262019-12-10 17:49:14 -0500129}
130
Nicolas Capens0b506e12021-02-04 17:00:08 -0500131// Eliminates allocas which store the address of other allocas.
132void Optimizer::propagateAlloca()
133{
134 Ice::CfgNode *entryBlock = function->getEntryNode();
135 Ice::InstList &instList = entryBlock->getInsts();
136
137 for(Ice::Inst &inst : instList)
138 {
139 if(inst.isDeleted())
140 {
141 continue;
142 }
143
144 auto *alloca = llvm::dyn_cast<Ice::InstAlloca>(&inst);
145
146 if(!alloca)
147 {
148 break; // Allocas are all at the top
149 }
150
151 // Look for stores of this alloca's address.
152 Ice::Operand *address = alloca->getDest();
153 Uses uses = *getUses(address); // Hard copy
154
155 for(auto *store : uses)
156 {
157 if(isStore(*store) && store->getData() == address)
158 {
159 Ice::Operand *dest = store->getStoreAddress();
160 Ice::Variable *destVar = llvm::dyn_cast<Ice::Variable>(dest);
161 Ice::Inst *def = destVar ? getDefinition(destVar) : nullptr;
162
163 // If the address is stored into another stack variable, eliminate the latter.
164 if(def && def->getKind() == Ice::Inst::Alloca)
165 {
166 Uses destUses = *getUses(dest); // Hard copy
167
168 // Make sure the only store into the stack variable is this address, and that all of its other uses are loads.
169 // This prevents dynamic array loads/stores to be replaced by a scalar.
170 if((destUses.stores.size() == 1) && (destUses.loads.size() == destUses.size() - 1))
171 {
172 for(auto *load : destUses.loads)
173 {
174 replace(load, address);
175 }
176
177 // The address is now only stored, never loaded, so the store can be eliminated, together with its alloca.
178 assert(getUses(dest)->size() == 1);
179 deleteInstruction(store);
180 assert(def->isDeleted());
181 }
182 }
183 }
184 }
185 }
186}
187
Nicolas Capens157ba262019-12-10 17:49:14 -0500188void Optimizer::eliminateDeadCode()
189{
190 bool modified;
191 do
192 {
193 modified = false;
194 for(Ice::CfgNode *basicBlock : function->getNodes())
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500195 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500196 for(Ice::Inst &inst : Ice::reverse_range(basicBlock->getInsts()))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500197 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500198 if(inst.isDeleted())
199 {
200 continue;
201 }
202
203 if(isDead(&inst))
204 {
205 deleteInstruction(&inst);
206 modified = true;
207 }
208 }
209 }
Ben Clayton713b8d32019-12-17 20:37:56 +0000210 } while(modified);
Nicolas Capens157ba262019-12-10 17:49:14 -0500211}
212
213void Optimizer::eliminateUnitializedLoads()
214{
215 Ice::CfgNode *entryBlock = function->getEntryNode();
216
217 for(Ice::Inst &alloca : entryBlock->getInsts())
218 {
219 if(alloca.isDeleted())
220 {
221 continue;
222 }
223
224 if(!llvm::isa<Ice::InstAlloca>(alloca))
225 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000226 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500227 }
228
229 Ice::Operand *address = alloca.getDest();
230
231 if(!hasUses(address))
232 {
233 continue;
234 }
235
236 const auto &addressUses = *getUses(address);
237
238 if(!addressUses.areOnlyLoadStore())
239 {
240 continue;
241 }
242
243 if(addressUses.stores.empty())
244 {
245 for(Ice::Inst *load : addressUses.loads)
246 {
247 Ice::Variable *loadData = load->getDest();
248
249 if(hasUses(loadData))
250 {
251 for(Ice::Inst *use : *getUses(loadData))
252 {
253 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
254 {
255 if(use->getSrc(i) == loadData)
256 {
257 auto *undef = context->getConstantUndef(loadData->getType());
258
259 use->replaceSource(i, undef);
260 }
261 }
262 }
263
264 setUses(loadData, nullptr);
265 }
266
267 load->setDeleted();
268 }
269
270 alloca.setDeleted();
271 setUses(address, nullptr);
272 }
273 }
274}
275
276void Optimizer::eliminateLoadsFollowingSingleStore()
277{
278 Ice::CfgNode *entryBlock = function->getEntryNode();
279
280 for(Ice::Inst &alloca : entryBlock->getInsts())
281 {
282 if(alloca.isDeleted())
283 {
284 continue;
285 }
286
287 if(!llvm::isa<Ice::InstAlloca>(alloca))
288 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000289 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500290 }
291
292 Ice::Operand *address = alloca.getDest();
293
294 if(!hasUses(address))
295 {
296 continue;
297 }
298
299 auto &addressUses = *getUses(address);
300
301 if(!addressUses.areOnlyLoadStore())
302 {
303 continue;
304 }
305
306 if(addressUses.stores.size() == 1)
307 {
308 Ice::Inst *store = addressUses.stores[0];
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500309 Ice::Operand *storeValue = store->getData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500310
Nicolas Capens3ab17bd2021-02-10 16:41:31 -0500311 auto instIterator = store->getIterator();
312 auto basicBlockEnd = getNode(store)->getInsts().end();
313
314 while(++instIterator != basicBlockEnd)
Nicolas Capens157ba262019-12-10 17:49:14 -0500315 {
Nicolas Capens3ab17bd2021-02-10 16:41:31 -0500316 Ice::Inst *load = &*instIterator;
317
Nicolas Capens157ba262019-12-10 17:49:14 -0500318 if(load->isDeleted() || !isLoad(*load))
319 {
320 continue;
321 }
322
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500323 if(load->getLoadAddress() != address)
Nicolas Capens157ba262019-12-10 17:49:14 -0500324 {
325 continue;
326 }
327
328 if(!loadTypeMatchesStore(load, store))
329 {
330 continue;
331 }
332
333 replace(load, storeValue);
334
335 for(size_t i = 0; i < addressUses.loads.size(); i++)
336 {
337 if(addressUses.loads[i] == load)
338 {
339 addressUses.loads[i] = addressUses.loads.back();
340 addressUses.loads.pop_back();
341 break;
342 }
343 }
344
345 for(size_t i = 0; i < addressUses.size(); i++)
346 {
347 if(addressUses[i] == load)
348 {
349 addressUses[i] = addressUses.back();
350 addressUses.pop_back();
351 break;
352 }
353 }
354
355 if(addressUses.size() == 1)
356 {
357 assert(addressUses[0] == store);
358
359 alloca.setDeleted();
360 store->setDeleted();
361 setUses(address, nullptr);
362
363 if(hasUses(storeValue))
364 {
365 auto &valueUses = *getUses(storeValue);
366
367 for(size_t i = 0; i < valueUses.size(); i++)
368 {
369 if(valueUses[i] == store)
370 {
371 valueUses[i] = valueUses.back();
372 valueUses.pop_back();
373 break;
374 }
375 }
376
377 if(valueUses.empty())
378 {
379 setUses(storeValue, nullptr);
380 }
381 }
382
383 break;
384 }
385 }
386 }
387 }
388}
389
390void Optimizer::optimizeStoresInSingleBasicBlock()
391{
392 Ice::CfgNode *entryBlock = function->getEntryNode();
393
Ben Clayton713b8d32019-12-17 20:37:56 +0000394 std::vector<std::vector<LoadStoreInst> *> allocatedVectors;
Nicolas Capens157ba262019-12-10 17:49:14 -0500395
396 for(Ice::Inst &alloca : entryBlock->getInsts())
397 {
398 if(alloca.isDeleted())
399 {
400 continue;
401 }
402
403 if(!llvm::isa<Ice::InstAlloca>(alloca))
404 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000405 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500406 }
407
408 Ice::Operand *address = alloca.getDest();
409
410 if(!hasUses(address))
411 {
412 continue;
413 }
414
415 const auto &addressUses = *getUses(address);
416
417 if(!addressUses.areOnlyLoadStore())
418 {
419 continue;
420 }
421
422 Ice::CfgNode *singleBasicBlock = getNode(addressUses.stores[0]);
423
424 for(size_t i = 1; i < addressUses.stores.size(); i++)
425 {
426 Ice::Inst *store = addressUses.stores[i];
427 if(getNode(store) != singleBasicBlock)
428 {
429 singleBasicBlock = nullptr;
430 break;
431 }
432 }
433
434 if(singleBasicBlock)
435 {
436 if(!hasLoadStoreInsts(singleBasicBlock))
437 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000438 std::vector<LoadStoreInst> *loadStoreInstVector = new std::vector<LoadStoreInst>();
Nicolas Capens157ba262019-12-10 17:49:14 -0500439 setLoadStoreInsts(singleBasicBlock, loadStoreInstVector);
440 allocatedVectors.push_back(loadStoreInstVector);
441 for(Ice::Inst &inst : singleBasicBlock->getInsts())
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500442 {
443 if(inst.isDeleted())
444 {
445 continue;
446 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500447
Nicolas Capens157ba262019-12-10 17:49:14 -0500448 bool isStoreInst = isStore(inst);
449 bool isLoadInst = isLoad(inst);
450
451 if(isStoreInst || isLoadInst)
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500452 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500453 loadStoreInstVector->push_back(LoadStoreInst(&inst, isStoreInst));
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500454 }
455 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500456 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500457
Nicolas Capens157ba262019-12-10 17:49:14 -0500458 Ice::Inst *store = nullptr;
459 Ice::Operand *storeValue = nullptr;
460 bool unmatchedLoads = false;
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500461
Ben Clayton713b8d32019-12-17 20:37:56 +0000462 for(auto &loadStoreInst : getLoadStoreInsts(singleBasicBlock))
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500463 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000464 Ice::Inst *inst = loadStoreInst.inst;
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500465
Nicolas Capens157ba262019-12-10 17:49:14 -0500466 if((loadStoreInst.address != address) || inst->isDeleted())
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500467 {
468 continue;
469 }
470
Nicolas Capens157ba262019-12-10 17:49:14 -0500471 if(loadStoreInst.isStore)
Alexis Hetu932640b2018-06-20 15:35:53 -0400472 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500473 // New store found. If we had a previous one, try to eliminate it.
474 if(store && !unmatchedLoads)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500475 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500476 // If the previous store is wider than the new one, we can't eliminate it
477 // because there could be a wide load reading its non-overwritten data.
478 if(storeSize(inst) >= storeSize(store))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500479 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500480 deleteInstruction(store);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500481 }
482 }
483
Nicolas Capens157ba262019-12-10 17:49:14 -0500484 store = inst;
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500485 storeValue = store->getData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500486 unmatchedLoads = false;
487 }
488 else
489 {
490 if(!loadTypeMatchesStore(inst, store))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500491 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500492 unmatchedLoads = true;
493 continue;
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500494 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500495
496 replace(inst, storeValue);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500497 }
498 }
499 }
500 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500501
Nicolas Capens157ba262019-12-10 17:49:14 -0500502 for(auto loadStoreInstVector : allocatedVectors)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500503 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500504 delete loadStoreInstVector;
505 }
506}
Nicolas Capense205c3d2016-11-30 15:14:28 -0500507
Nicolas Capens157ba262019-12-10 17:49:14 -0500508void Optimizer::analyzeUses(Ice::Cfg *function)
509{
510 for(Ice::CfgNode *basicBlock : function->getNodes())
511 {
512 for(Ice::Inst &instruction : basicBlock->getInsts())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500513 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500514 if(instruction.isDeleted())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500515 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500516 continue;
517 }
Alexis Hetu932640b2018-06-20 15:35:53 -0400518
Nicolas Capens157ba262019-12-10 17:49:14 -0500519 setNode(&instruction, basicBlock);
520 if(instruction.getDest())
521 {
522 setDefinition(instruction.getDest(), &instruction);
523 }
524
525 for(Ice::SizeT i = 0; i < instruction.getSrcSize(); i++)
526 {
527 Ice::SizeT unique = 0;
528 for(; unique < i; unique++)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500529 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500530 if(instruction.getSrc(i) == instruction.getSrc(unique))
Alexis Hetu932640b2018-06-20 15:35:53 -0400531 {
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500532 break;
533 }
534 }
535
Nicolas Capens157ba262019-12-10 17:49:14 -0500536 if(i == unique)
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500537 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500538 Ice::Operand *src = instruction.getSrc(i);
539 getUses(src)->insert(src, &instruction);
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500540 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500541 }
542 }
543 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500544}
545
Nicolas Capens157ba262019-12-10 17:49:14 -0500546void Optimizer::replace(Ice::Inst *instruction, Ice::Operand *newValue)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500547{
Nicolas Capens157ba262019-12-10 17:49:14 -0500548 Ice::Variable *oldValue = instruction->getDest();
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500549
Nicolas Capens157ba262019-12-10 17:49:14 -0500550 if(!newValue)
551 {
552 newValue = context->getConstantUndef(oldValue->getType());
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500553 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500554
555 if(hasUses(oldValue))
556 {
557 for(Ice::Inst *use : *getUses(oldValue))
558 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000559 assert(!use->isDeleted()); // Should have been removed from uses already
Nicolas Capens157ba262019-12-10 17:49:14 -0500560
561 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
562 {
563 if(use->getSrc(i) == oldValue)
564 {
565 use->replaceSource(i, newValue);
566 }
567 }
568
569 getUses(newValue)->insert(newValue, use);
570 }
571
572 setUses(oldValue, nullptr);
573 }
574
575 deleteInstruction(instruction);
576}
577
578void Optimizer::deleteInstruction(Ice::Inst *instruction)
579{
580 if(!instruction || instruction->isDeleted())
581 {
582 return;
583 }
584
585 instruction->setDeleted();
586
587 for(Ice::SizeT i = 0; i < instruction->getSrcSize(); i++)
588 {
589 Ice::Operand *src = instruction->getSrc(i);
590
591 if(hasUses(src))
592 {
593 auto &srcUses = *getUses(src);
594
595 srcUses.erase(instruction);
596
597 if(srcUses.empty())
598 {
599 setUses(src, nullptr);
600
601 if(Ice::Variable *var = llvm::dyn_cast<Ice::Variable>(src))
602 {
603 deleteInstruction(getDefinition(var));
604 }
605 }
606 }
607 }
608}
609
610bool Optimizer::isDead(Ice::Inst *instruction)
611{
612 Ice::Variable *dest = instruction->getDest();
613
614 if(dest)
615 {
616 return (!hasUses(dest) || getUses(dest)->empty()) && !instruction->hasSideEffects();
617 }
618 else if(isStore(*instruction))
619 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500620 if(Ice::Variable *address = llvm::dyn_cast<Ice::Variable>(instruction->getStoreAddress()))
Nicolas Capens157ba262019-12-10 17:49:14 -0500621 {
622 Ice::Inst *def = getDefinition(address);
623
624 if(def && llvm::isa<Ice::InstAlloca>(def))
625 {
626 if(hasUses(address))
627 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000628 Optimizer::Uses *uses = getUses(address);
629 return uses->size() == uses->stores.size(); // Dead if all uses are stores
Nicolas Capens157ba262019-12-10 17:49:14 -0500630 }
631 else
632 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000633 return true; // No uses
Nicolas Capens157ba262019-12-10 17:49:14 -0500634 }
635 }
636 }
637 }
638
639 return false;
640}
641
Nicolas Capens33a77f72021-02-08 15:04:38 -0500642const Ice::InstIntrinsic *Optimizer::asLoadSubVector(const Ice::Inst *instruction)
Nicolas Capens157ba262019-12-10 17:49:14 -0500643{
Nicolas Capens33a77f72021-02-08 15:04:38 -0500644 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsic>(instruction))
Nicolas Capens157ba262019-12-10 17:49:14 -0500645 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500646 if(instrinsic->getIntrinsicID() == Ice::Intrinsics::LoadSubVector)
Nicolas Capens157ba262019-12-10 17:49:14 -0500647 {
648 return instrinsic;
649 }
650 }
651
652 return nullptr;
653}
654
Nicolas Capens33a77f72021-02-08 15:04:38 -0500655const Ice::InstIntrinsic *Optimizer::asStoreSubVector(const Ice::Inst *instruction)
Nicolas Capens157ba262019-12-10 17:49:14 -0500656{
Nicolas Capens33a77f72021-02-08 15:04:38 -0500657 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsic>(instruction))
Nicolas Capens157ba262019-12-10 17:49:14 -0500658 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500659 if(instrinsic->getIntrinsicID() == Ice::Intrinsics::StoreSubVector)
Nicolas Capens157ba262019-12-10 17:49:14 -0500660 {
661 return instrinsic;
662 }
663 }
664
665 return nullptr;
666}
667
668bool Optimizer::isLoad(const Ice::Inst &instruction)
669{
670 if(llvm::isa<Ice::InstLoad>(&instruction))
671 {
672 return true;
673 }
674
675 return asLoadSubVector(&instruction) != nullptr;
676}
677
678bool Optimizer::isStore(const Ice::Inst &instruction)
679{
680 if(llvm::isa<Ice::InstStore>(&instruction))
681 {
682 return true;
683 }
684
685 return asStoreSubVector(&instruction) != nullptr;
686}
687
Nicolas Capens157ba262019-12-10 17:49:14 -0500688std::size_t Optimizer::storeSize(const Ice::Inst *store)
689{
690 assert(isStore(*store));
691
692 if(auto *instStore = llvm::dyn_cast<Ice::InstStore>(store))
693 {
694 return Ice::typeWidthInBytes(instStore->getData()->getType());
695 }
696
697 if(auto *storeSubVector = asStoreSubVector(store))
698 {
699 return llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(3))->getValue();
700 }
701
702 return 0;
703}
704
705bool Optimizer::loadTypeMatchesStore(const Ice::Inst *load, const Ice::Inst *store)
706{
707 if(!load || !store)
708 {
709 return false;
710 }
711
712 assert(isLoad(*load) && isStore(*store));
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500713 assert(load->getLoadAddress() == store->getStoreAddress());
Nicolas Capens157ba262019-12-10 17:49:14 -0500714
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500715 if(store->getData()->getType() != load->getDest()->getType())
Nicolas Capens157ba262019-12-10 17:49:14 -0500716 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500717 return false;
Nicolas Capens157ba262019-12-10 17:49:14 -0500718 }
719
720 if(auto *storeSubVector = asStoreSubVector(store))
721 {
722 if(auto *loadSubVector = asLoadSubVector(load))
723 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500724 // Check for matching sub-vector width.
725 return llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(2))->getValue() ==
726 llvm::cast<Ice::ConstantInteger32>(loadSubVector->getSrc(1))->getValue();
Nicolas Capens157ba262019-12-10 17:49:14 -0500727 }
728 }
729
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500730 return true;
Nicolas Capens157ba262019-12-10 17:49:14 -0500731}
732
Nicolas Capens54313fb2021-02-19 14:26:27 -0500733void Optimizer::collectDiagnostics()
734{
735 if(report)
736 {
737 *report = {};
738
739 for(auto *basicBlock : function->getNodes())
740 {
741 for(auto &inst : basicBlock->getInsts())
742 {
743 if(inst.isDeleted())
744 {
745 continue;
746 }
747
748 if(llvm::isa<Ice::InstAlloca>(inst))
749 {
750 report->allocas++;
751 }
752 else if(isLoad(inst))
753 {
754 report->loads++;
755 }
756 else if(isStore(inst))
757 {
758 report->stores++;
759 }
760 }
761 }
762 }
763}
764
Ben Clayton713b8d32019-12-17 20:37:56 +0000765Optimizer::Uses *Optimizer::getUses(Ice::Operand *operand)
Nicolas Capens157ba262019-12-10 17:49:14 -0500766{
Ben Clayton713b8d32019-12-17 20:37:56 +0000767 Optimizer::Uses *uses = (Optimizer::Uses *)operand->Ice::Operand::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500768 if(!uses)
769 {
770 uses = new Optimizer::Uses;
771 setUses(operand, uses);
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500772 operandsWithUses.push_back(operand);
Nicolas Capens157ba262019-12-10 17:49:14 -0500773 }
774 return uses;
775}
776
Ben Clayton713b8d32019-12-17 20:37:56 +0000777void Optimizer::setUses(Ice::Operand *operand, Optimizer::Uses *uses)
Nicolas Capens157ba262019-12-10 17:49:14 -0500778{
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500779 if(auto *oldUses = reinterpret_cast<Optimizer::Uses *>(operand->Ice::Operand::getExternalData()))
780 {
781 delete oldUses;
782 }
783
Nicolas Capens157ba262019-12-10 17:49:14 -0500784 operand->Ice::Operand::setExternalData(uses);
785}
786
Ben Clayton713b8d32019-12-17 20:37:56 +0000787bool Optimizer::hasUses(Ice::Operand *operand) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500788{
789 return operand->Ice::Operand::getExternalData() != nullptr;
790}
791
Ben Clayton713b8d32019-12-17 20:37:56 +0000792Ice::CfgNode *Optimizer::getNode(Ice::Inst *inst)
Nicolas Capens157ba262019-12-10 17:49:14 -0500793{
Ben Clayton713b8d32019-12-17 20:37:56 +0000794 return (Ice::CfgNode *)inst->Ice::Inst::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500795}
796
Ben Clayton713b8d32019-12-17 20:37:56 +0000797void Optimizer::setNode(Ice::Inst *inst, Ice::CfgNode *node)
Nicolas Capens157ba262019-12-10 17:49:14 -0500798{
799 inst->Ice::Inst::setExternalData(node);
800}
801
Ben Clayton713b8d32019-12-17 20:37:56 +0000802Ice::Inst *Optimizer::getDefinition(Ice::Variable *var)
Nicolas Capens157ba262019-12-10 17:49:14 -0500803{
Ben Clayton713b8d32019-12-17 20:37:56 +0000804 return (Ice::Inst *)var->Ice::Variable::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500805}
806
Ben Clayton713b8d32019-12-17 20:37:56 +0000807void Optimizer::setDefinition(Ice::Variable *var, Ice::Inst *inst)
Nicolas Capens157ba262019-12-10 17:49:14 -0500808{
809 var->Ice::Variable::setExternalData(inst);
810}
811
Ben Clayton713b8d32019-12-17 20:37:56 +0000812const std::vector<Optimizer::LoadStoreInst> &Optimizer::getLoadStoreInsts(Ice::CfgNode *node)
Nicolas Capens157ba262019-12-10 17:49:14 -0500813{
Ben Clayton713b8d32019-12-17 20:37:56 +0000814 return *((const std::vector<LoadStoreInst> *)node->Ice::CfgNode::getExternalData());
Nicolas Capens157ba262019-12-10 17:49:14 -0500815}
816
Ben Clayton713b8d32019-12-17 20:37:56 +0000817void Optimizer::setLoadStoreInsts(Ice::CfgNode *node, std::vector<LoadStoreInst> *insts)
Nicolas Capens157ba262019-12-10 17:49:14 -0500818{
819 node->Ice::CfgNode::setExternalData(insts);
820}
821
Ben Clayton713b8d32019-12-17 20:37:56 +0000822bool Optimizer::hasLoadStoreInsts(Ice::CfgNode *node) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500823{
824 return node->Ice::CfgNode::getExternalData() != nullptr;
825}
826
827bool Optimizer::Uses::areOnlyLoadStore() const
828{
829 return size() == (loads.size() + stores.size());
830}
831
832void Optimizer::Uses::insert(Ice::Operand *value, Ice::Inst *instruction)
833{
834 push_back(instruction);
835
836 if(isLoad(*instruction))
837 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500838 if(value == instruction->getLoadAddress())
Nicolas Capens157ba262019-12-10 17:49:14 -0500839 {
840 loads.push_back(instruction);
841 }
842 }
843 else if(isStore(*instruction))
844 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500845 if(value == instruction->getStoreAddress())
Nicolas Capens157ba262019-12-10 17:49:14 -0500846 {
847 stores.push_back(instruction);
848 }
849 }
850}
851
852void Optimizer::Uses::erase(Ice::Inst *instruction)
853{
854 auto &uses = *this;
855
856 for(size_t i = 0; i < uses.size(); i++)
857 {
858 if(uses[i] == instruction)
859 {
860 uses[i] = back();
861 pop_back();
862
863 for(size_t i = 0; i < loads.size(); i++)
864 {
865 if(loads[i] == instruction)
866 {
867 loads[i] = loads.back();
868 loads.pop_back();
869 break;
870 }
871 }
872
873 for(size_t i = 0; i < stores.size(); i++)
874 {
875 if(stores[i] == instruction)
876 {
877 stores[i] = stores.back();
878 stores.pop_back();
879 break;
880 }
881 }
882
883 break;
884 }
885 }
886}
887
Ben Clayton713b8d32019-12-17 20:37:56 +0000888} // anonymous namespace
Nicolas Capens157ba262019-12-10 17:49:14 -0500889
890namespace rr {
891
Nicolas Capens54313fb2021-02-19 14:26:27 -0500892void optimize(Ice::Cfg *function, Nucleus::OptimizerReport *report)
Nicolas Capens157ba262019-12-10 17:49:14 -0500893{
Nicolas Capens54313fb2021-02-19 14:26:27 -0500894 Optimizer optimizer(report);
Nicolas Capens157ba262019-12-10 17:49:14 -0500895
896 optimizer.run(function);
897}
898
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500899} // namespace rr