blob: d5f95e89d55ef1f1f82d8d7f1ac2d50be1f60368 [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
Nicolas Capens3ab17bd2021-02-10 16:41:31 -0500300 auto instIterator = store->getIterator();
301 auto basicBlockEnd = getNode(store)->getInsts().end();
302
303 while(++instIterator != basicBlockEnd)
Nicolas Capens157ba262019-12-10 17:49:14 -0500304 {
Nicolas Capens3ab17bd2021-02-10 16:41:31 -0500305 Ice::Inst *load = &*instIterator;
306
Nicolas Capens157ba262019-12-10 17:49:14 -0500307 if(load->isDeleted() || !isLoad(*load))
308 {
309 continue;
310 }
311
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500312 if(load->getLoadAddress() != address)
Nicolas Capens157ba262019-12-10 17:49:14 -0500313 {
314 continue;
315 }
316
317 if(!loadTypeMatchesStore(load, store))
318 {
319 continue;
320 }
321
322 replace(load, storeValue);
323
324 for(size_t i = 0; i < addressUses.loads.size(); i++)
325 {
326 if(addressUses.loads[i] == load)
327 {
328 addressUses.loads[i] = addressUses.loads.back();
329 addressUses.loads.pop_back();
330 break;
331 }
332 }
333
334 for(size_t i = 0; i < addressUses.size(); i++)
335 {
336 if(addressUses[i] == load)
337 {
338 addressUses[i] = addressUses.back();
339 addressUses.pop_back();
340 break;
341 }
342 }
343
344 if(addressUses.size() == 1)
345 {
346 assert(addressUses[0] == store);
347
348 alloca.setDeleted();
349 store->setDeleted();
350 setUses(address, nullptr);
351
352 if(hasUses(storeValue))
353 {
354 auto &valueUses = *getUses(storeValue);
355
356 for(size_t i = 0; i < valueUses.size(); i++)
357 {
358 if(valueUses[i] == store)
359 {
360 valueUses[i] = valueUses.back();
361 valueUses.pop_back();
362 break;
363 }
364 }
365
366 if(valueUses.empty())
367 {
368 setUses(storeValue, nullptr);
369 }
370 }
371
372 break;
373 }
374 }
375 }
376 }
377}
378
379void Optimizer::optimizeStoresInSingleBasicBlock()
380{
381 Ice::CfgNode *entryBlock = function->getEntryNode();
382
Ben Clayton713b8d32019-12-17 20:37:56 +0000383 std::vector<std::vector<LoadStoreInst> *> allocatedVectors;
Nicolas Capens157ba262019-12-10 17:49:14 -0500384
385 for(Ice::Inst &alloca : entryBlock->getInsts())
386 {
387 if(alloca.isDeleted())
388 {
389 continue;
390 }
391
392 if(!llvm::isa<Ice::InstAlloca>(alloca))
393 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000394 break; // Allocas are all at the top
Nicolas Capens157ba262019-12-10 17:49:14 -0500395 }
396
397 Ice::Operand *address = alloca.getDest();
398
399 if(!hasUses(address))
400 {
401 continue;
402 }
403
404 const auto &addressUses = *getUses(address);
405
406 if(!addressUses.areOnlyLoadStore())
407 {
408 continue;
409 }
410
411 Ice::CfgNode *singleBasicBlock = getNode(addressUses.stores[0]);
412
413 for(size_t i = 1; i < addressUses.stores.size(); i++)
414 {
415 Ice::Inst *store = addressUses.stores[i];
416 if(getNode(store) != singleBasicBlock)
417 {
418 singleBasicBlock = nullptr;
419 break;
420 }
421 }
422
423 if(singleBasicBlock)
424 {
425 if(!hasLoadStoreInsts(singleBasicBlock))
426 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000427 std::vector<LoadStoreInst> *loadStoreInstVector = new std::vector<LoadStoreInst>();
Nicolas Capens157ba262019-12-10 17:49:14 -0500428 setLoadStoreInsts(singleBasicBlock, loadStoreInstVector);
429 allocatedVectors.push_back(loadStoreInstVector);
430 for(Ice::Inst &inst : singleBasicBlock->getInsts())
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500431 {
432 if(inst.isDeleted())
433 {
434 continue;
435 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500436
Nicolas Capens157ba262019-12-10 17:49:14 -0500437 bool isStoreInst = isStore(inst);
438 bool isLoadInst = isLoad(inst);
439
440 if(isStoreInst || isLoadInst)
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500441 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500442 loadStoreInstVector->push_back(LoadStoreInst(&inst, isStoreInst));
Nicolas Capensc9d70d52016-12-12 15:07:39 -0500443 }
444 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500445 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500446
Nicolas Capens157ba262019-12-10 17:49:14 -0500447 Ice::Inst *store = nullptr;
448 Ice::Operand *storeValue = nullptr;
449 bool unmatchedLoads = false;
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500450
Ben Clayton713b8d32019-12-17 20:37:56 +0000451 for(auto &loadStoreInst : getLoadStoreInsts(singleBasicBlock))
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500452 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000453 Ice::Inst *inst = loadStoreInst.inst;
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500454
Nicolas Capens157ba262019-12-10 17:49:14 -0500455 if((loadStoreInst.address != address) || inst->isDeleted())
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500456 {
457 continue;
458 }
459
Nicolas Capens157ba262019-12-10 17:49:14 -0500460 if(loadStoreInst.isStore)
Alexis Hetu932640b2018-06-20 15:35:53 -0400461 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500462 // New store found. If we had a previous one, try to eliminate it.
463 if(store && !unmatchedLoads)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500464 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500465 // If the previous store is wider than the new one, we can't eliminate it
466 // because there could be a wide load reading its non-overwritten data.
467 if(storeSize(inst) >= storeSize(store))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500468 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500469 deleteInstruction(store);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500470 }
471 }
472
Nicolas Capens157ba262019-12-10 17:49:14 -0500473 store = inst;
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500474 storeValue = store->getData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500475 unmatchedLoads = false;
476 }
477 else
478 {
479 if(!loadTypeMatchesStore(inst, store))
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500480 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500481 unmatchedLoads = true;
482 continue;
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500483 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500484
485 replace(inst, storeValue);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500486 }
487 }
488 }
489 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500490
Nicolas Capens157ba262019-12-10 17:49:14 -0500491 for(auto loadStoreInstVector : allocatedVectors)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500492 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500493 delete loadStoreInstVector;
494 }
495}
Nicolas Capense205c3d2016-11-30 15:14:28 -0500496
Nicolas Capens157ba262019-12-10 17:49:14 -0500497void Optimizer::analyzeUses(Ice::Cfg *function)
498{
499 for(Ice::CfgNode *basicBlock : function->getNodes())
500 {
501 for(Ice::Inst &instruction : basicBlock->getInsts())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500502 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500503 if(instruction.isDeleted())
Nicolas Capense205c3d2016-11-30 15:14:28 -0500504 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500505 continue;
506 }
Alexis Hetu932640b2018-06-20 15:35:53 -0400507
Nicolas Capens157ba262019-12-10 17:49:14 -0500508 setNode(&instruction, basicBlock);
509 if(instruction.getDest())
510 {
511 setDefinition(instruction.getDest(), &instruction);
512 }
513
514 for(Ice::SizeT i = 0; i < instruction.getSrcSize(); i++)
515 {
516 Ice::SizeT unique = 0;
517 for(; unique < i; unique++)
Nicolas Capense205c3d2016-11-30 15:14:28 -0500518 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500519 if(instruction.getSrc(i) == instruction.getSrc(unique))
Alexis Hetu932640b2018-06-20 15:35:53 -0400520 {
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500521 break;
522 }
523 }
524
Nicolas Capens157ba262019-12-10 17:49:14 -0500525 if(i == unique)
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500526 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500527 Ice::Operand *src = instruction.getSrc(i);
528 getUses(src)->insert(src, &instruction);
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500529 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500530 }
531 }
532 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500533}
534
Nicolas Capens157ba262019-12-10 17:49:14 -0500535void Optimizer::replace(Ice::Inst *instruction, Ice::Operand *newValue)
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500536{
Nicolas Capens157ba262019-12-10 17:49:14 -0500537 Ice::Variable *oldValue = instruction->getDest();
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500538
Nicolas Capens157ba262019-12-10 17:49:14 -0500539 if(!newValue)
540 {
541 newValue = context->getConstantUndef(oldValue->getType());
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500542 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500543
544 if(hasUses(oldValue))
545 {
546 for(Ice::Inst *use : *getUses(oldValue))
547 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000548 assert(!use->isDeleted()); // Should have been removed from uses already
Nicolas Capens157ba262019-12-10 17:49:14 -0500549
550 for(Ice::SizeT i = 0; i < use->getSrcSize(); i++)
551 {
552 if(use->getSrc(i) == oldValue)
553 {
554 use->replaceSource(i, newValue);
555 }
556 }
557
558 getUses(newValue)->insert(newValue, use);
559 }
560
561 setUses(oldValue, nullptr);
562 }
563
564 deleteInstruction(instruction);
565}
566
567void Optimizer::deleteInstruction(Ice::Inst *instruction)
568{
569 if(!instruction || instruction->isDeleted())
570 {
571 return;
572 }
573
574 instruction->setDeleted();
575
576 for(Ice::SizeT i = 0; i < instruction->getSrcSize(); i++)
577 {
578 Ice::Operand *src = instruction->getSrc(i);
579
580 if(hasUses(src))
581 {
582 auto &srcUses = *getUses(src);
583
584 srcUses.erase(instruction);
585
586 if(srcUses.empty())
587 {
588 setUses(src, nullptr);
589
590 if(Ice::Variable *var = llvm::dyn_cast<Ice::Variable>(src))
591 {
592 deleteInstruction(getDefinition(var));
593 }
594 }
595 }
596 }
597}
598
599bool Optimizer::isDead(Ice::Inst *instruction)
600{
601 Ice::Variable *dest = instruction->getDest();
602
603 if(dest)
604 {
605 return (!hasUses(dest) || getUses(dest)->empty()) && !instruction->hasSideEffects();
606 }
607 else if(isStore(*instruction))
608 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500609 if(Ice::Variable *address = llvm::dyn_cast<Ice::Variable>(instruction->getStoreAddress()))
Nicolas Capens157ba262019-12-10 17:49:14 -0500610 {
611 Ice::Inst *def = getDefinition(address);
612
613 if(def && llvm::isa<Ice::InstAlloca>(def))
614 {
615 if(hasUses(address))
616 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000617 Optimizer::Uses *uses = getUses(address);
618 return uses->size() == uses->stores.size(); // Dead if all uses are stores
Nicolas Capens157ba262019-12-10 17:49:14 -0500619 }
620 else
621 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000622 return true; // No uses
Nicolas Capens157ba262019-12-10 17:49:14 -0500623 }
624 }
625 }
626 }
627
628 return false;
629}
630
Nicolas Capens33a77f72021-02-08 15:04:38 -0500631const Ice::InstIntrinsic *Optimizer::asLoadSubVector(const Ice::Inst *instruction)
Nicolas Capens157ba262019-12-10 17:49:14 -0500632{
Nicolas Capens33a77f72021-02-08 15:04:38 -0500633 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsic>(instruction))
Nicolas Capens157ba262019-12-10 17:49:14 -0500634 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500635 if(instrinsic->getIntrinsicID() == Ice::Intrinsics::LoadSubVector)
Nicolas Capens157ba262019-12-10 17:49:14 -0500636 {
637 return instrinsic;
638 }
639 }
640
641 return nullptr;
642}
643
Nicolas Capens33a77f72021-02-08 15:04:38 -0500644const Ice::InstIntrinsic *Optimizer::asStoreSubVector(const Ice::Inst *instruction)
Nicolas Capens157ba262019-12-10 17:49:14 -0500645{
Nicolas Capens33a77f72021-02-08 15:04:38 -0500646 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsic>(instruction))
Nicolas Capens157ba262019-12-10 17:49:14 -0500647 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500648 if(instrinsic->getIntrinsicID() == Ice::Intrinsics::StoreSubVector)
Nicolas Capens157ba262019-12-10 17:49:14 -0500649 {
650 return instrinsic;
651 }
652 }
653
654 return nullptr;
655}
656
657bool Optimizer::isLoad(const Ice::Inst &instruction)
658{
659 if(llvm::isa<Ice::InstLoad>(&instruction))
660 {
661 return true;
662 }
663
664 return asLoadSubVector(&instruction) != nullptr;
665}
666
667bool Optimizer::isStore(const Ice::Inst &instruction)
668{
669 if(llvm::isa<Ice::InstStore>(&instruction))
670 {
671 return true;
672 }
673
674 return asStoreSubVector(&instruction) != nullptr;
675}
676
Nicolas Capens157ba262019-12-10 17:49:14 -0500677std::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));
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500702 assert(load->getLoadAddress() == store->getStoreAddress());
Nicolas Capens157ba262019-12-10 17:49:14 -0500703
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500704 if(store->getData()->getType() != load->getDest()->getType())
Nicolas Capens157ba262019-12-10 17:49:14 -0500705 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500706 return false;
Nicolas Capens157ba262019-12-10 17:49:14 -0500707 }
708
709 if(auto *storeSubVector = asStoreSubVector(store))
710 {
711 if(auto *loadSubVector = asLoadSubVector(load))
712 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500713 // Check for matching sub-vector width.
714 return llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(2))->getValue() ==
715 llvm::cast<Ice::ConstantInteger32>(loadSubVector->getSrc(1))->getValue();
Nicolas Capens157ba262019-12-10 17:49:14 -0500716 }
717 }
718
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500719 return true;
Nicolas Capens157ba262019-12-10 17:49:14 -0500720}
721
Ben Clayton713b8d32019-12-17 20:37:56 +0000722Optimizer::Uses *Optimizer::getUses(Ice::Operand *operand)
Nicolas Capens157ba262019-12-10 17:49:14 -0500723{
Ben Clayton713b8d32019-12-17 20:37:56 +0000724 Optimizer::Uses *uses = (Optimizer::Uses *)operand->Ice::Operand::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500725 if(!uses)
726 {
727 uses = new Optimizer::Uses;
728 setUses(operand, uses);
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500729 operandsWithUses.push_back(operand);
Nicolas Capens157ba262019-12-10 17:49:14 -0500730 }
731 return uses;
732}
733
Ben Clayton713b8d32019-12-17 20:37:56 +0000734void Optimizer::setUses(Ice::Operand *operand, Optimizer::Uses *uses)
Nicolas Capens157ba262019-12-10 17:49:14 -0500735{
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500736 if(auto *oldUses = reinterpret_cast<Optimizer::Uses *>(operand->Ice::Operand::getExternalData()))
737 {
738 delete oldUses;
739 }
740
Nicolas Capens157ba262019-12-10 17:49:14 -0500741 operand->Ice::Operand::setExternalData(uses);
742}
743
Ben Clayton713b8d32019-12-17 20:37:56 +0000744bool Optimizer::hasUses(Ice::Operand *operand) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500745{
746 return operand->Ice::Operand::getExternalData() != nullptr;
747}
748
Ben Clayton713b8d32019-12-17 20:37:56 +0000749Ice::CfgNode *Optimizer::getNode(Ice::Inst *inst)
Nicolas Capens157ba262019-12-10 17:49:14 -0500750{
Ben Clayton713b8d32019-12-17 20:37:56 +0000751 return (Ice::CfgNode *)inst->Ice::Inst::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500752}
753
Ben Clayton713b8d32019-12-17 20:37:56 +0000754void Optimizer::setNode(Ice::Inst *inst, Ice::CfgNode *node)
Nicolas Capens157ba262019-12-10 17:49:14 -0500755{
756 inst->Ice::Inst::setExternalData(node);
757}
758
Ben Clayton713b8d32019-12-17 20:37:56 +0000759Ice::Inst *Optimizer::getDefinition(Ice::Variable *var)
Nicolas Capens157ba262019-12-10 17:49:14 -0500760{
Ben Clayton713b8d32019-12-17 20:37:56 +0000761 return (Ice::Inst *)var->Ice::Variable::getExternalData();
Nicolas Capens157ba262019-12-10 17:49:14 -0500762}
763
Ben Clayton713b8d32019-12-17 20:37:56 +0000764void Optimizer::setDefinition(Ice::Variable *var, Ice::Inst *inst)
Nicolas Capens157ba262019-12-10 17:49:14 -0500765{
766 var->Ice::Variable::setExternalData(inst);
767}
768
Ben Clayton713b8d32019-12-17 20:37:56 +0000769const std::vector<Optimizer::LoadStoreInst> &Optimizer::getLoadStoreInsts(Ice::CfgNode *node)
Nicolas Capens157ba262019-12-10 17:49:14 -0500770{
Ben Clayton713b8d32019-12-17 20:37:56 +0000771 return *((const std::vector<LoadStoreInst> *)node->Ice::CfgNode::getExternalData());
Nicolas Capens157ba262019-12-10 17:49:14 -0500772}
773
Ben Clayton713b8d32019-12-17 20:37:56 +0000774void Optimizer::setLoadStoreInsts(Ice::CfgNode *node, std::vector<LoadStoreInst> *insts)
Nicolas Capens157ba262019-12-10 17:49:14 -0500775{
776 node->Ice::CfgNode::setExternalData(insts);
777}
778
Ben Clayton713b8d32019-12-17 20:37:56 +0000779bool Optimizer::hasLoadStoreInsts(Ice::CfgNode *node) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500780{
781 return node->Ice::CfgNode::getExternalData() != nullptr;
782}
783
784bool Optimizer::Uses::areOnlyLoadStore() const
785{
786 return size() == (loads.size() + stores.size());
787}
788
789void Optimizer::Uses::insert(Ice::Operand *value, Ice::Inst *instruction)
790{
791 push_back(instruction);
792
793 if(isLoad(*instruction))
794 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500795 if(value == instruction->getLoadAddress())
Nicolas Capens157ba262019-12-10 17:49:14 -0500796 {
797 loads.push_back(instruction);
798 }
799 }
800 else if(isStore(*instruction))
801 {
Nicolas Capens673a7fe2021-02-05 15:03:22 -0500802 if(value == instruction->getStoreAddress())
Nicolas Capens157ba262019-12-10 17:49:14 -0500803 {
804 stores.push_back(instruction);
805 }
806 }
807}
808
809void Optimizer::Uses::erase(Ice::Inst *instruction)
810{
811 auto &uses = *this;
812
813 for(size_t i = 0; i < uses.size(); i++)
814 {
815 if(uses[i] == instruction)
816 {
817 uses[i] = back();
818 pop_back();
819
820 for(size_t i = 0; i < loads.size(); i++)
821 {
822 if(loads[i] == instruction)
823 {
824 loads[i] = loads.back();
825 loads.pop_back();
826 break;
827 }
828 }
829
830 for(size_t i = 0; i < stores.size(); i++)
831 {
832 if(stores[i] == instruction)
833 {
834 stores[i] = stores.back();
835 stores.pop_back();
836 break;
837 }
838 }
839
840 break;
841 }
842 }
843}
844
Ben Clayton713b8d32019-12-17 20:37:56 +0000845} // anonymous namespace
Nicolas Capens157ba262019-12-10 17:49:14 -0500846
847namespace rr {
848
849void optimize(Ice::Cfg *function)
850{
851 Optimizer optimizer;
852
853 optimizer.run(function);
854}
855
Antonio Maiorano614a4d42020-01-29 13:33:02 -0500856} // namespace rr