1 //===------ Simplify.cpp ----------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Simplify a SCoP by removing unnecessary statements and accesses. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "polly/Simplify.h" 15 #include "polly/ScopInfo.h" 16 #include "polly/ScopPass.h" 17 #include "polly/Support/GICHelper.h" 18 #include "polly/Support/ISLOStream.h" 19 #include "polly/Support/ISLTools.h" 20 #include "polly/Support/VirtualInstruction.h" 21 #include "llvm/ADT/Statistic.h" 22 #include "llvm/Support/Debug.h" 23 #define DEBUG_TYPE "polly-simplify" 24 25 using namespace llvm; 26 using namespace polly; 27 28 namespace { 29 30 #define TWO_STATISTICS(VARNAME, DESC) \ 31 static llvm::Statistic VARNAME[2] = { \ 32 {DEBUG_TYPE, #VARNAME "0", DESC " (first)", {0}, false}, \ 33 {DEBUG_TYPE, #VARNAME "1", DESC " (second)", {0}, false}} 34 35 /// Number of max disjuncts we allow in removeOverwrites(). This is to avoid 36 /// that the analysis of accesses in a statement is becoming too complex. Chosen 37 /// to be relatively small because all the common cases should access only few 38 /// array elements per statement. 39 static int const SimplifyMaxDisjuncts = 4; 40 41 TWO_STATISTICS(ScopsProcessed, "Number of SCoPs processed"); 42 TWO_STATISTICS(ScopsModified, "Number of SCoPs simplified"); 43 44 TWO_STATISTICS(TotalOverwritesRemoved, "Number of removed overwritten writes"); 45 TWO_STATISTICS(TotalWritesCoalesced, "Number of writes coalesced with another"); 46 TWO_STATISTICS(TotalRedundantWritesRemoved, 47 "Number of writes of same value removed in any SCoP"); 48 TWO_STATISTICS(TotalEmptyPartialAccessesRemoved, 49 "Number of empty partial accesses removed"); 50 TWO_STATISTICS(TotalDeadAccessesRemoved, "Number of dead accesses removed"); 51 TWO_STATISTICS(TotalDeadInstructionsRemoved, 52 "Number of unused instructions removed"); 53 TWO_STATISTICS(TotalStmtsRemoved, "Number of statements removed in any SCoP"); 54 55 TWO_STATISTICS(NumValueWrites, "Number of scalar value writes after Simplify"); 56 TWO_STATISTICS( 57 NumValueWritesInLoops, 58 "Number of scalar value writes nested in affine loops after Simplify"); 59 TWO_STATISTICS(NumPHIWrites, 60 "Number of scalar phi writes after the first simplification"); 61 TWO_STATISTICS( 62 NumPHIWritesInLoops, 63 "Number of scalar phi writes nested in affine loops after Simplify"); 64 TWO_STATISTICS(NumSingletonWrites, "Number of singleton writes after Simplify"); 65 TWO_STATISTICS( 66 NumSingletonWritesInLoops, 67 "Number of singleton writes nested in affine loops after Simplify"); 68 69 static bool isImplicitRead(MemoryAccess *MA) { 70 return MA->isRead() && MA->isOriginalScalarKind(); 71 } 72 73 static bool isExplicitAccess(MemoryAccess *MA) { 74 return MA->isOriginalArrayKind(); 75 } 76 77 static bool isImplicitWrite(MemoryAccess *MA) { 78 return MA->isWrite() && MA->isOriginalScalarKind(); 79 } 80 81 /// Like isl::union_map::add_map, but may also return an underapproximated 82 /// result if getting too complex. 83 /// 84 /// This is implemented by adding disjuncts to the results until the limit is 85 /// reached. 86 static isl::union_map underapproximatedAddMap(isl::union_map UMap, 87 isl::map Map) { 88 if (UMap.is_null() || Map.is_null()) 89 return {}; 90 91 isl::map PrevMap = UMap.extract_map(Map.get_space()); 92 93 // Fast path: If known that we cannot exceed the disjunct limit, just add 94 // them. 95 if (isl_map_n_basic_map(PrevMap.get()) + isl_map_n_basic_map(Map.get()) <= 96 SimplifyMaxDisjuncts) 97 return UMap.add_map(Map); 98 99 isl::map Result = isl::map::empty(PrevMap.get_space()); 100 PrevMap.foreach_basic_map([&Result](isl::basic_map BMap) -> isl::stat { 101 if (isl_map_n_basic_map(Result.get()) > SimplifyMaxDisjuncts) 102 return isl::stat::error; 103 Result = Result.unite(BMap); 104 return isl::stat::ok; 105 }); 106 Map.foreach_basic_map([&Result](isl::basic_map BMap) -> isl::stat { 107 if (isl_map_n_basic_map(Result.get()) > SimplifyMaxDisjuncts) 108 return isl::stat::error; 109 Result = Result.unite(BMap); 110 return isl::stat::ok; 111 }); 112 113 isl::union_map UResult = 114 UMap.subtract(isl::map::universe(PrevMap.get_space())); 115 UResult.add_map(Result); 116 117 return UResult; 118 } 119 120 class Simplify : public ScopPass { 121 private: 122 /// The invocation id (if there are multiple instances in the pass manager's 123 /// pipeline) to determine which statistics to update. 124 int CallNo; 125 126 /// The last/current SCoP that is/has been processed. 127 Scop *S; 128 129 /// Number of writes that are overwritten anyway. 130 int OverwritesRemoved = 0; 131 132 /// Number of combined writes. 133 int WritesCoalesced = 0; 134 135 /// Number of redundant writes removed from this SCoP. 136 int RedundantWritesRemoved = 0; 137 138 /// Number of writes with empty access domain removed. 139 int EmptyPartialAccessesRemoved = 0; 140 141 /// Number of unused accesses removed from this SCoP. 142 int DeadAccessesRemoved = 0; 143 144 /// Number of unused instructions removed from this SCoP. 145 int DeadInstructionsRemoved = 0; 146 147 /// Number of unnecessary statements removed from the SCoP. 148 int StmtsRemoved = 0; 149 150 /// Return whether at least one simplification has been applied. 151 bool isModified() const { 152 return OverwritesRemoved > 0 || WritesCoalesced > 0 || 153 RedundantWritesRemoved > 0 || EmptyPartialAccessesRemoved > 0 || 154 DeadAccessesRemoved > 0 || DeadInstructionsRemoved > 0 || 155 StmtsRemoved > 0; 156 } 157 158 /// Remove writes that are overwritten unconditionally later in the same 159 /// statement. 160 /// 161 /// There must be no read of the same value between the write (that is to be 162 /// removed) and the overwrite. 163 void removeOverwrites() { 164 for (auto &Stmt : *S) { 165 isl::set Domain = Stmt.getDomain(); 166 isl::union_map WillBeOverwritten = 167 isl::union_map::empty(S->getParamSpace()); 168 169 SmallVector<MemoryAccess *, 32> Accesses(getAccessesInOrder(Stmt)); 170 171 // Iterate in reverse order, so the overwrite comes before the write that 172 // is to be removed. 173 for (auto *MA : reverse(Accesses)) { 174 175 // In region statements, the explicit accesses can be in blocks that are 176 // can be executed in any order. We therefore process only the implicit 177 // writes and stop after that. 178 if (Stmt.isRegionStmt() && isExplicitAccess(MA)) 179 break; 180 181 auto AccRel = MA->getAccessRelation(); 182 AccRel = AccRel.intersect_domain(Domain); 183 AccRel = AccRel.intersect_params(S->getContext()); 184 185 // If a value is read in-between, do not consider it as overwritten. 186 if (MA->isRead()) { 187 // Invalidate all overwrites for the array it accesses to avoid too 188 // complex isl sets. 189 isl::map AccRelUniv = isl::map::universe(AccRel.get_space()); 190 WillBeOverwritten = WillBeOverwritten.subtract(AccRelUniv); 191 continue; 192 } 193 194 // If all of a write's elements are overwritten, remove it. 195 isl::union_map AccRelUnion = AccRel; 196 if (AccRelUnion.is_subset(WillBeOverwritten)) { 197 DEBUG(dbgs() << "Removing " << MA 198 << " which will be overwritten anyway\n"); 199 200 Stmt.removeSingleMemoryAccess(MA); 201 OverwritesRemoved++; 202 TotalOverwritesRemoved[CallNo]++; 203 } 204 205 // Unconditional writes overwrite other values. 206 if (MA->isMustWrite()) { 207 // Avoid too complex isl sets. If necessary, throw away some of the 208 // knowledge. 209 WillBeOverwritten = 210 underapproximatedAddMap(WillBeOverwritten, AccRel); 211 } 212 } 213 } 214 } 215 216 /// Combine writes that write the same value if possible. 217 /// 218 /// This function is able to combine: 219 /// - Partial writes with disjoint domain. 220 /// - Writes that write to the same array element. 221 /// 222 /// In all cases, both writes must write the same values. 223 void coalesceWrites() { 224 for (auto &Stmt : *S) { 225 isl::set Domain = Stmt.getDomain().intersect_params(S->getContext()); 226 227 // We let isl do the lookup for the same-value condition. For this, we 228 // wrap llvm::Value into an isl::set such that isl can do the lookup in 229 // its hashtable implementation. llvm::Values are only compared within a 230 // ScopStmt, so the map can be local to this scope. TODO: Refactor with 231 // ZoneAlgorithm::makeValueSet() 232 SmallDenseMap<Value *, isl::set> ValueSets; 233 auto makeValueSet = [&ValueSets, this](Value *V) -> isl::set { 234 assert(V); 235 isl::set &Result = ValueSets[V]; 236 if (Result.is_null()) { 237 isl::ctx Ctx = S->getIslCtx(); 238 std::string Name = 239 getIslCompatibleName("Val", V, ValueSets.size() - 1, 240 std::string(), UseInstructionNames); 241 isl::id Id = isl::id::alloc(Ctx, Name, V); 242 Result = isl::set::universe( 243 isl::space(Ctx, 0, 0).set_tuple_id(isl::dim::set, Id)); 244 } 245 return Result; 246 }; 247 248 // List of all eligible (for coalescing) writes of the future. 249 // { [Domain[] -> Element[]] -> [Value[] -> MemoryAccess[]] } 250 isl::union_map FutureWrites = isl::union_map::empty(S->getParamSpace()); 251 252 // Iterate over accesses from the last to the first. 253 SmallVector<MemoryAccess *, 32> Accesses(getAccessesInOrder(Stmt)); 254 for (MemoryAccess *MA : reverse(Accesses)) { 255 // In region statements, the explicit accesses can be in blocks that can 256 // be executed in any order. We therefore process only the implicit 257 // writes and stop after that. 258 if (Stmt.isRegionStmt() && isExplicitAccess(MA)) 259 break; 260 261 // { Domain[] -> Element[] } 262 isl::map AccRel = 263 MA->getLatestAccessRelation().intersect_domain(Domain); 264 265 // { [Domain[] -> Element[]] } 266 isl::set AccRelWrapped = AccRel.wrap(); 267 268 // { Value[] } 269 isl::set ValSet; 270 271 if (MA->isMustWrite() && (MA->isOriginalScalarKind() || 272 isa<StoreInst>(MA->getAccessInstruction()))) { 273 // Normally, tryGetValueStored() should be used to determine which 274 // element is written, but it can return nullptr; For PHI accesses, 275 // getAccessValue() returns the PHI instead of the PHI's incoming 276 // value. In this case, where we only compare values of a single 277 // statement, this is fine, because within a statement, a PHI in a 278 // successor block has always the same value as the incoming write. We 279 // still preferably use the incoming value directly so we also catch 280 // direct uses of that. 281 Value *StoredVal = MA->tryGetValueStored(); 282 if (!StoredVal) 283 StoredVal = MA->getAccessValue(); 284 ValSet = makeValueSet(StoredVal); 285 286 // { Domain[] } 287 isl::set AccDomain = AccRel.domain(); 288 289 // Parts of the statement's domain that is not written by this access. 290 isl::set UndefDomain = Domain.subtract(AccDomain); 291 292 // { Element[] } 293 isl::set ElementUniverse = 294 isl::set::universe(AccRel.get_space().range()); 295 296 // { Domain[] -> Element[] } 297 isl::map UndefAnything = 298 isl::map::from_domain_and_range(UndefDomain, ElementUniverse); 299 300 // We are looking a compatible write access. The other write can 301 // access these elements... 302 isl::map AllowedAccesses = AccRel.unite(UndefAnything); 303 304 // ... and must write the same value. 305 // { [Domain[] -> Element[]] -> Value[] } 306 isl::map Filter = 307 isl::map::from_domain_and_range(AllowedAccesses.wrap(), ValSet); 308 309 // Lookup future write that fulfills these conditions. 310 // { [[Domain[] -> Element[]] -> Value[]] -> MemoryAccess[] } 311 isl::union_map Filtered = 312 FutureWrites.uncurry().intersect_domain(Filter.wrap()); 313 314 // Iterate through the candidates. 315 Filtered.foreach_map([&, this](isl::map Map) -> isl::stat { 316 MemoryAccess *OtherMA = (MemoryAccess *)Map.get_space() 317 .get_tuple_id(isl::dim::out) 318 .get_user(); 319 320 isl::map OtherAccRel = 321 OtherMA->getLatestAccessRelation().intersect_domain(Domain); 322 323 // The filter only guaranteed that some of OtherMA's accessed 324 // elements are allowed. Verify that it only accesses allowed 325 // elements. Otherwise, continue with the next candidate. 326 if (!OtherAccRel.is_subset(AllowedAccesses).is_true()) 327 return isl::stat::ok; 328 329 // The combined access relation. 330 // { Domain[] -> Element[] } 331 isl::map NewAccRel = AccRel.unite(OtherAccRel); 332 simplify(NewAccRel); 333 334 // Carry out the coalescing. 335 Stmt.removeSingleMemoryAccess(MA); 336 OtherMA->setNewAccessRelation(NewAccRel); 337 338 // We removed MA, OtherMA takes its role. 339 MA = OtherMA; 340 341 TotalWritesCoalesced[CallNo]++; 342 WritesCoalesced++; 343 344 // Don't look for more candidates. 345 return isl::stat::error; 346 }); 347 } 348 349 // Two writes cannot be coalesced if there is another access (to some of 350 // the written elements) between them. Remove all visited write accesses 351 // from the list of eligible writes. Don't just remove the accessed 352 // elements, but any MemoryAccess that touches any of the invalidated 353 // elements. 354 SmallPtrSet<MemoryAccess *, 2> TouchedAccesses; 355 FutureWrites.intersect_domain(AccRelWrapped) 356 .foreach_map([&TouchedAccesses](isl::map Map) -> isl::stat { 357 MemoryAccess *MA = (MemoryAccess *)Map.get_space() 358 .range() 359 .unwrap() 360 .get_tuple_id(isl::dim::out) 361 .get_user(); 362 TouchedAccesses.insert(MA); 363 return isl::stat::ok; 364 }); 365 isl::union_map NewFutureWrites = 366 isl::union_map::empty(FutureWrites.get_space()); 367 FutureWrites.foreach_map([&TouchedAccesses, &NewFutureWrites]( 368 isl::map FutureWrite) -> isl::stat { 369 MemoryAccess *MA = (MemoryAccess *)FutureWrite.get_space() 370 .range() 371 .unwrap() 372 .get_tuple_id(isl::dim::out) 373 .get_user(); 374 if (!TouchedAccesses.count(MA)) 375 NewFutureWrites = NewFutureWrites.add_map(FutureWrite); 376 return isl::stat::ok; 377 }); 378 FutureWrites = NewFutureWrites; 379 380 if (MA->isMustWrite() && !ValSet.is_null()) { 381 // { MemoryAccess[] } 382 auto AccSet = 383 isl::set::universe(isl::space(S->getIslCtx(), 0, 0) 384 .set_tuple_id(isl::dim::set, MA->getId())); 385 386 // { Val[] -> MemoryAccess[] } 387 isl::map ValAccSet = isl::map::from_domain_and_range(ValSet, AccSet); 388 389 // { [Domain[] -> Element[]] -> [Value[] -> MemoryAccess[]] } 390 isl::map AccRelValAcc = 391 isl::map::from_domain_and_range(AccRelWrapped, ValAccSet.wrap()); 392 FutureWrites = FutureWrites.add_map(AccRelValAcc); 393 } 394 } 395 } 396 } 397 398 /// Remove writes that just write the same value already stored in the 399 /// element. 400 void removeRedundantWrites() { 401 for (auto &Stmt : *S) { 402 SmallDenseMap<Value *, isl::set> ValueSets; 403 auto makeValueSet = [&ValueSets, this](Value *V) -> isl::set { 404 assert(V); 405 isl::set &Result = ValueSets[V]; 406 if (Result.is_null()) { 407 isl_ctx *Ctx = S->getIslCtx().get(); 408 std::string Name = 409 getIslCompatibleName("Val", V, ValueSets.size() - 1, 410 std::string(), UseInstructionNames); 411 isl::id Id = give(isl_id_alloc(Ctx, Name.c_str(), V)); 412 Result = isl::set::universe( 413 isl::space(Ctx, 0, 0).set_tuple_id(isl::dim::set, Id)); 414 } 415 return Result; 416 }; 417 418 isl::set Domain = Stmt.getDomain(); 419 Domain = Domain.intersect_params(S->getContext()); 420 421 // List of element reads that still have the same value while iterating 422 // through the MemoryAccesses. 423 // { [Domain[] -> Element[]] -> Val[] } 424 isl::union_map Known = isl::union_map::empty(S->getParamSpace()); 425 426 SmallVector<MemoryAccess *, 32> Accesses(getAccessesInOrder(Stmt)); 427 for (MemoryAccess *MA : Accesses) { 428 // Is the memory access in a defined order relative to the other 429 // accesses? In region statements, only the first and the last accesses 430 // have defined order. Execution of those in the middle may depend on 431 // runtime conditions an therefore cannot be modified. 432 bool IsOrdered = 433 Stmt.isBlockStmt() || MA->isOriginalScalarKind() || 434 (!S->getBoxedLoops().size() && MA->getAccessInstruction() && 435 Stmt.getEntryBlock() == MA->getAccessInstruction()->getParent()); 436 437 isl::map AccRel = MA->getAccessRelation(); 438 AccRel = AccRel.intersect_domain(Domain); 439 isl::set AccRelWrapped = AccRel.wrap(); 440 441 // Determine whether a write is redundant (stores only values that are 442 // already present in the written array elements) and remove it if this 443 // is the case. 444 if (IsOrdered && MA->isMustWrite() && 445 (isa<StoreInst>(MA->getAccessInstruction()) || 446 MA->isOriginalScalarKind())) { 447 Value *StoredVal = MA->tryGetValueStored(); 448 if (!StoredVal) 449 StoredVal = MA->getAccessValue(); 450 451 if (StoredVal) { 452 // Lookup in the set of known values. 453 isl::map AccRelStoredVal = isl::map::from_domain_and_range( 454 AccRelWrapped, makeValueSet(StoredVal)); 455 if (isl::union_map(AccRelStoredVal).is_subset(Known)) { 456 DEBUG(dbgs() << "Cleanup of " << MA << ":\n"); 457 DEBUG(dbgs() << " Scalar: " << *StoredVal << "\n"); 458 DEBUG(dbgs() << " AccRel: " << AccRel << "\n"); 459 460 Stmt.removeSingleMemoryAccess(MA); 461 462 RedundantWritesRemoved++; 463 TotalRedundantWritesRemoved[CallNo]++; 464 } 465 } 466 } 467 468 // Update the know values set. 469 if (MA->isRead()) { 470 // Loaded values are the currently known values of the array element 471 // it was loaded from. 472 Value *LoadedVal = MA->getAccessValue(); 473 if (LoadedVal && IsOrdered) { 474 isl::map AccRelVal = isl::map::from_domain_and_range( 475 AccRelWrapped, makeValueSet(LoadedVal)); 476 477 Known = Known.add_map(AccRelVal); 478 } 479 } else if (MA->isWrite()) { 480 // Remove (possibly) overwritten values from the known elements set. 481 // We remove all elements of the accessed array to avoid too complex 482 // isl sets. 483 isl::set AccRelUniv = isl::set::universe(AccRelWrapped.get_space()); 484 Known = Known.subtract_domain(AccRelUniv); 485 486 // At this point, we could add the written value of must-writes. 487 // However, writing same values is already handled by 488 // coalesceWrites(). 489 } 490 } 491 } 492 } 493 494 /// Remove statements without side effects. 495 void removeUnnecessaryStmts() { 496 auto NumStmtsBefore = S->getSize(); 497 S->simplifySCoP(true); 498 assert(NumStmtsBefore >= S->getSize()); 499 StmtsRemoved = NumStmtsBefore - S->getSize(); 500 DEBUG(dbgs() << "Removed " << StmtsRemoved << " (of " << NumStmtsBefore 501 << ") statements\n"); 502 TotalStmtsRemoved[CallNo] += StmtsRemoved; 503 } 504 505 /// Remove accesses that have an empty domain. 506 void removeEmptyPartialAccesses() { 507 for (ScopStmt &Stmt : *S) { 508 // Defer the actual removal to not invalidate iterators. 509 SmallVector<MemoryAccess *, 8> DeferredRemove; 510 511 for (MemoryAccess *MA : Stmt) { 512 if (!MA->isWrite()) 513 continue; 514 515 isl::map AccRel = MA->getAccessRelation(); 516 if (!AccRel.is_empty().is_true()) 517 continue; 518 519 DEBUG(dbgs() << "Removing " << MA 520 << " because it's a partial access that never occurs\n"); 521 DeferredRemove.push_back(MA); 522 } 523 524 for (MemoryAccess *MA : DeferredRemove) { 525 Stmt.removeSingleMemoryAccess(MA); 526 EmptyPartialAccessesRemoved++; 527 TotalEmptyPartialAccessesRemoved[CallNo]++; 528 } 529 } 530 } 531 532 /// Mark all reachable instructions and access, and sweep those that are not 533 /// reachable. 534 void markAndSweep(LoopInfo *LI) { 535 DenseSet<MemoryAccess *> UsedMA; 536 DenseSet<VirtualInstruction> UsedInsts; 537 538 // Get all reachable instructions and accesses. 539 markReachable(S, LI, UsedInsts, UsedMA); 540 541 // Remove all non-reachable accesses. 542 // We need get all MemoryAccesses first, in order to not invalidate the 543 // iterators when removing them. 544 SmallVector<MemoryAccess *, 64> AllMAs; 545 for (ScopStmt &Stmt : *S) 546 AllMAs.append(Stmt.begin(), Stmt.end()); 547 548 for (MemoryAccess *MA : AllMAs) { 549 if (UsedMA.count(MA)) 550 continue; 551 DEBUG(dbgs() << "Removing " << MA << " because its value is not used\n"); 552 ScopStmt *Stmt = MA->getStatement(); 553 Stmt->removeSingleMemoryAccess(MA); 554 555 DeadAccessesRemoved++; 556 TotalDeadAccessesRemoved[CallNo]++; 557 } 558 559 // Remove all non-reachable instructions. 560 for (ScopStmt &Stmt : *S) { 561 // Note that for region statements, we can only remove the non-terminator 562 // instructions of the entry block. All other instructions are not in the 563 // instructions list, but implicitly always part of the statement. 564 565 SmallVector<Instruction *, 32> AllInsts(Stmt.insts_begin(), 566 Stmt.insts_end()); 567 SmallVector<Instruction *, 32> RemainInsts; 568 569 for (Instruction *Inst : AllInsts) { 570 auto It = UsedInsts.find({&Stmt, Inst}); 571 if (It == UsedInsts.end()) { 572 DEBUG(dbgs() << "Removing "; Inst->print(dbgs()); 573 dbgs() << " because it is not used\n"); 574 DeadInstructionsRemoved++; 575 TotalDeadInstructionsRemoved[CallNo]++; 576 continue; 577 } 578 579 RemainInsts.push_back(Inst); 580 581 // If instructions appear multiple times, keep only the first. 582 UsedInsts.erase(It); 583 } 584 585 // Set the new instruction list to be only those we did not remove. 586 Stmt.setInstructions(RemainInsts); 587 } 588 } 589 590 /// Print simplification statistics to @p OS. 591 void printStatistics(llvm::raw_ostream &OS, int Indent = 0) const { 592 OS.indent(Indent) << "Statistics {\n"; 593 OS.indent(Indent + 4) << "Overwrites removed: " << OverwritesRemoved 594 << '\n'; 595 OS.indent(Indent + 4) << "Partial writes coalesced: " << WritesCoalesced 596 << "\n"; 597 OS.indent(Indent + 4) << "Redundant writes removed: " 598 << RedundantWritesRemoved << "\n"; 599 OS.indent(Indent + 4) << "Accesses with empty domains removed: " 600 << EmptyPartialAccessesRemoved << "\n"; 601 OS.indent(Indent + 4) << "Dead accesses removed: " << DeadAccessesRemoved 602 << '\n'; 603 OS.indent(Indent + 4) << "Dead instructions removed: " 604 << DeadInstructionsRemoved << '\n'; 605 OS.indent(Indent + 4) << "Stmts removed: " << StmtsRemoved << "\n"; 606 OS.indent(Indent) << "}\n"; 607 } 608 609 /// Print the current state of all MemoryAccesses to @p OS. 610 void printAccesses(llvm::raw_ostream &OS, int Indent = 0) const { 611 OS.indent(Indent) << "After accesses {\n"; 612 for (auto &Stmt : *S) { 613 OS.indent(Indent + 4) << Stmt.getBaseName() << "\n"; 614 for (auto *MA : Stmt) 615 MA->print(OS); 616 } 617 OS.indent(Indent) << "}\n"; 618 } 619 620 public: 621 static char ID; 622 explicit Simplify(int CallNo = 0) : ScopPass(ID), CallNo(CallNo) {} 623 624 virtual void getAnalysisUsage(AnalysisUsage &AU) const override { 625 AU.addRequiredTransitive<ScopInfoRegionPass>(); 626 AU.addRequired<LoopInfoWrapperPass>(); 627 AU.setPreservesAll(); 628 } 629 630 virtual bool runOnScop(Scop &S) override { 631 // Reset statistics of last processed SCoP. 632 releaseMemory(); 633 assert(!isModified()); 634 635 // Prepare processing of this SCoP. 636 this->S = &S; 637 ScopsProcessed[CallNo]++; 638 639 DEBUG(dbgs() << "Removing partial writes that never happen...\n"); 640 removeEmptyPartialAccesses(); 641 642 DEBUG(dbgs() << "Removing overwrites...\n"); 643 removeOverwrites(); 644 645 DEBUG(dbgs() << "Coalesce partial writes...\n"); 646 coalesceWrites(); 647 648 DEBUG(dbgs() << "Removing redundant writes...\n"); 649 removeRedundantWrites(); 650 651 DEBUG(dbgs() << "Cleanup unused accesses...\n"); 652 LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); 653 markAndSweep(LI); 654 655 DEBUG(dbgs() << "Removing statements without side effects...\n"); 656 removeUnnecessaryStmts(); 657 658 if (isModified()) 659 ScopsModified[CallNo]++; 660 DEBUG(dbgs() << "\nFinal Scop:\n"); 661 DEBUG(dbgs() << S); 662 663 auto ScopStats = S.getStatistics(); 664 NumValueWrites[CallNo] += ScopStats.NumValueWrites; 665 NumValueWritesInLoops[CallNo] += ScopStats.NumValueWritesInLoops; 666 NumPHIWrites[CallNo] += ScopStats.NumPHIWrites; 667 NumPHIWritesInLoops[CallNo] += ScopStats.NumPHIWritesInLoops; 668 NumSingletonWrites[CallNo] += ScopStats.NumSingletonWrites; 669 NumSingletonWritesInLoops[CallNo] += ScopStats.NumSingletonWritesInLoops; 670 671 return false; 672 } 673 674 virtual void printScop(raw_ostream &OS, Scop &S) const override { 675 assert(&S == this->S && 676 "Can only print analysis for the last processed SCoP"); 677 printStatistics(OS); 678 679 if (!isModified()) { 680 OS << "SCoP could not be simplified\n"; 681 return; 682 } 683 printAccesses(OS); 684 } 685 686 virtual void releaseMemory() override { 687 S = nullptr; 688 689 OverwritesRemoved = 0; 690 WritesCoalesced = 0; 691 RedundantWritesRemoved = 0; 692 EmptyPartialAccessesRemoved = 0; 693 DeadAccessesRemoved = 0; 694 DeadInstructionsRemoved = 0; 695 StmtsRemoved = 0; 696 } 697 }; 698 699 char Simplify::ID; 700 } // anonymous namespace 701 702 namespace polly { 703 SmallVector<MemoryAccess *, 32> getAccessesInOrder(ScopStmt &Stmt) { 704 705 SmallVector<MemoryAccess *, 32> Accesses; 706 707 for (MemoryAccess *MemAcc : Stmt) 708 if (isImplicitRead(MemAcc)) 709 Accesses.push_back(MemAcc); 710 711 for (MemoryAccess *MemAcc : Stmt) 712 if (isExplicitAccess(MemAcc)) 713 Accesses.push_back(MemAcc); 714 715 for (MemoryAccess *MemAcc : Stmt) 716 if (isImplicitWrite(MemAcc)) 717 Accesses.push_back(MemAcc); 718 719 return Accesses; 720 } 721 } // namespace polly 722 723 Pass *polly::createSimplifyPass(int CallNo) { return new Simplify(CallNo); } 724 725 INITIALIZE_PASS_BEGIN(Simplify, "polly-simplify", "Polly - Simplify", false, 726 false) 727 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) 728 INITIALIZE_PASS_END(Simplify, "polly-simplify", "Polly - Simplify", false, 729 false) 730