blob: a3b328e7b1274c0de344bd825ccbd5d06a798889 [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
20#include <map>
21#include <vector>
22
23namespace
24{
25 class Optimizer
26 {
27 public:
28 void run(Ice::Cfg *function);
29
30 private:
31 void analyzeUses(Ice::Cfg *function);
32 void eliminateUnusedAllocas();
Nicolas Capensf4452fc2016-12-12 13:08:06 -050033 void eliminateUnitializedLoads();
Nicolas Capense205c3d2016-11-30 15:14:28 -050034 void eliminateLoadsFollowingSingleStore();
35
36 void replace(Ice::Inst *instruction, Ice::Operand *newValue);
37 void deleteInstruction(Ice::Inst *instruction);
Nicolas Capensf4452fc2016-12-12 13:08:06 -050038
39 static bool isLoad(const Ice::Inst &instruction);
40 static bool isStore(const Ice::Inst &instruction);
41 static Ice::Operand *storeAddress(const Ice::Inst *instruction);
42 static Ice::Operand *loadAddress(const Ice::Inst *instruction);
Nicolas Capense205c3d2016-11-30 15:14:28 -050043 static Ice::Operand *storeData(const Ice::Inst *instruction);
Nicolas Capens2ae9d742016-11-24 14:43:05 -050044
45 Ice::Cfg *function;
Nicolas Capensf4452fc2016-12-12 13:08:06 -050046 Ice::GlobalContext *context;
Nicolas Capens2ae9d742016-11-24 14:43:05 -050047
Nicolas Capensf4452fc2016-12-12 13:08:06 -050048 struct Uses : std::vector<Ice::Inst*>
49 {
50 bool areOnlyLoadStore() const;
51 void insert(Ice::Operand *value, Ice::Inst *instruction);
52 void erase(Ice::Inst *instruction);
53
54 std::vector<Ice::Inst*> loads;
55 std::vector<Ice::Inst*> stores;
56 };
57
58 std::map<Ice::Operand*, Uses> uses;
Nicolas Capense205c3d2016-11-30 15:14:28 -050059 std::map<Ice::Inst*, Ice::CfgNode*> node;
60 std::map<Ice::Variable*, Ice::Inst*> definition;
Nicolas Capens2ae9d742016-11-24 14:43:05 -050061 };
62
63 void Optimizer::run(Ice::Cfg *function)
64 {
65 this->function = function;
Nicolas Capensf4452fc2016-12-12 13:08:06 -050066 this->context = function->getContext();
Nicolas Capens2ae9d742016-11-24 14:43:05 -050067
68 analyzeUses(function);
69
70 eliminateUnusedAllocas();
Nicolas Capensf4452fc2016-12-12 13:08:06 -050071 eliminateUnitializedLoads();
Nicolas Capense205c3d2016-11-30 15:14:28 -050072 eliminateLoadsFollowingSingleStore();
Nicolas Capens2ae9d742016-11-24 14:43:05 -050073 }
74
75 void Optimizer::eliminateUnusedAllocas()
76 {
77 Ice::CfgNode *entryBlock = function->getEntryNode();
78
79 for(Ice::Inst &alloca : entryBlock->getInsts())
80 {
81 if(!llvm::isa<Ice::InstAlloca>(alloca))
82 {
83 return; // Allocas are all at the top
84 }
85
86 Ice::Operand *address = alloca.getDest();
87
88 if(uses[address].empty())
89 {
90 alloca.setDeleted();
91 }
92 }
93 }
94
Nicolas Capensf4452fc2016-12-12 13:08:06 -050095 void Optimizer::eliminateUnitializedLoads()
96 {
97 Ice::CfgNode *entryBlock = function->getEntryNode();
98
99 for(Ice::Inst &alloca : entryBlock->getInsts())
100 {
101 if(alloca.isDeleted())
102 {
103 continue;
104 }
105
106 if(!llvm::isa<Ice::InstAlloca>(alloca))
107 {
108 return; // Allocas are all at the top
109 }
110
111 Ice::Operand *address = alloca.getDest();
112 const auto &addressEntry = uses.find(address);
113 const auto &addressUses = addressEntry->second;
114
115 if(!addressUses.areOnlyLoadStore())
116 {
117 continue;
118 }
119
120 if(addressUses.stores.empty())
121 {
122 for(Ice::Inst *load : addressUses.loads)
123 {
124 Ice::Variable *loadData = load->getDest();
125
126 for(Ice::Inst *use : uses[loadData])
127 {
128 for(int i = 0; i < use->getSrcSize(); i++)
129 {
130 if(use->getSrc(i) == loadData)
131 {
132 auto *undef = context->getConstantUndef(loadData->getType());
133
134 use->replaceSource(i, undef);
135 }
136 }
137 }
138
139 uses.erase(loadData);
140
141 load->setDeleted();
142 }
143
144 alloca.setDeleted();
145 uses.erase(addressEntry);
146 }
147 }
148 }
149
Nicolas Capense205c3d2016-11-30 15:14:28 -0500150 void Optimizer::eliminateLoadsFollowingSingleStore()
151 {
152 Ice::CfgNode *entryBlock = function->getEntryNode();
153
154 for(Ice::Inst &alloca : entryBlock->getInsts())
155 {
156 if(alloca.isDeleted())
157 {
158 continue;
159 }
160
161 if(!llvm::isa<Ice::InstAlloca>(alloca))
162 {
163 return; // Allocas are all at the top
164 }
165
166 Ice::Operand *address = alloca.getDest();
167 const auto &addressEntry = uses.find(address);
168 auto &addressUses = addressEntry->second;
169
170 if(!addressUses.areOnlyLoadStore())
171 {
172 continue;
173 }
174
175 if(addressUses.stores.size() == 1)
176 {
177 Ice::Inst *store = addressUses.stores[0];
178 Ice::Operand *storeValue = storeData(store);
179
180 for(Ice::Inst *load = &*++store->getIterator(), *next = nullptr; load != next; next = load, load = &*++store->getIterator())
181 {
182 if(load->isDeleted() || !isLoad(*load))
183 {
184 continue;
185 }
186
187 if(loadAddress(load) != address)
188 {
189 continue;
190 }
191
192 replace(load, storeValue);
193
194 for(int i = 0; i < addressUses.loads.size(); i++)
195 {
196 if(addressUses.loads[i] == load)
197 {
198 addressUses.loads[i] = addressUses.loads.back();
199 addressUses.loads.pop_back();
200 break;
201 }
202 }
203
204 for(int i = 0; i < addressUses.size(); i++)
205 {
206 if(addressUses[i] == load)
207 {
208 addressUses[i] = addressUses.back();
209 addressUses.pop_back();
210 break;
211 }
212 }
213
214 if(addressUses.size() == 1)
215 {
216 assert(addressUses[0] == store);
217
218 alloca.setDeleted();
219 store->setDeleted();
220 uses.erase(address);
221
222 auto &valueUses = uses[storeValue];
223
224 for(int i = 0; i < valueUses.size(); i++)
225 {
226 if(valueUses[i] == store)
227 {
228 valueUses[i] = valueUses.back();
229 valueUses.pop_back();
230 break;
231 }
232 }
233
234 if(valueUses.empty())
235 {
236 uses.erase(storeValue);
237 }
238
239 break;
240 }
241 }
242 }
243 }
244 }
245
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500246 void Optimizer::analyzeUses(Ice::Cfg *function)
247 {
248 uses.clear();
Nicolas Capense205c3d2016-11-30 15:14:28 -0500249 node.clear();
250 definition.clear();
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500251
252 for(Ice::CfgNode *basicBlock : function->getNodes())
253 {
254 for(Ice::Inst &instruction : basicBlock->getInsts())
255 {
256 if(instruction.isDeleted())
257 {
258 continue;
259 }
260
Nicolas Capense205c3d2016-11-30 15:14:28 -0500261 node[&instruction] = basicBlock;
262 definition[instruction.getDest()] = &instruction;
263
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500264 for(int i = 0; i < instruction.getSrcSize(); i++)
265 {
266 int unique = 0;
267 for(; unique < i; unique++)
268 {
269 if(instruction.getSrc(i) == instruction.getSrc(unique))
270 {
271 break;
272 }
273 }
274
275 if(i == unique)
276 {
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500277 Ice::Operand *src = instruction.getSrc(i);
278 uses[src].insert(src, &instruction);
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500279 }
280 }
281 }
282 }
283 }
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500284
Nicolas Capense205c3d2016-11-30 15:14:28 -0500285 void Optimizer::replace(Ice::Inst *instruction, Ice::Operand *newValue)
286 {
287 Ice::Variable *oldValue = instruction->getDest();
288
289 if(!newValue)
290 {
291 newValue = context->getConstantUndef(oldValue->getType());
292 }
293
294 for(Ice::Inst *use : uses[oldValue])
295 {
296 assert(!use->isDeleted()); // Should have been removed from uses already
297
298 for(int i = 0; i < use->getSrcSize(); i++)
299 {
300 if(use->getSrc(i) == oldValue)
301 {
302 use->replaceSource(i, newValue);
303 }
304 }
305
306 uses[newValue].insert(newValue, use);
307 }
308
309 uses.erase(oldValue);
310
311 deleteInstruction(instruction);
312 }
313
314 void Optimizer::deleteInstruction(Ice::Inst *instruction)
315 {
316 if(instruction->isDeleted())
317 {
318 return;
319 }
320
321 instruction->setDeleted();
322
323 for(int i = 0; i < instruction->getSrcSize(); i++)
324 {
325 Ice::Operand *src = instruction->getSrc(i);
326
327 const auto &srcEntry = uses.find(src);
328
329 if(srcEntry != uses.end())
330 {
331 auto &srcUses = srcEntry->second;
332
333 srcUses.erase(instruction);
334
335 if(srcUses.empty())
336 {
337 uses.erase(srcEntry);
338
339 if(Ice::Variable *var = llvm::dyn_cast<Ice::Variable>(src))
340 {
341 deleteInstruction(definition[var]);
342 }
343 }
344 }
345 }
346 }
347
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500348 bool Optimizer::isLoad(const Ice::Inst &instruction)
349 {
350 if(llvm::isa<Ice::InstLoad>(&instruction))
351 {
352 return true;
353 }
354
355 if(auto intrinsicCall = llvm::dyn_cast<Ice::InstIntrinsicCall>(&instruction))
356 {
357 return intrinsicCall->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector;
358 }
359
360 return false;
361 }
362
363 bool Optimizer::isStore(const Ice::Inst &instruction)
364 {
365 if(llvm::isa<Ice::InstStore>(&instruction))
366 {
367 return true;
368 }
369
370 if(auto intrinsicCall = llvm::dyn_cast<Ice::InstIntrinsicCall>(&instruction))
371 {
372 return intrinsicCall->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector;
373 }
374
375 return false;
376 }
377
378 Ice::Operand *Optimizer::storeAddress(const Ice::Inst *instruction)
379 {
380 assert(isStore(*instruction));
381
382 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
383 {
384 return store->getAddr();
385 }
386
387 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
388 {
389 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector)
390 {
391 return instrinsic->getSrc(2);
392 }
393 }
394
395 return nullptr;
396 }
397
398 Ice::Operand *Optimizer::loadAddress(const Ice::Inst *instruction)
399 {
400 assert(isLoad(*instruction));
401
402 if(auto *load = llvm::dyn_cast<Ice::InstLoad>(instruction))
403 {
404 return load->getSourceAddress();
405 }
406
407 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
408 {
409 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector)
410 {
411 return instrinsic->getSrc(1);
412 }
413 }
414
415 return nullptr;
416 }
417
Nicolas Capense205c3d2016-11-30 15:14:28 -0500418 Ice::Operand *Optimizer::storeData(const Ice::Inst *instruction)
419 {
420 assert(isStore(*instruction));
421
422 if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
423 {
424 return store->getData();
425 }
426
427 if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
428 {
429 if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector)
430 {
431 return instrinsic->getSrc(1);
432 }
433 }
434
435 return nullptr;
436 }
437
Nicolas Capensf4452fc2016-12-12 13:08:06 -0500438 bool Optimizer::Uses::areOnlyLoadStore() const
439 {
440 return size() == (loads.size() + stores.size());
441 }
442
443 void Optimizer::Uses::insert(Ice::Operand *value, Ice::Inst *instruction)
444 {
445 push_back(instruction);
446
447 if(isLoad(*instruction))
448 {
449 if(value == loadAddress(instruction))
450 {
451 loads.push_back(instruction);
452 }
453 }
454 else if(isStore(*instruction))
455 {
456 if(value == storeAddress(instruction))
457 {
458 stores.push_back(instruction);
459 }
460 }
461 }
462
463 void Optimizer::Uses::erase(Ice::Inst *instruction)
464 {
465 auto &uses = *this;
466
467 for(int i = 0; i < uses.size(); i++)
468 {
469 if(uses[i] == instruction)
470 {
471 uses[i] = back();
472 pop_back();
473
474 for(int i = 0; i < loads.size(); i++)
475 {
476 if(loads[i] == instruction)
477 {
478 loads[i] = loads.back();
479 loads.pop_back();
480 break;
481 }
482 }
483
484 for(int i = 0; i < stores.size(); i++)
485 {
486 if(stores[i] == instruction)
487 {
488 stores[i] = stores.back();
489 stores.pop_back();
490 break;
491 }
492 }
493
494 break;
495 }
496 }
497 }
Nicolas Capens2ae9d742016-11-24 14:43:05 -0500498}
499
500namespace sw
501{
502 void optimize(Ice::Cfg *function)
503 {
504 Optimizer optimizer;
505
506 optimizer.run(function);
507 }
508}