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 "llvm/ADT/Statistic.h" 20 #include "llvm/Support/Debug.h" 21 #define DEBUG_TYPE "polly-simplify" 22 23 using namespace llvm; 24 using namespace polly; 25 26 namespace { 27 28 STATISTIC(ScopsProcessed, "Number of SCoPs processed"); 29 STATISTIC(ScopsModified, "Number of SCoPs simplified"); 30 31 STATISTIC(PairUnequalAccRels, "Number of Load-Store pairs NOT removed because " 32 "of different access relations"); 33 STATISTIC(InBetweenStore, "Number of Load-Store pairs NOT removed because " 34 "there is another store between them"); 35 STATISTIC(TotalOverwritesRemoved, "Number of removed overwritten writes"); 36 STATISTIC(TotalRedundantWritesRemoved, 37 "Number of writes of same value removed in any SCoP"); 38 STATISTIC(TotalStmtsRemoved, "Number of statements removed in any SCoP"); 39 40 static bool isImplicitRead(MemoryAccess *MA) { 41 return MA->isRead() && MA->isOriginalScalarKind(); 42 } 43 44 static bool isExplicitAccess(MemoryAccess *MA) { 45 return MA->isOriginalArrayKind(); 46 } 47 48 static bool isImplicitWrite(MemoryAccess *MA) { 49 return MA->isWrite() && MA->isOriginalScalarKind(); 50 } 51 52 /// Return a vector that contains MemoryAccesses in the order in 53 /// which they are executed. 54 /// 55 /// The order is: 56 /// - Implicit reads (BlockGenerator::generateScalarLoads) 57 /// - Explicit reads and writes (BlockGenerator::generateArrayLoad, 58 /// BlockGenerator::generateArrayStore) 59 /// - In block statements, the accesses are in order in which their 60 /// instructions are executed. 61 /// - In region statements, that order of execution is not predictable at 62 /// compile-time. 63 /// - Implicit writes (BlockGenerator::generateScalarStores) 64 /// The order in which implicit writes are executed relative to each other is 65 /// undefined. 66 static SmallVector<MemoryAccess *, 32> getAccessesInOrder(ScopStmt &Stmt) { 67 68 SmallVector<MemoryAccess *, 32> Accesses; 69 70 for (MemoryAccess *MemAcc : Stmt) 71 if (isImplicitRead(MemAcc)) 72 Accesses.push_back(MemAcc); 73 74 for (MemoryAccess *MemAcc : Stmt) 75 if (isExplicitAccess(MemAcc)) 76 Accesses.push_back(MemAcc); 77 78 for (MemoryAccess *MemAcc : Stmt) 79 if (isImplicitWrite(MemAcc)) 80 Accesses.push_back(MemAcc); 81 82 return Accesses; 83 } 84 85 class Simplify : public ScopPass { 86 private: 87 /// The last/current SCoP that is/has been processed. 88 Scop *S; 89 90 /// Number of writes that are overwritten anyway. 91 int OverwritesRemoved = 0; 92 93 /// Number of redundant writes removed from this SCoP. 94 int RedundantWritesRemoved = 0; 95 96 /// Number of unnecessary statements removed from the SCoP. 97 int StmtsRemoved = 0; 98 99 /// Return whether at least one simplification has been applied. 100 bool isModified() const { 101 return OverwritesRemoved > 0 || RedundantWritesRemoved > 0 || 102 StmtsRemoved > 0; 103 } 104 105 MemoryAccess *getReadAccessForValue(ScopStmt *Stmt, llvm::Value *Val) { 106 if (!isa<Instruction>(Val)) 107 return nullptr; 108 109 for (auto *MA : *Stmt) { 110 if (!MA->isRead()) 111 continue; 112 if (MA->getAccessValue() != Val) 113 continue; 114 115 return MA; 116 } 117 118 return nullptr; 119 } 120 121 /// Return a write access that occurs between @p From and @p To. 122 /// 123 /// In region statements the order is ignored because we cannot predict it. 124 /// 125 /// @param Stmt Statement of both writes. 126 /// @param From Start looking after this access. 127 /// @param To Stop looking at this access, with the access itself. 128 /// @param Targets Look for an access that may wrote to one of these elements. 129 /// 130 /// @return A write access between @p From and @p To that writes to at least 131 /// one element in @p Targets. 132 MemoryAccess *hasWriteBetween(ScopStmt *Stmt, MemoryAccess *From, 133 MemoryAccess *To, isl::map Targets) { 134 auto TargetsSpace = Targets.get_space(); 135 136 bool Started = Stmt->isRegionStmt(); 137 for (auto *Acc : *Stmt) { 138 if (Acc->isLatestScalarKind()) 139 continue; 140 141 if (Stmt->isBlockStmt() && From == Acc) { 142 assert(!Started); 143 Started = true; 144 continue; 145 } 146 if (Stmt->isBlockStmt() && To == Acc) { 147 assert(Started); 148 return nullptr; 149 } 150 if (!Started) 151 continue; 152 153 if (!Acc->isWrite()) 154 continue; 155 156 auto AccRel = give(Acc->getAccessRelation()); 157 auto AccRelSpace = AccRel.get_space(); 158 159 // Spaces being different means that they access different arrays. 160 if (!TargetsSpace.has_equal_tuples(AccRelSpace)) 161 continue; 162 163 AccRel = AccRel.intersect_domain(give(Acc->getStatement()->getDomain())); 164 AccRel = AccRel.intersect_params(give(S->getContext())); 165 auto CommonElt = Targets.intersect(AccRel); 166 if (!CommonElt.is_empty()) 167 return Acc; 168 } 169 assert(Stmt->isRegionStmt() && 170 "To must be encountered in block statements"); 171 return nullptr; 172 } 173 174 /// Remove writes that are overwritten unconditionally later in the same 175 /// statement. 176 /// 177 /// There must be no read of the same value between the write (that is to be 178 /// removed) and the overwrite. 179 void removeOverwrites() { 180 for (auto &Stmt : *S) { 181 auto Domain = give(Stmt.getDomain()); 182 isl::union_map WillBeOverwritten = 183 isl::union_map::empty(give(S->getParamSpace())); 184 185 SmallVector<MemoryAccess *, 32> Accesses(getAccessesInOrder(Stmt)); 186 187 // Iterate in reverse order, so the overwrite comes before the write that 188 // is to be removed. 189 for (auto *MA : reverse(Accesses)) { 190 191 // In region statements, the explicit accesses can be in blocks that are 192 // can be executed in any order. We therefore process only the implicit 193 // writes and stop after that. 194 if (Stmt.isRegionStmt() && isExplicitAccess(MA)) 195 break; 196 197 auto AccRel = give(MA->getAccessRelation()); 198 AccRel = AccRel.intersect_domain(Domain); 199 AccRel = AccRel.intersect_params(give(S->getContext())); 200 201 // If a value is read in-between, do not consider it as overwritten. 202 if (MA->isRead()) { 203 WillBeOverwritten = WillBeOverwritten.subtract(AccRel); 204 continue; 205 } 206 207 // If all of a write's elements are overwritten, remove it. 208 isl::union_map AccRelUnion = AccRel; 209 if (AccRelUnion.is_subset(WillBeOverwritten)) { 210 DEBUG(dbgs() << "Removing " << MA 211 << " which will be overwritten anyway\n"); 212 213 Stmt.removeSingleMemoryAccess(MA); 214 OverwritesRemoved++; 215 TotalOverwritesRemoved++; 216 } 217 218 // Unconditional writes overwrite other values. 219 if (MA->isMustWrite()) 220 WillBeOverwritten = WillBeOverwritten.add_map(AccRel); 221 } 222 } 223 } 224 225 /// Remove writes that just write the same value already stored in the 226 /// element. 227 void removeRedundantWrites() { 228 // Delay actual removal to not invalidate iterators. 229 SmallVector<MemoryAccess *, 8> StoresToRemove; 230 231 for (auto &Stmt : *S) { 232 for (auto *WA : Stmt) { 233 if (!WA->isMustWrite()) 234 continue; 235 if (!WA->isLatestArrayKind()) 236 continue; 237 if (!isa<StoreInst>(WA->getAccessInstruction())) 238 continue; 239 240 auto ReadingValue = WA->getAccessValue(); 241 if (!ReadingValue) 242 continue; 243 244 auto RA = getReadAccessForValue(&Stmt, ReadingValue); 245 if (!RA) 246 continue; 247 if (!RA->isLatestArrayKind()) 248 continue; 249 250 auto WARel = give(WA->getLatestAccessRelation()); 251 WARel = WARel.intersect_domain(give(WA->getStatement()->getDomain())); 252 WARel = WARel.intersect_params(give(S->getContext())); 253 auto RARel = give(RA->getLatestAccessRelation()); 254 RARel = RARel.intersect_domain(give(RA->getStatement()->getDomain())); 255 RARel = RARel.intersect_params(give(S->getContext())); 256 257 if (!RARel.is_equal(WARel)) { 258 PairUnequalAccRels++; 259 DEBUG(dbgs() << "Not cleaning up " << WA 260 << " because of unequal access relations:\n"); 261 DEBUG(dbgs() << " RA: " << RARel << "\n"); 262 DEBUG(dbgs() << " WA: " << WARel << "\n"); 263 continue; 264 } 265 266 if (auto *Conflicting = hasWriteBetween(&Stmt, RA, WA, WARel)) { 267 (void)Conflicting; 268 InBetweenStore++; 269 DEBUG(dbgs() << "Not cleaning up " << WA 270 << " because there is another store to the same element " 271 "between\n"); 272 DEBUG(Conflicting->print(dbgs())); 273 continue; 274 } 275 276 StoresToRemove.push_back(WA); 277 } 278 } 279 280 for (auto *WA : StoresToRemove) { 281 auto Stmt = WA->getStatement(); 282 auto AccRel = give(WA->getAccessRelation()); 283 auto AccVal = WA->getAccessValue(); 284 285 DEBUG(dbgs() << "Cleanup of " << WA << ":\n"); 286 DEBUG(dbgs() << " Scalar: " << *AccVal << "\n"); 287 DEBUG(dbgs() << " AccRel: " << AccRel << "\n"); 288 (void)AccVal; 289 (void)AccRel; 290 291 Stmt->removeSingleMemoryAccess(WA); 292 293 RedundantWritesRemoved++; 294 TotalRedundantWritesRemoved++; 295 } 296 } 297 298 /// Remove statements without side effects. 299 void removeUnnecessayStmts() { 300 auto NumStmtsBefore = S->getSize(); 301 S->simplifySCoP(true); 302 assert(NumStmtsBefore >= S->getSize()); 303 StmtsRemoved = NumStmtsBefore - S->getSize(); 304 DEBUG(dbgs() << "Removed " << StmtsRemoved << " (of " << NumStmtsBefore 305 << ") statements\n"); 306 TotalStmtsRemoved += StmtsRemoved; 307 } 308 309 /// Print simplification statistics to @p OS. 310 void printStatistics(llvm::raw_ostream &OS, int Indent = 0) const { 311 OS.indent(Indent) << "Statistics {\n"; 312 OS.indent(Indent + 4) << "Overwrites removed: " << OverwritesRemoved 313 << '\n'; 314 OS.indent(Indent + 4) << "Redundant writes removed: " 315 << RedundantWritesRemoved << "\n"; 316 OS.indent(Indent + 4) << "Stmts removed: " << StmtsRemoved << "\n"; 317 OS.indent(Indent) << "}\n"; 318 } 319 320 /// Print the current state of all MemoryAccesses to @p OS. 321 void printAccesses(llvm::raw_ostream &OS, int Indent = 0) const { 322 OS.indent(Indent) << "After accesses {\n"; 323 for (auto &Stmt : *S) { 324 OS.indent(Indent + 4) << Stmt.getBaseName() << "\n"; 325 for (auto *MA : Stmt) 326 MA->print(OS); 327 } 328 OS.indent(Indent) << "}\n"; 329 } 330 331 public: 332 static char ID; 333 explicit Simplify() : ScopPass(ID) {} 334 335 virtual void getAnalysisUsage(AnalysisUsage &AU) const override { 336 AU.addRequiredTransitive<ScopInfoRegionPass>(); 337 AU.setPreservesAll(); 338 } 339 340 virtual bool runOnScop(Scop &S) override { 341 // Reset statistics of last processed SCoP. 342 releaseMemory(); 343 344 // Prepare processing of this SCoP. 345 this->S = &S; 346 ScopsProcessed++; 347 348 DEBUG(dbgs() << "Removing overwrites...\n"); 349 removeOverwrites(); 350 351 DEBUG(dbgs() << "Removing redundant writes...\n"); 352 removeRedundantWrites(); 353 354 DEBUG(dbgs() << "Removing statements without side effects...\n"); 355 removeUnnecessayStmts(); 356 357 if (isModified()) 358 ScopsModified++; 359 DEBUG(dbgs() << "\nFinal Scop:\n"); 360 DEBUG(S.print(dbgs())); 361 362 return false; 363 } 364 365 virtual void printScop(raw_ostream &OS, Scop &S) const override { 366 assert(&S == this->S && 367 "Can only print analysis for the last processed SCoP"); 368 printStatistics(OS); 369 370 if (!isModified()) { 371 OS << "SCoP could not be simplified\n"; 372 return; 373 } 374 printAccesses(OS); 375 } 376 377 virtual void releaseMemory() override { 378 S = nullptr; 379 380 OverwritesRemoved = 0; 381 RedundantWritesRemoved = 0; 382 StmtsRemoved = 0; 383 } 384 }; 385 386 char Simplify::ID; 387 } // anonymous namespace 388 389 Pass *polly::createSimplifyPass() { return new Simplify(); } 390 391 INITIALIZE_PASS_BEGIN(Simplify, "polly-simplify", "Polly - Simplify", false, 392 false) 393 INITIALIZE_PASS_END(Simplify, "polly-simplify", "Polly - Simplify", false, 394 false) 395