blob: a3901d7e36cc1b7e328237b2ebb871ece63f278c [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);
Nicolas Capens0b506e12021-02-04 17:00:08 -050031
Nicolas Capens157ba262019-12-10 17:49:14 -050032 void eliminateDeadCode();
Nicolas Capens0b506e12021-02-04 17:00:08 -050033 void propagateAlloca();
Nicolas Capens157ba262019-12-10 17:49:14 -050034 void eliminateUnitializedLoads();
35 void eliminateLoadsFollowingSingleStore();
36 void optimizeStoresInSingleBasicBlock();
37
38 void replace(Ice::Inst *instruction, Ice::Operand *newValue);
39 void deleteInstruction(Ice::Inst *instruction);
40 bool isDead(Ice::Inst *instruction);
41
Nicolas Capens33a77f72021-02-08 15:04:38 -050042 static const Ice::InstIntrinsic *asLoadSubVector(const Ice::Inst *instruction);
43 static const Ice::InstIntrinsic *asStoreSubVector(const Ice::Inst *instruction);
Nicolas Capens157ba262019-12-10 17:49:14 -050044 static bool isLoad(const Ice::Inst &instruction);
45 static bool isStore(const Ice::Inst &instruction);
Nicolas Capens157ba262019-12-10 17:49:14 -050046 static std::size_t storeSize(const Ice::Inst *instruction);
47 static bool loadTypeMatchesStore(const Ice::Inst *load, const Ice::Inst *store);
48
49 Ice::Cfg *function;
50 Ice::GlobalContext *context;
51
Ben Clayton713b8d32019-12-17 20:37:56 +000052 struct Uses : std::vector<Ice::Inst *>
Nicolas Capens2ae9d742016-11-24 14:43:05 -050053 {
Nicolas Capens157ba262019-12-10 17:49:14 -050054 bool areOnlyLoadStore() const;
55 void insert(Ice::Operand *value, Ice::Inst *instruction);
56 void erase(Ice::Inst *instruction);
Nicolas Capens2ae9d742016-11-24 14:43:05 -050057
Ben Clayton713b8d32019-12-17 20:37:56 +000058 std::vector<Ice::Inst *> loads;
59 std::vector<Ice::Inst *> stores;
Nicolas Capens2ae9d742016-11-24 14:43:05 -050060 };
61
Nicolas Capens157ba262019-12-10 17:49:14 -050062 struct LoadStoreInst
Nicolas Capens2ae9d742016-11-24 14:43:05 -050063 {
Ben Clayton713b8d32019-12-17 20:37:56 +000064 LoadStoreInst(Ice::Inst *inst, bool isStore)
65 : inst(inst)
Nicolas Capens673a7fe2021-02-05 15:03:22 -050066 , address(isStore ? inst->getStoreAddress() : inst->getLoadAddress())
Ben Clayton713b8d32019-12-17 20:37:56 +000067 , isStore(isStore)
Alexis Hetu932640b2018-06-20 15:35:53 -040068 {
Alexis Hetu932640b2018-06-20 15:35:53 -040069 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -050070
Ben Clayton713b8d32019-12-17 20:37:56 +000071 Ice::Inst *inst;
Nicolas Capens157ba262019-12-10 17:49:14 -050072 Ice::Operand *address;
73 bool isStore;
74 };
75
Ben Clayton713b8d32019-12-17 20:37:56 +000076 Optimizer::Uses *getUses(Ice::Operand *);
77 void setUses(Ice::Operand *, Optimizer::Uses *);
78 bool hasUses(Ice::Operand *) const;
Nicolas Capens157ba262019-12-10 17:49:14 -050079
Ben Clayton713b8d32019-12-17 20:37:56 +000080 Ice::CfgNode *getNode(Ice::Inst *);
81 void setNode(Ice::Inst *, Ice::CfgNode *);
Nicolas Capens157ba262019-12-10 17:49:14 -050082
Ben Clayton713b8d32019-12-17 20:37:56 +000083 Ice::Inst *getDefinition(Ice::Variable *);
84 void setDefinition(Ice::Variable *, Ice::Inst *);
Nicolas Capens157ba262019-12-10 17:49:14 -050085
Ben Clayton713b8d32019-12-17 20:37:56 +000086 const std::vector<LoadStoreInst> &getLoadStoreInsts(Ice::CfgNode *);
87 void setLoadStoreInsts(Ice::CfgNode *, std::vector<LoadStoreInst> *);
88 bool hasLoadStoreInsts(Ice::CfgNode *node) const;
Nicolas Capens157ba262019-12-10 17:49:14 -050089
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -050090 std::vector<Ice::Operand *> operandsWithUses;
Nicolas Capens157ba262019-12-10 17:49:14 -050091};
92
93void Optimizer::run(Ice::Cfg *function)
94{
95 this->function = function;
96 this->context = function->getContext();
97
98 analyzeUses(function);
99
Nicolas Capens0b506e12021-02-04 17:00:08 -0500100 // Start by eliminating any dead code, to avoid redundant work for the
101 // subsequent optimization passes.
Nicolas Capens157ba262019-12-10 17:49:14 -0500102 eliminateDeadCode();
Nicolas Capens0b506e12021-02-04 17:00:08 -0500103
104 // Eliminate allocas which store the address of other allocas.
105 propagateAlloca();
106
Nicolas Capens157ba262019-12-10 17:49:14 -0500107 eliminateUnitializedLoads();
108 eliminateLoadsFollowingSingleStore();
109 optimizeStoresInSingleBasicBlock();
110 eliminateDeadCode();
111
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500112 for(auto operand : operandsWithUses)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500113 {
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500114 // Deletes the Uses instance on the operand
115 setUses(operand, nullptr);
Nicolas Capens157ba262019-12-10 17:49:14 -0500116 }
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500117 operandsWithUses.clear();
Nicolas Capens157ba262019-12-10 17:49:14 -0500118}
119
Nicolas Capens0b506e12021-02-04 17:00:08 -0500120// Eliminates allocas which store the address of other allocas.
121void Optimizer::propagateAlloca()
122{
123 Ice::CfgNode *entryBlock = function->getEntryNode();
124 Ice::InstList &instList = entryBlock->getInsts();
125
126 for(Ice::Inst &inst : instList)
127 {
128 if(inst.isDeleted())
129 {
130 continue;
131 }
132
133 auto *alloca = llvm::dyn_cast<Ice::InstAlloca>(&inst);
134
135 if(!alloca)
136 {
137 break; // Allocas are all at the top
138 }
139
140 // Look for stores of this alloca's address.
141 Ice::Operand *address = alloca->getDest();
142 Uses uses = *getUses(address); // Hard copy
143
144 for(auto *store : uses)
145 {
146 if(isStore(*store) && store->getData() == address)
147 {
148 Ice::Operand *dest = store->getStoreAddress();
149 Ice::Variable *destVar = llvm::dyn_cast<Ice::Variable>(dest);
150 Ice::Inst *def = destVar ? getDefinition(destVar) : nullptr;
151
152 // If the address is stored into another stack variable, eliminate the latter.
153 if(def && def->getKind() == Ice::Inst::Alloca)
154 {
155 Uses destUses = *getUses(dest); // Hard copy
156
157 // Make sure the only store into the stack variable is this address, and that all of its other uses are loads.
158 // This prevents dynamic array loads/stores to be replaced by a scalar.
159 if((destUses.stores.size() == 1) && (destUses.loads.size() == destUses.size() - 1))
160 {
161 for(auto *load : destUses.loads)
162 {
163 replace(load, address);
164 }
165
166 // The address is now only stored, never loaded, so the store can be eliminated, together with its alloca.
167 assert(getUses(dest)->size() == 1);
168 deleteInstruction(store);
169 assert(def->isDeleted());
170 }
171 }
172 }
173 }
174 }
175}
176
Nicolas Capens157ba262019-12-10 17:49:14 -0500177void Optimizer::eliminateDeadCode()
178{
179 bool modified;
180 do
181 {
182 modified = false;
183 for(Ice::CfgNode *basicBlock : function->getNodes())
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500184 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500185 for(Ice::Inst &inst : Ice::reverse_range(basicBlock->getInsts()))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500186 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500187 if(inst.isDeleted())
188 {
189 continue;
190 }
191
192 if(isDead(&inst))
193 {
194 deleteInstruction(&inst);
195 modified = true;
196 }
197 }
198 }
Ben Clayton713b8d32019-12-17 20:37:56 +0000199 } while(modified);
Nicolas Capens157ba262019-12-10 17:49:14 -0500200}
201
202void Optimizer::eliminateUnitializedLoads()
203{
204 Ice::CfgNode *entryBlock = function->getEntryNode();
205
206 for(Ice::Inst &alloca : entryBlock->getInsts())
207 {
208 if(alloca.isDeleted())
209 {
210 continue;
211 }
212
213 if(!llvm::isa<Ice::InstAlloca>(alloca))
214 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000215 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500216 }
217
218 Ice::Operand *address = alloca.getDest();
219
220 if(!hasUses(address))
221 {
222 continue;
223 }
224
225 const auto &addressUses = *getUses(address);
226
227 if(!addressUses.areOnlyLoadStore())
228 {
229 continue;
230 }
231
232 if(addressUses.stores.empty())
233 {
234 for(Ice::Inst *load : addressUses.loads)
235 {
236 Ice::Variable *loadData = load->getDest();
237
238 if(hasUses(loadData))
239 {
240 for(Ice::Inst *use : *getUses(loadData))
241 {
242 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
243 {
244 if(use->getSrc(i) == loadData)
245 {
246 auto *undef = context->getConstantUndef(loadData->getType());
247
248 use->replaceSource(i, undef);
249 }
250 }
251 }
252
253 setUses(loadData, nullptr);
254 }
255
256 load->setDeleted();
257 }
258
259 alloca.setDeleted();
260 setUses(address, nullptr);
261 }
262 }
263}
264
265void Optimizer::eliminateLoadsFollowingSingleStore()
266{
267 Ice::CfgNode *entryBlock = function->getEntryNode();
268
269 for(Ice::Inst &alloca : entryBlock->getInsts())
270 {
271 if(alloca.isDeleted())
272 {
273 continue;
274 }
275
276 if(!llvm::isa<Ice::InstAlloca>(alloca))
277 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000278 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500279 }
280
281 Ice::Operand *address = alloca.getDest();
282
283 if(!hasUses(address))
284 {
285 continue;
286 }
287
288 auto &addressUses = *getUses(address);
289
290 if(!addressUses.areOnlyLoadStore())
291 {
292 continue;
293 }
294
295 if(addressUses.stores.size() == 1)
296 {
297 Ice::Inst *store = addressUses.stores[0];
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500298 Ice::Operand *storeValue = store->getData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500299
300 for(Ice::Inst *load = &*++store->getIterator(), *next = nullptr; load != next; next = load, load = &*++store->getIterator())
301 {
302 if(load->isDeleted() || !isLoad(*load))
303 {
304 continue;
305 }
306
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500307 if(load->getLoadAddress() != address)
Nicolas Capens157ba262019-12-10 17:49:14 -0500308 {
309 continue;
310 }
311
312 if(!loadTypeMatchesStore(load, store))
313 {
314 continue;
315 }
316
Antonio Maioranob3d9a2a2020-02-14 14:38:04 -0500317 // TODO(b/148272103): InstLoad assumes that a constant ptr is an offset, rather than an
318 // absolute address. We need to make sure we don't replace a variable with a constant
319 // on this load.
320 if(llvm::isa<Ice::Constant>(storeValue))
321 {
322 continue;
323 }
324
Nicolas Capens157ba262019-12-10 17:49:14 -0500325 replace(load, storeValue);
326
327 for(size_t i = 0; i < addressUses.loads.size(); i++)
328 {
329 if(addressUses.loads[i] == load)
330 {
331 addressUses.loads[i] = addressUses.loads.back();
332 addressUses.loads.pop_back();
333 break;
334 }
335 }
336
337 for(size_t i = 0; i < addressUses.size(); i++)
338 {
339 if(addressUses[i] == load)
340 {
341 addressUses[i] = addressUses.back();
342 addressUses.pop_back();
343 break;
344 }
345 }
346
347 if(addressUses.size() == 1)
348 {
349 assert(addressUses[0] == store);
350
351 alloca.setDeleted();
352 store->setDeleted();
353 setUses(address, nullptr);
354
355 if(hasUses(storeValue))
356 {
357 auto &valueUses = *getUses(storeValue);
358
359 for(size_t i = 0; i < valueUses.size(); i++)
360 {
361 if(valueUses[i] == store)
362 {
363 valueUses[i] = valueUses.back();
364 valueUses.pop_back();
365 break;
366 }
367 }
368
369 if(valueUses.empty())
370 {
371 setUses(storeValue, nullptr);
372 }
373 }
374
375 break;
376 }
377 }
378 }
379 }
380}
381
382void Optimizer::optimizeStoresInSingleBasicBlock()
383{
384 Ice::CfgNode *entryBlock = function->getEntryNode();
385
Ben Clayton713b8d32019-12-17 20:37:56 +0000386 std::vector<std::vector<LoadStoreInst> *> allocatedVectors;
Nicolas Capens157ba262019-12-10 17:49:14 -0500387
388 for(Ice::Inst &alloca : entryBlock->getInsts())
389 {
390 if(alloca.isDeleted())
391 {
392 continue;
393 }
394
395 if(!llvm::isa<Ice::InstAlloca>(alloca))
396 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000397 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500398 }
399
400 Ice::Operand *address = alloca.getDest();
401
402 if(!hasUses(address))
403 {
404 continue;
405 }
406
407 const auto &addressUses = *getUses(address);
408
409 if(!addressUses.areOnlyLoadStore())
410 {
411 continue;
412 }
413
414 Ice::CfgNode *singleBasicBlock = getNode(addressUses.stores[0]);
415
416 for(size_t i = 1; i < addressUses.stores.size(); i++)
417 {
418 Ice::Inst *store = addressUses.stores[i];
419 if(getNode(store) != singleBasicBlock)
420 {
421 singleBasicBlock = nullptr;
422 break;
423 }
424 }
425
426 if(singleBasicBlock)
427 {
428 if(!hasLoadStoreInsts(singleBasicBlock))
429 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000430 std::vector<LoadStoreInst> *loadStoreInstVector = new std::vector<LoadStoreInst>();
Nicolas Capens157ba262019-12-10 17:49:14 -0500431 setLoadStoreInsts(singleBasicBlock, loadStoreInstVector);
432 allocatedVectors.push_back(loadStoreInstVector);
433 for(Ice::Inst &inst : singleBasicBlock->getInsts())
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500434 {
435 if(inst.isDeleted())
436 {
437 continue;
438 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500439
Nicolas Capens157ba262019-12-10 17:49:14 -0500440 bool isStoreInst = isStore(inst);
441 bool isLoadInst = isLoad(inst);
442
443 if(isStoreInst || isLoadInst)
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500444 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500445 loadStoreInstVector->push_back(LoadStoreInst(&inst, isStoreInst));
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500446 }
447 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500448 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500449
Nicolas Capens157ba262019-12-10 17:49:14 -0500450 Ice::Inst *store = nullptr;
451 Ice::Operand *storeValue = nullptr;
452 bool unmatchedLoads = false;
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500453
Ben Clayton713b8d32019-12-17 20:37:56 +0000454 for(auto &loadStoreInst : getLoadStoreInsts(singleBasicBlock))
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500455 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000456 Ice::Inst *inst = loadStoreInst.inst;
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500457
Nicolas Capens157ba262019-12-10 17:49:14 -0500458 if((loadStoreInst.address != address) || inst->isDeleted())
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500459 {
460 continue;
461 }
462
Nicolas Capens157ba262019-12-10 17:49:14 -0500463 if(loadStoreInst.isStore)
Alexis Hetu932640b2018-06-20 15:35:53 -0400464 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500465 // New store found. If we had a previous one, try to eliminate it.
466 if(store && !unmatchedLoads)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500467 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500468 // If the previous store is wider than the new one, we can't eliminate it
469 // because there could be a wide load reading its non-overwritten data.
470 if(storeSize(inst) >= storeSize(store))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500471 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500472 deleteInstruction(store);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500473 }
474 }
475
Nicolas Capens157ba262019-12-10 17:49:14 -0500476 store = inst;
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500477 storeValue = store->getData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500478 unmatchedLoads = false;
479 }
480 else
481 {
482 if(!loadTypeMatchesStore(inst, store))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500483 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500484 unmatchedLoads = true;
485 continue;
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500486 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500487
Antonio Maioranob3d9a2a2020-02-14 14:38:04 -0500488 // TODO(b/148272103): InstLoad assumes that a constant ptr is an offset, rather than an
489 // absolute address. We need to make sure we don't replace a variable with a constant
490 // on this load.
491 if(llvm::isa<Ice::Constant>(storeValue))
492 {
Antonio Maiorano5ff1de52020-03-03 19:53:13 -0500493 unmatchedLoads = true;
Antonio Maioranob3d9a2a2020-02-14 14:38:04 -0500494 continue;
495 }
496
Nicolas Capens157ba262019-12-10 17:49:14 -0500497 replace(inst, storeValue);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500498 }
499 }
500 }
501 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500502
Nicolas Capens157ba262019-12-10 17:49:14 -0500503 for(auto loadStoreInstVector : allocatedVectors)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500504 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500505 delete loadStoreInstVector;
506 }
507}
Nicolas Capense205c3d2016-11-30 15:14:28 -0500508
Nicolas Capens157ba262019-12-10 17:49:14 -0500509void Optimizer::analyzeUses(Ice::Cfg *function)
510{
511 for(Ice::CfgNode *basicBlock : function->getNodes())
512 {
513 for(Ice::Inst &instruction : basicBlock->getInsts())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500514 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500515 if(instruction.isDeleted())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500516 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500517 continue;
518 }
Alexis Hetu932640b2018-06-20 15:35:53 -0400519
Nicolas Capens157ba262019-12-10 17:49:14 -0500520 setNode(&instruction, basicBlock);
521 if(instruction.getDest())
522 {
523 setDefinition(instruction.getDest(), &instruction);
524 }
525
526 for(Ice::SizeT i = 0; i < instruction.getSrcSize(); i++)
527 {
528 Ice::SizeT unique = 0;
529 for(; unique < i; unique++)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500530 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500531 if(instruction.getSrc(i) == instruction.getSrc(unique))
Alexis Hetu932640b2018-06-20 15:35:53 -0400532 {
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500533 break;
534 }
535 }
536
Nicolas Capens157ba262019-12-10 17:49:14 -0500537 if(i == unique)
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500538 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500539 Ice::Operand *src = instruction.getSrc(i);
540 getUses(src)->insert(src, &instruction);
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500541 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500542 }
543 }
544 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500545}
546
Nicolas Capens157ba262019-12-10 17:49:14 -0500547void Optimizer::replace(Ice::Inst *instruction, Ice::Operand *newValue)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500548{
Nicolas Capens157ba262019-12-10 17:49:14 -0500549 Ice::Variable *oldValue = instruction->getDest();
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500550
Nicolas Capens157ba262019-12-10 17:49:14 -0500551 if(!newValue)
552 {
553 newValue = context->getConstantUndef(oldValue->getType());
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500554 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500555
556 if(hasUses(oldValue))
557 {
558 for(Ice::Inst *use : *getUses(oldValue))
559 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000560 assert(!use->isDeleted()); // Should have been removed from uses already
Nicolas Capens157ba262019-12-10 17:49:14 -0500561
562 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
563 {
564 if(use->getSrc(i) == oldValue)
565 {
566 use->replaceSource(i, newValue);
567 }
568 }
569
570 getUses(newValue)->insert(newValue, use);
571 }
572
573 setUses(oldValue, nullptr);
574 }
575
576 deleteInstruction(instruction);
577}
578
579void Optimizer::deleteInstruction(Ice::Inst *instruction)
580{
581 if(!instruction || instruction->isDeleted())
582 {
583 return;
584 }
585
586 instruction->setDeleted();
587
588 for(Ice::SizeT i = 0; i < instruction->getSrcSize(); i++)
589 {
590 Ice::Operand *src = instruction->getSrc(i);
591
592 if(hasUses(src))
593 {
594 auto &srcUses = *getUses(src);
595
596 srcUses.erase(instruction);
597
598 if(srcUses.empty())
599 {
600 setUses(src, nullptr);
601
602 if(Ice::Variable *var = llvm::dyn_cast<Ice::Variable>(src))
603 {
604 deleteInstruction(getDefinition(var));
605 }
606 }
607 }
608 }
609}
610
611bool Optimizer::isDead(Ice::Inst *instruction)
612{
613 Ice::Variable *dest = instruction->getDest();
614
615 if(dest)
616 {
617 return (!hasUses(dest) || getUses(dest)->empty()) && !instruction->hasSideEffects();
618 }
619 else if(isStore(*instruction))
620 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500621 if(Ice::Variable *address = llvm::dyn_cast<Ice::Variable>(instruction->getStoreAddress()))
Nicolas Capens157ba262019-12-10 17:49:14 -0500622 {
623 Ice::Inst *def = getDefinition(address);
624
625 if(def && llvm::isa<Ice::InstAlloca>(def))
626 {
627 if(hasUses(address))
628 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000629 Optimizer::Uses *uses = getUses(address);
630 return uses->size() == uses->stores.size(); // Dead if all uses are stores
Nicolas Capens157ba262019-12-10 17:49:14 -0500631 }
632 else
633 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000634 return true; // No uses
Nicolas Capens157ba262019-12-10 17:49:14 -0500635 }
636 }
637 }
638 }
639
640 return false;
641}
642
Nicolas Capens33a77f72021-02-08 15:04:38 -0500643const Ice::InstIntrinsic *Optimizer::asLoadSubVector(const Ice::Inst *instruction)
Nicolas Capens157ba262019-12-10 17:49:14 -0500644{
Nicolas Capens33a77f72021-02-08 15:04:38 -0500645 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsic>(instruction))
Nicolas Capens157ba262019-12-10 17:49:14 -0500646 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500647 if(instrinsic->getIntrinsicID() == Ice::Intrinsics::LoadSubVector)
Nicolas Capens157ba262019-12-10 17:49:14 -0500648 {
649 return instrinsic;
650 }
651 }
652
653 return nullptr;
654}
655
Nicolas Capens33a77f72021-02-08 15:04:38 -0500656const Ice::InstIntrinsic *Optimizer::asStoreSubVector(const Ice::Inst *instruction)
Nicolas Capens157ba262019-12-10 17:49:14 -0500657{
Nicolas Capens33a77f72021-02-08 15:04:38 -0500658 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsic>(instruction))
Nicolas Capens157ba262019-12-10 17:49:14 -0500659 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500660 if(instrinsic->getIntrinsicID() == Ice::Intrinsics::StoreSubVector)
Nicolas Capens157ba262019-12-10 17:49:14 -0500661 {
662 return instrinsic;
663 }
664 }
665
666 return nullptr;
667}
668
669bool Optimizer::isLoad(const Ice::Inst &instruction)
670{
671 if(llvm::isa<Ice::InstLoad>(&instruction))
672 {
673 return true;
674 }
675
676 return asLoadSubVector(&instruction) != nullptr;
677}
678
679bool Optimizer::isStore(const Ice::Inst &instruction)
680{
681 if(llvm::isa<Ice::InstStore>(&instruction))
682 {
683 return true;
684 }
685
686 return asStoreSubVector(&instruction) != nullptr;
687}
688
Nicolas Capens157ba262019-12-10 17:49:14 -0500689std::size_t Optimizer::storeSize(const Ice::Inst *store)
690{
691 assert(isStore(*store));
692
693 if(auto *instStore = llvm::dyn_cast<Ice::InstStore>(store))
694 {
695 return Ice::typeWidthInBytes(instStore->getData()->getType());
696 }
697
698 if(auto *storeSubVector = asStoreSubVector(store))
699 {
700 return llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(3))->getValue();
701 }
702
703 return 0;
704}
705
706bool Optimizer::loadTypeMatchesStore(const Ice::Inst *load, const Ice::Inst *store)
707{
708 if(!load || !store)
709 {
710 return false;
711 }
712
713 assert(isLoad(*load) && isStore(*store));
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500714 assert(load->getLoadAddress() == store->getStoreAddress());
Nicolas Capens157ba262019-12-10 17:49:14 -0500715
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500716 if(store->getData()->getType() != load->getDest()->getType())
Nicolas Capens157ba262019-12-10 17:49:14 -0500717 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500718 return false;
Nicolas Capens157ba262019-12-10 17:49:14 -0500719 }
720
721 if(auto *storeSubVector = asStoreSubVector(store))
722 {
723 if(auto *loadSubVector = asLoadSubVector(load))
724 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500725 // Check for matching sub-vector width.
726 return llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(2))->getValue() ==
727 llvm::cast<Ice::ConstantInteger32>(loadSubVector->getSrc(1))->getValue();
Nicolas Capens157ba262019-12-10 17:49:14 -0500728 }
729 }
730
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500731 return true;
Nicolas Capens157ba262019-12-10 17:49:14 -0500732}
733
Ben Clayton713b8d32019-12-17 20:37:56 +0000734Optimizer::Uses *Optimizer::getUses(Ice::Operand *operand)
Nicolas Capens157ba262019-12-10 17:49:14 -0500735{
Ben Clayton713b8d32019-12-17 20:37:56 +0000736 Optimizer::Uses *uses = (Optimizer::Uses *)operand->Ice::Operand::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500737 if(!uses)
738 {
739 uses = new Optimizer::Uses;
740 setUses(operand, uses);
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500741 operandsWithUses.push_back(operand);
Nicolas Capens157ba262019-12-10 17:49:14 -0500742 }
743 return uses;
744}
745
Ben Clayton713b8d32019-12-17 20:37:56 +0000746void Optimizer::setUses(Ice::Operand *operand, Optimizer::Uses *uses)
Nicolas Capens157ba262019-12-10 17:49:14 -0500747{
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500748 if(auto *oldUses = reinterpret_cast<Optimizer::Uses *>(operand->Ice::Operand::getExternalData()))
749 {
750 delete oldUses;
751 }
752
Nicolas Capens157ba262019-12-10 17:49:14 -0500753 operand->Ice::Operand::setExternalData(uses);
754}
755
Ben Clayton713b8d32019-12-17 20:37:56 +0000756bool Optimizer::hasUses(Ice::Operand *operand) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500757{
758 return operand->Ice::Operand::getExternalData() != nullptr;
759}
760
Ben Clayton713b8d32019-12-17 20:37:56 +0000761Ice::CfgNode *Optimizer::getNode(Ice::Inst *inst)
Nicolas Capens157ba262019-12-10 17:49:14 -0500762{
Ben Clayton713b8d32019-12-17 20:37:56 +0000763 return (Ice::CfgNode *)inst->Ice::Inst::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500764}
765
Ben Clayton713b8d32019-12-17 20:37:56 +0000766void Optimizer::setNode(Ice::Inst *inst, Ice::CfgNode *node)
Nicolas Capens157ba262019-12-10 17:49:14 -0500767{
768 inst->Ice::Inst::setExternalData(node);
769}
770
Ben Clayton713b8d32019-12-17 20:37:56 +0000771Ice::Inst *Optimizer::getDefinition(Ice::Variable *var)
Nicolas Capens157ba262019-12-10 17:49:14 -0500772{
Ben Clayton713b8d32019-12-17 20:37:56 +0000773 return (Ice::Inst *)var->Ice::Variable::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500774}
775
Ben Clayton713b8d32019-12-17 20:37:56 +0000776void Optimizer::setDefinition(Ice::Variable *var, Ice::Inst *inst)
Nicolas Capens157ba262019-12-10 17:49:14 -0500777{
778 var->Ice::Variable::setExternalData(inst);
779}
780
Ben Clayton713b8d32019-12-17 20:37:56 +0000781const std::vector<Optimizer::LoadStoreInst> &Optimizer::getLoadStoreInsts(Ice::CfgNode *node)
Nicolas Capens157ba262019-12-10 17:49:14 -0500782{
Ben Clayton713b8d32019-12-17 20:37:56 +0000783 return *((const std::vector<LoadStoreInst> *)node->Ice::CfgNode::getExternalData());
Nicolas Capens157ba262019-12-10 17:49:14 -0500784}
785
Ben Clayton713b8d32019-12-17 20:37:56 +0000786void Optimizer::setLoadStoreInsts(Ice::CfgNode *node, std::vector<LoadStoreInst> *insts)
Nicolas Capens157ba262019-12-10 17:49:14 -0500787{
788 node->Ice::CfgNode::setExternalData(insts);
789}
790
Ben Clayton713b8d32019-12-17 20:37:56 +0000791bool Optimizer::hasLoadStoreInsts(Ice::CfgNode *node) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500792{
793 return node->Ice::CfgNode::getExternalData() != nullptr;
794}
795
796bool Optimizer::Uses::areOnlyLoadStore() const
797{
798 return size() == (loads.size() + stores.size());
799}
800
801void Optimizer::Uses::insert(Ice::Operand *value, Ice::Inst *instruction)
802{
803 push_back(instruction);
804
805 if(isLoad(*instruction))
806 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500807 if(value == instruction->getLoadAddress())
Nicolas Capens157ba262019-12-10 17:49:14 -0500808 {
809 loads.push_back(instruction);
810 }
811 }
812 else if(isStore(*instruction))
813 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500814 if(value == instruction->getStoreAddress())
Nicolas Capens157ba262019-12-10 17:49:14 -0500815 {
816 stores.push_back(instruction);
817 }
818 }
819}
820
821void Optimizer::Uses::erase(Ice::Inst *instruction)
822{
823 auto &uses = *this;
824
825 for(size_t i = 0; i < uses.size(); i++)
826 {
827 if(uses[i] == instruction)
828 {
829 uses[i] = back();
830 pop_back();
831
832 for(size_t i = 0; i < loads.size(); i++)
833 {
834 if(loads[i] == instruction)
835 {
836 loads[i] = loads.back();
837 loads.pop_back();
838 break;
839 }
840 }
841
842 for(size_t i = 0; i < stores.size(); i++)
843 {
844 if(stores[i] == instruction)
845 {
846 stores[i] = stores.back();
847 stores.pop_back();
848 break;
849 }
850 }
851
852 break;
853 }
854 }
855}
856
Ben Clayton713b8d32019-12-17 20:37:56 +0000857} // anonymous namespace
Nicolas Capens157ba262019-12-10 17:49:14 -0500858
859namespace rr {
860
861void optimize(Ice::Cfg *function)
862{
863 Optimizer optimizer;
864
865 optimizer.run(function);
866}
867
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500868} // namespace rr