26#include "llvm/ADT/Statistic.h"
27#include "llvm/IR/Module.h"
28#include "llvm/InitializePasses.h"
31#define DEBUG_TYPE "polly-delicm"
39 DelicmMaxOps(
"polly-delicm-max-ops",
40 cl::desc(
"Maximum number of isl operations to invest for "
41 "lifetime analysis; 0=no limit"),
44cl::opt<bool> DelicmOverapproximateWrites(
45 "polly-delicm-overapproximate-writes",
47 "Do more PHI writes than necessary in order to avoid partial accesses"),
50cl::opt<bool> DelicmPartialWrites(
"polly-delicm-partial-writes",
51 cl::desc(
"Allow partial writes"),
52 cl::init(
true), cl::Hidden,
56 DelicmComputeKnown(
"polly-delicm-compute-known",
57 cl::desc(
"Compute known content of array elements"),
60STATISTIC(DeLICMAnalyzed,
"Number of successfully analyzed SCoPs");
62 "Analyses aborted because max_operations was reached");
63STATISTIC(MappedValueScalars,
"Number of mapped Value scalars");
64STATISTIC(MappedPHIScalars,
"Number of mapped PHI scalars");
65STATISTIC(TargetsMapped,
"Number of stores used for at least one mapping");
66STATISTIC(DeLICMScopsModified,
"Number of SCoPs optimized");
68STATISTIC(NumValueWrites,
"Number of scalar value writes after DeLICM");
70 "Number of scalar value writes nested in affine loops after DeLICM");
71STATISTIC(NumPHIWrites,
"Number of scalar phi writes after DeLICM");
73 "Number of scalar phi writes nested in affine loops after DeLICM");
74STATISTIC(NumSingletonWrites,
"Number of singleton writes after DeLICM");
76 "Number of singleton writes nested in affine loops after DeLICM");
102 bool InclOverwrite) {
108 auto Result = computeReachingOverwrite(
109 std::move(Schedule), std::move(WritesMap), InclPrevWrite, InclOverwrite);
111 return Result.domain_factor_range();
124 isl::set Writes,
bool InclPrevWrite,
125 bool InclOverwrite) {
133 return singleton(std::move(ReachOverwrite), ResultSpace);
188class Knowledge final {
241 void checkConsistency()
const {
257 auto Universe = Occupied.
unite(Unused);
272 : Occupied(std::move(Occupied)), Unused(std::move(Unused)),
273 Known(std::move(Known)), Written(std::move(Written)) {
278 bool isUsable()
const {
284 void print(llvm::raw_ostream &OS,
unsigned Indent = 0)
const {
287 OS.indent(Indent) <<
"Occupied: " << Occupied <<
"\n";
289 OS.indent(Indent) <<
"Occupied: <Everything else not in Unused>\n";
291 OS.indent(Indent) <<
"Unused: " << Unused <<
"\n";
293 OS.indent(Indent) <<
"Unused: <Everything else not in Occupied>\n";
294 OS.indent(Indent) <<
"Known: " << Known <<
"\n";
295 OS.indent(Indent) <<
"Written : " << Written <<
'\n';
297 OS.indent(Indent) <<
"Invalid knowledge\n";
302 void learnFrom(Knowledge That) {
306 That.Unused.is_null() &&
307 "This function is only prepared to learn occupied elements from That");
308 assert(Occupied.
is_null() &&
"This function does not implement "
310 "this->Occupied.unite(That.Occupied);`");
312 Unused = Unused.
subtract(That.Occupied);
313 Known = Known.
unite(That.Known);
314 Written = Written.
unite(That.Written);
338 const Knowledge &Proposed,
339 llvm::raw_ostream *OS =
nullptr,
340 unsigned Indent = 0) {
341 assert(!Existing.Unused.is_null());
342 assert(!Proposed.Occupied.is_null());
345 if (!Existing.Occupied.is_null() && !Proposed.Unused.is_null()) {
346 auto ExistingUniverse = Existing.Occupied.unite(Existing.Unused);
347 auto ProposedUniverse = Proposed.Occupied.unite(Proposed.Unused);
348 assert(ExistingUniverse.is_equal(ProposedUniverse) &&
349 "Both inputs' Knowledges must be over the same universe");
378 auto ProposedValues = Proposed.Known.unite(ProposedOccupiedAnyVal);
381 auto ExistingValues = Existing.Known.unite(ExistingUnusedAnyVal);
383 auto MatchingVals = ExistingValues.intersect(ProposedValues);
384 auto Matches = MatchingVals.domain();
389 if (!Proposed.Occupied.is_subset(Matches)) {
391 auto Conflicting = Proposed.Occupied.subtract(Matches);
392 auto ExistingConflictingKnown =
393 Existing.Known.intersect_domain(Conflicting);
394 auto ProposedConflictingKnown =
395 Proposed.Known.intersect_domain(Conflicting);
397 OS->indent(Indent) <<
"Proposed lifetime conflicting with Existing's\n";
398 OS->indent(Indent) <<
"Conflicting occupied: " << Conflicting <<
"\n";
399 if (!ExistingConflictingKnown.is_empty())
401 <<
"Existing Known: " << ExistingConflictingKnown <<
"\n";
402 if (!ProposedConflictingKnown.is_empty())
404 <<
"Proposed Known: " << ProposedConflictingKnown <<
"\n";
428 auto ProposedFixedDefs =
430 auto ProposedFixedKnown =
433 auto ExistingConflictingWrites =
434 Existing.Written.intersect_domain(ProposedFixedDefs);
435 auto ExistingConflictingWritesDomain = ExistingConflictingWrites.domain();
437 auto CommonWrittenVal =
438 ProposedFixedKnown.intersect(ExistingConflictingWrites);
439 auto CommonWrittenValDomain = CommonWrittenVal.domain();
441 if (!ExistingConflictingWritesDomain.is_subset(CommonWrittenValDomain)) {
443 auto ExistingConflictingWritten =
444 ExistingConflictingWrites.subtract_domain(CommonWrittenValDomain);
445 auto ProposedConflictingKnown = ProposedFixedKnown.subtract_domain(
446 ExistingConflictingWritten.domain());
449 <<
"Proposed a lifetime where there is an Existing write into it\n";
450 OS->indent(Indent) <<
"Existing conflicting writes: "
451 << ExistingConflictingWritten <<
"\n";
452 if (!ProposedConflictingKnown.is_empty())
454 <<
"Proposed conflicting known: " << ProposedConflictingKnown
461 auto ExistingAvailableDefs =
463 auto ExistingKnownDefs =
466 auto ProposedWrittenDomain = Proposed.Written.domain();
467 auto KnownIdentical = ExistingKnownDefs.intersect(Proposed.Written);
468 auto IdenticalOrUnused =
469 ExistingAvailableDefs.unite(KnownIdentical.domain());
470 if (!ProposedWrittenDomain.is_subset(IdenticalOrUnused)) {
472 auto Conflicting = ProposedWrittenDomain.subtract(IdenticalOrUnused);
473 auto ExistingConflictingKnown =
474 ExistingKnownDefs.intersect_domain(Conflicting);
475 auto ProposedConflictingWritten =
476 Proposed.Written.intersect_domain(Conflicting);
478 OS->indent(Indent) <<
"Proposed writes into range used by Existing\n";
479 OS->indent(Indent) <<
"Proposed conflicting writes: "
480 << ProposedConflictingWritten <<
"\n";
481 if (!ExistingConflictingKnown.is_empty())
483 <<
"Existing conflicting known: " << ExistingConflictingKnown
491 auto ExistingWrittenDomain = Existing.Written.domain();
493 Existing.Written.domain().intersect(Proposed.Written.domain());
497 ExistingKnownWritten.intersect(ProposedKnownWritten).domain();
499 if (!BothWritten.is_subset(CommonWritten)) {
501 auto Conflicting = BothWritten.subtract(CommonWritten);
502 auto ExistingConflictingWritten =
503 Existing.Written.intersect_domain(Conflicting);
504 auto ProposedConflictingWritten =
505 Proposed.Written.intersect_domain(Conflicting);
507 OS->indent(Indent) <<
"Proposed writes at the same time as an already "
509 OS->indent(Indent) <<
"Conflicting writes: " << Conflicting <<
"\n";
510 if (!ExistingConflictingWritten.is_empty())
512 <<
"Exiting write: " << ExistingConflictingWritten <<
"\n";
513 if (!ProposedConflictingWritten.is_empty())
515 <<
"Proposed write: " << ProposedConflictingWritten <<
"\n";
528 Knowledge OriginalZone;
535 int NumberOfCompatibleTargets = 0;
539 int NumberOfTargetsMapped = 0;
542 int NumberOfMappedValueScalars = 0;
545 int NumberOfMappedPHIScalars = 0;
551 raw_ostream *OS =
nullptr;
553 return Knowledge::isConflicting(Zone, Proposed, OS, 4);
562 auto *MA =
S->getValueDef(SAI);
566 <<
" Reject because value is read-only within the scop\n");
574 auto Inst = MA->getAccessInstruction();
575 for (
auto User : Inst->users()) {
576 if (!isa<Instruction>(User))
578 auto UserInst = cast<Instruction>(User);
580 if (!
S->contains(UserInst)) {
581 POLLY_DEBUG(dbgs() <<
" Reject because value is escaping\n");
590 auto *MA =
S->getPHIRead(SAI);
595 auto PHI = cast<PHINode>(MA->getAccessInstruction());
596 for (
auto Incoming :
PHI->blocks()) {
597 if (!
S->contains(Incoming)) {
599 <<
" Reject because at least one incoming block is "
600 "not in the scop region\n");
608 POLLY_DEBUG(dbgs() <<
" Reject ExitPHI or other non-value\n");
620 std::tuple<isl::union_map, isl::map>
628 for (
auto *MA :
S->getValueUses(SAI))
634 auto *DefMA =
S->getValueDef(SAI);
656 auto Lifetime =
betweenScatter(WriteScatter, UseScatter,
false,
true);
659 auto DefUses = Uses.domain_factor_domain();
661 return std::make_pair(DefUses, Lifetime);
674 auto *DefMA =
S->getValueDef(SAI);
675 assert(DefMA->isValueKind());
676 assert(DefMA->isMustWrite());
677 auto *V = DefMA->getAccessValue();
678 auto *DefInst = DefMA->getAccessInstruction();
681 if (!DefMA->getLatestScopArrayInfo()->isValueKind())
689 auto DefTarget = TargetElt.
apply_domain(DefSched.reverse());
691 POLLY_DEBUG(dbgs() <<
" Def Mapping: " << DefTarget <<
'\n');
694 auto MappedDomain = DefTarget.domain();
695 if (!OrigDomain.is_subset(MappedDomain)) {
698 <<
" Reject because mapping does not encompass all instances\n");
708 std::tie(DefUses, Lifetime) = computeValueUses(SAI);
709 POLLY_DEBUG(dbgs() <<
" Lifetime: " << Lifetime <<
'\n');
719 if (DelicmComputeKnown)
721 LI->getLoopFor(DefInst->getParent()));
726 auto EltKnownTranslator = DefTarget.range_product(Lifetime);
729 auto EltKnown = ValInst.
apply_domain(EltKnownTranslator);
733 auto WrittenTranslator = DefTarget.range_product(DefSched);
736 auto DefEltSched = ValInst.
apply_domain(WrittenTranslator);
746 mapValue(SAI, std::move(DefTarget), std::move(UseTarget),
747 std::move(Lifetime), std::move(Proposed));
752 void applyLifetime(Knowledge Proposed) {
753 Zone.learnFrom(std::move(Proposed));
772 Knowledge Proposed) {
774 for (
auto *MA :
S->getValueUses(SAI)) {
786 auto *WA =
S->getValueDef(SAI);
787 WA->setNewAccessRelation(DefTarget);
788 applyLifetime(Proposed);
790 MappedValueScalars++;
791 NumberOfMappedValueScalars += 1;
795 bool IsCertain =
true) {
798 if (!DelicmComputeKnown)
813 for (
auto *MA :
S->getPHIIncomings(SAI)) {
816 auto *WriteStmt = MA->getStatement();
818 auto Incoming = MA->getIncoming();
819 assert(!Incoming.empty());
820 if (Incoming.size() == 1) {
821 ValInst =
makeValInst(Incoming[0].second, WriteStmt,
822 LI->getLoopFor(Incoming[0].first));
832 Result = Result.unite(ValInst);
835 assert(Result.is_single_valued() &&
836 "Cannot have multiple incoming values for same incoming statement");
849 auto *PHIRead =
S->getPHIRead(SAI);
850 assert(PHIRead->isPHIKind());
851 assert(PHIRead->isRead());
854 if (!PHIRead->getLatestScopArrayInfo()->isPHIKind())
861 auto PHITarget = PHISched.apply_range(TargetElt);
863 POLLY_DEBUG(dbgs() <<
" Mapping: " << PHITarget <<
'\n');
866 auto MappedDomain = PHITarget.domain();
867 if (!OrigDomain.is_subset(MappedDomain)) {
870 <<
" Reject because mapping does not encompass all instances\n");
876 if (PerPHIWrites.is_null()) {
878 dbgs() <<
" Reject because cannot determine incoming values\n");
883 auto WritesTarget = PerPHIWrites.apply_domain(PHITarget).reverse();
889 for (
auto *MA :
S->getPHIIncomings(SAI))
890 UniverseWritesDom = UniverseWritesDom.unite(
getDomainFor(MA));
892 auto RelevantWritesTarget = WritesTarget;
893 if (DelicmOverapproximateWrites)
894 WritesTarget = expandMapping(WritesTarget, UniverseWritesDom);
896 auto ExpandedWritesDom = WritesTarget.domain();
897 if (!DelicmPartialWrites &&
898 !UniverseWritesDom.is_subset(ExpandedWritesDom)) {
900 dbgs() <<
" Reject because did not find PHI write mapping for "
902 if (DelicmOverapproximateWrites)
904 << RelevantWritesTarget <<
'\n');
905 POLLY_DEBUG(dbgs() <<
" Deduced Mapping: " << WritesTarget
908 << UniverseWritesDom.subtract(ExpandedWritesDom)
919 auto Lifetime =
betweenScatter(PerPHIWriteScatter, PHISched,
false,
true);
921 POLLY_DEBUG(dbgs() <<
" Lifetime: " << Lifetime <<
"\n");
927 auto WrittenValue = determinePHIWrittenValues(SAI);
930 auto WrittenTranslator = WritesTarget.range_product(Schedule);
933 auto Written = WrittenValue.apply_domain(WrittenTranslator);
937 auto LifetimeTranslator = WritesTarget.range_product(WriteLifetime);
943 auto EltLifetimeInst = WrittenKnownValue.apply_domain(LifetimeTranslator);
947 auto Occupied = LifetimeTranslator.range();
950 Knowledge Proposed(Occupied, {}, EltLifetimeInst, Written);
954 mapPHI(SAI, std::move(PHITarget), std::move(WritesTarget),
955 std::move(Lifetime), std::move(Proposed));
975 Knowledge Proposed) {
980 for (
auto *MA :
S->getPHIIncomings(SAI)) {
989 Domain.get_space().map_from_domain_and_range(ElementSpace);
991 MA->setNewAccessRelation(NewAccRelMap);
995 auto *PHIRead =
S->getPHIRead(SAI);
996 PHIRead->setNewAccessRelation(ReadTarget);
997 applyLifetime(Proposed);
1000 NumberOfMappedPHIScalars++;
1013 bool collapseScalarsToStore(
MemoryAccess *TargetStoreMA) {
1028 computeScalarReachingOverwrite(Schedule, TargetDom,
false,
true);
1032 auto EltTarget = Target.apply_range(TargetAccRel);
1034 POLLY_DEBUG(dbgs() <<
" Target mapping is " << EltTarget <<
'\n');
1037 SmallVector<MemoryAccess *, 16> Worklist;
1040 SmallPtrSet<const ScopArrayInfo *, 16> Closed;
1043 auto ProcessAllIncoming = [&](
ScopStmt *Stmt) {
1044 for (
auto *MA : *Stmt) {
1045 if (!MA->isLatestScalarKind())
1050 Worklist.push_back(MA);
1055 if (
auto *WrittenValInputMA = TargetStmt->lookupInputAccessOf(WrittenVal))
1056 Worklist.push_back(WrittenValInputMA);
1058 ProcessAllIncoming(TargetStmt);
1060 auto AnyMapped =
false;
1061 auto &DL =
S->getRegion().getEntry()->getModule()->getDataLayout();
1065 while (!Worklist.empty()) {
1066 auto *MA = Worklist.pop_back_val();
1068 auto *SAI = MA->getScopArrayInfo();
1069 if (Closed.count(SAI))
1072 POLLY_DEBUG(dbgs() <<
"\n Trying to map " << MA <<
" (SAI: " << SAI
1076 if (!isMappable(SAI))
1079 auto MASize = DL.getTypeAllocSize(MA->getAccessValue()->getType());
1080 if (MASize > StoreSize) {
1082 dbgs() <<
" Reject because storage size is insufficient\n");
1088 if (!tryMapValue(SAI, EltTarget))
1091 auto *DefAcc =
S->getValueDef(SAI);
1092 ProcessAllIncoming(DefAcc->getStatement());
1100 if (!tryMapPHI(SAI, EltTarget))
1104 for (
auto *PHIWrite :
S->getPHIIncomings(SAI)) {
1105 auto *PHIWriteStmt = PHIWrite->getStatement();
1106 bool FoundAny =
false;
1107 for (
auto Incoming : PHIWrite->getIncoming()) {
1108 auto *IncomingInputMA =
1109 PHIWriteStmt->lookupInputAccessOf(Incoming.second);
1110 if (!IncomingInputMA)
1113 Worklist.push_back(IncomingInputMA);
1118 ProcessAllIncoming(PHIWrite->getStatement());
1128 NumberOfTargetsMapped++;
1139 false,
false,
true);
1141 auto Result = ArrayUnused.wrap();
1170 auto Set = Map.range();
1171 return Set.is_singleton();
1175 void printStatistics(llvm::raw_ostream &OS,
int Indent = 0)
const {
1176 OS.indent(Indent) <<
"Statistics {\n";
1177 OS.indent(Indent + 4) <<
"Compatible overwrites: "
1178 << NumberOfCompatibleTargets <<
"\n";
1179 OS.indent(Indent + 4) <<
"Overwrites mapped to: " << NumberOfTargetsMapped
1181 OS.indent(Indent + 4) <<
"Value scalars mapped: "
1182 << NumberOfMappedValueScalars <<
'\n';
1183 OS.indent(Indent + 4) <<
"PHI scalars mapped: "
1184 << NumberOfMappedPHIScalars <<
'\n';
1185 OS.indent(Indent) <<
"}\n";
1194 bool computeZone() {
1206 EltUnused = computeLifetime();
1208 EltWritten = computeWritten();
1214 "The only reason that these things have not been computed should "
1215 "be if the max-operations limit hit");
1217 POLLY_DEBUG(dbgs() <<
"DeLICM analysis exceeded max_operations\n");
1218 DebugLoc Begin, End;
1220 OptimizationRemarkAnalysis R(
DEBUG_TYPE,
"OutOfQuota", Begin,
1222 R <<
"maximal number of operations exceeded during zone analysis";
1223 S->getFunction().getContext().diagnose(R);
1227 Zone = OriginalZone = Knowledge({}, EltUnused, EltKnown, EltWritten);
1228 POLLY_DEBUG(dbgs() <<
"Computed Zone:\n"; OriginalZone.print(dbgs(), 4));
1230 assert(Zone.isUsable() && OriginalZone.isUsable());
1239 void greedyCollapse() {
1240 bool Modified =
false;
1242 for (
auto &Stmt : *
S) {
1243 for (
auto *MA : Stmt) {
1251 <<
" pruned because it is a MAY_WRITE\n");
1252 OptimizationRemarkMissed R(
DEBUG_TYPE,
"TargetMayWrite",
1254 R <<
"Skipped possible mapping target because it is not an "
1255 "unconditional overwrite";
1256 S->getFunction().getContext().diagnose(R);
1260 if (Stmt.getNumIterators() == 0) {
1262 <<
" pruned because it is not in a loop\n");
1263 OptimizationRemarkMissed R(
DEBUG_TYPE,
"WriteNotInLoop",
1265 R <<
"skipped possible mapping target because it is not in a loop";
1266 S->getFunction().getContext().diagnose(R);
1270 if (isScalarAccess(MA)) {
1273 <<
" pruned because it writes only a single element\n");
1274 OptimizationRemarkMissed R(
DEBUG_TYPE,
"ScalarWrite",
1276 R <<
"skipped possible mapping target because the memory location "
1277 "written to does not depend on its outer loop";
1278 S->getFunction().getContext().diagnose(R);
1284 <<
" pruned because it is not a StoreInst\n");
1285 OptimizationRemarkMissed R(
DEBUG_TYPE,
"NotAStore",
1287 R <<
"skipped possible mapping target because non-store instructions "
1288 "are not supported";
1289 S->getFunction().getContext().diagnose(R);
1307 <<
" is incompatible because it writes multiple "
1308 "elements per instance\n");
1309 OptimizationRemarkMissed R(
DEBUG_TYPE,
"NonFunctionalAccRel",
1311 R <<
"skipped possible mapping target because it writes more than "
1313 S->getFunction().getContext().diagnose(R);
1318 if (!TouchedElts.
is_subset(CompatibleElts)) {
1322 <<
" is incompatible because it touches incompatible elements\n");
1323 OptimizationRemarkMissed R(
DEBUG_TYPE,
"IncompatibleElts",
1325 R <<
"skipped possible mapping target because a target location "
1326 "cannot be reliably analyzed";
1327 S->getFunction().getContext().diagnose(R);
1332 NumberOfCompatibleTargets++;
1333 POLLY_DEBUG(dbgs() <<
"Analyzing target access " << MA <<
"\n");
1334 if (collapseScalarsToStore(MA))
1340 DeLICMScopsModified++;
1344 void print(llvm::raw_ostream &OS,
int Indent = 0) {
1345 if (!Zone.isUsable()) {
1346 OS.indent(Indent) <<
"Zone not computed\n";
1350 printStatistics(OS, Indent);
1351 if (!isModified()) {
1352 OS.indent(Indent) <<
"No modification has been made\n";
1359 bool isModified()
const {
return NumberOfTargetsMapped > 0; }
1362static std::unique_ptr<DeLICMImpl> collapseToUnused(
Scop &
S, LoopInfo &LI) {
1363 std::unique_ptr<DeLICMImpl> Impl = std::make_unique<DeLICMImpl>(&
S, &LI);
1365 if (!Impl->computeZone()) {
1366 POLLY_DEBUG(dbgs() <<
"Abort because cannot reliably compute lifetimes\n");
1370 POLLY_DEBUG(dbgs() <<
"Collapsing scalars to unused array elements...\n");
1371 Impl->greedyCollapse();
1379static std::unique_ptr<DeLICMImpl> runDeLICM(
Scop &
S, LoopInfo &LI) {
1380 std::unique_ptr<DeLICMImpl> Impl = collapseToUnused(
S, LI);
1396 LoopInfo &LI = SAR.
LI;
1397 std::unique_ptr<DeLICMImpl> Impl = runDeLICM(
S, LI);
1400 *OS <<
"Printing analysis 'Polly - DeLICM/DePRE' for region: '"
1401 <<
S.getName() <<
"' in function '" <<
S.getFunction().getName()
1404 assert(Impl->getScop() == &
S);
1406 *OS <<
"DeLICM result:\n";
1411 if (!Impl->isModified())
1412 return PreservedAnalyses::all();
1414 PreservedAnalyses PA;
1415 PA.preserveSet<AllAnalysesOn<Module>>();
1416 PA.preserveSet<AllAnalysesOn<Function>>();
1417 PA.preserveSet<AllAnalysesOn<Loop>>();
1421class DeLICMWrapperPass final :
public ScopPass {
1423 DeLICMWrapperPass(
const DeLICMWrapperPass &) =
delete;
1424 const DeLICMWrapperPass &operator=(
const DeLICMWrapperPass &) =
delete;
1427 std::unique_ptr<DeLICMImpl> Impl;
1431 explicit DeLICMWrapperPass() :
ScopPass(ID) {}
1435 AU.addRequired<LoopInfoWrapperPass>();
1436 AU.setPreservesAll();
1443 auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
1444 Impl = runDeLICM(
S, LI);
1446 return Impl->isModified();
1452 assert(Impl->getScop() == &
S);
1454 OS <<
"DeLICM result:\n";
1458 void releaseMemory()
override { Impl.reset(); }
1461char DeLICMWrapperPass::ID;
1464class DeLICMPrinterLegacyPass final :
public ScopPass {
1468 DeLICMPrinterLegacyPass() : DeLICMPrinterLegacyPass(outs()) {}
1469 explicit DeLICMPrinterLegacyPass(llvm::raw_ostream &OS)
1473 DeLICMWrapperPass &P = getAnalysis<DeLICMWrapperPass>();
1475 OS <<
"Printing analysis '" << P.getPassName() <<
"' for region: '"
1476 <<
S.getRegion().getNameStr() <<
"' in function '"
1477 <<
S.getFunction().getName() <<
"':\n";
1485 AU.addRequired<DeLICMWrapperPass>();
1486 AU.setPreservesAll();
1490 llvm::raw_ostream &OS;
1493char DeLICMPrinterLegacyPass::ID = 0;
1499 return new DeLICMPrinterLegacyPass(OS);
1506 return runDeLICMUsingNPM(
S, SAM, SAR, U,
nullptr);
1513 return runDeLICMUsingNPM(
S, SAM, SAR, U, &
OS);
1521 llvm::raw_ostream *OS,
unsigned Indent) {
1522 Knowledge Existing(std::move(ExistingOccupied), std::move(ExistingUnused),
1523 std::move(ExistingKnown), std::move(ExistingWrites));
1524 Knowledge Proposed(std::move(ProposedOccupied), std::move(ProposedUnused),
1525 std::move(ProposedKnown), std::move(ProposedWrites));
1527 return Knowledge::isConflicting(Existing, Proposed, OS, Indent);
INITIALIZE_PASS_BEGIN(DependenceInfo, "polly-dependences", "Polly - Calculate dependences", false, false)
INITIALIZE_PASS_END(DependenceInfo, "polly-dependences", "Polly - Calculate dependences", false, false) namespace
INITIALIZE_PASS_DEPENDENCY(ScopInfoRegionPass)
llvm::cl::OptionCategory PollyCategory
STATISTIC(ScopFound, "Number of valid Scops")
static isl::map from_union_map(isl::union_map umap)
isl::map apply_domain(isl::map map2) const
isl::space get_space() const
isl::space map_from_domain_and_range(isl::space range) const
isl::union_set range() const
isl::union_map reverse() const
isl::union_map gist_domain(isl::union_set uset) const
isl::union_map unite(isl::union_map umap2) const
isl::union_set domain() const
isl::space get_space() const
isl::union_map apply_domain(isl::union_map umap2) const
static isl::union_map from_domain(isl::union_set uset)
isl::union_map coalesce() const
isl::union_map apply_range(isl::union_map umap2) const
boolean is_single_valued() const
isl::union_map intersect_domain(isl::space space) const
static isl::union_set empty(isl::ctx ctx)
boolean is_disjoint(const isl::union_set &uset2) const
isl::union_set subtract(isl::union_set uset2) const
boolean is_subset(const isl::union_set &uset2) const
isl::union_set unite(isl::union_set uset2) const
Scoped limit of ISL operations.
Represent memory accesses in statements.
isl::map getLatestAccessRelation() const
Return the newest access relation of this access.
bool isLatestArrayKind() const
Whether storage memory is either an custom .s2a/.phiops alloca (false) or an existing pointer into an...
bool isWrite() const
Is this a write memory access?
Instruction * getAccessInstruction() const
Return the access instruction of this memory access.
bool isMustWrite() const
Is this a must-write memory access?
ScopStmt * getStatement() const
Get the statement that contains this memory access.
bool isMayWrite() const
Is this a may-write memory access?
Value * getAccessValue() const
Return the access value of this memory access.
A class to store information about arrays in the SCoP.
bool isValueKind() const
Is this array info modeling an llvm::Value?
bool isPHIKind() const
Is this array info modeling special PHI node memory?
The legacy pass manager's analysis pass to compute scop information for a region.
The legacy pass manager's analysis pass to compute scop information for the whole function.
ScopPass - This class adapts the RegionPass interface to allow convenient creation of passes that ope...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
virtual bool runOnScop(Scop &S)=0
runOnScop - This method must be overloaded to perform the desired Polyhedral transformation or analys...
virtual void printScop(raw_ostream &OS, Scop &S) const
Print method for SCoPs.
Base class for algorithms based on zones, like DeLICM.
isl::map makeUnknownForDomain(ScopStmt *Stmt) const
Create a statement-to-unknown value mapping.
isl::union_set makeEmptyUnionSet() const
isl::union_map makeEmptyUnionMap() const
void printAccesses(llvm::raw_ostream &OS, int Indent=0) const
Print the current state of all MemoryAccesses to .
isl::set getDomainFor(ScopStmt *Stmt) const
Get the domain of Stmt.
isl::map makeValInst(llvm::Value *Val, ScopStmt *UserStmt, llvm::Loop *Scope, bool IsCertain=true)
Create a mapping from a statement instance to the instance of an llvm::Value that can be used in ther...
void collectCompatibleElts()
Find the array elements that can be used for zone analysis.
isl::map getScatterFor(ScopStmt *Stmt) const
Get the schedule for Stmt.
isl::union_map computePerPHI(const polly::ScopArrayInfo *SAI)
For each 'execution' of a PHINode, get the incoming block that was executed before.
void computeCommon()
Compute the different zones.
isl::union_map computeKnown(bool FromWrite, bool FromRead) const
Compute which value an array element stores at every instant.
isl::map getScalarReachingDefinition(ScopStmt *Stmt)
Get the reaching definition of a scalar defined in Stmt.
isl::map getAccessRelationFor(MemoryAccess *MA) const
Get the access relation of MA.
bool isCompatibleAccess(MemoryAccess *MA)
Return whether MA can be used for transformations (e.g.
enum isl_error isl_ctx_last_error(isl_ctx *ctx)
This file contains the declaration of the PolyhedralInfo class, which will provide an interface to ex...
isl::map betweenScatter(isl::map From, isl::map To, bool InclFrom, bool InclTo)
Construct a range of timepoints between two timepoints.
llvm::Pass * createDeLICMPrinterLegacyPass(llvm::raw_ostream &OS)
isl::union_map makeUnknownForDomain(isl::union_set Domain)
Create a domain-to-unknown value mapping.
isl::union_map computeReachingWrite(isl::union_map Schedule, isl::union_map Writes, bool Reverse, bool InclPrevDef, bool InclNextDef)
Compute the reaching definition statement or the next overwrite for each definition of an array eleme...
isl::union_map computeArrayUnused(isl::union_map Schedule, isl::union_map Writes, isl::union_map Reads, bool ReadEltInSameInst, bool InclLastRead, bool InclWrite)
Compute the timepoints where the contents of an array element are not used.
void getDebugLocations(const BBPair &P, DebugLoc &Begin, DebugLoc &End)
Set the begin and end source location for the region limited by P.
@ Value
MemoryKind::Value: Models an llvm::Value.
@ PHI
MemoryKind::PHI: Models PHI nodes within the SCoP.
llvm::Pass * createDeLICMWrapperPass()
Create a new DeLICM pass instance.
bool isConflicting(isl::union_set ExistingOccupied, isl::union_set ExistingUnused, isl::union_map ExistingKnown, isl::union_map ExistingWrites, isl::union_set ProposedOccupied, isl::union_set ProposedUnused, isl::union_map ProposedKnown, isl::union_map ProposedWrites, llvm::raw_ostream *OS=nullptr, unsigned Indent=0)
Determine whether two lifetimes are conflicting.
BBPair getBBPairForRegion(const Region *R)
Return the region delimiters (entry & exit block) of R.
isl::union_map applyDomainRange(isl::union_map UMap, isl::union_map Func)
Apply a map to the 'middle' of another relation.
isl::union_set convertZoneToTimepoints(isl::union_set Zone, bool InclStart, bool InclEnd)
Convert a zone (range between timepoints) to timepoints.
AnalysisManager< Scop, ScopStandardAnalysisResults & > ScopAnalysisManager
isl::map singleton(isl::union_map UMap, isl::space ExpectedSpace)
If by construction a union map is known to contain only a single map, return it.
isl::union_map filterKnownValInst(const isl::union_map &UMap)
Return only the mappings that map to known values.
isl::space getScatterSpace(const isl::union_map &Schedule)
Return the scatter space of a Schedule.
llvm::PreservedAnalyses run(Scop &S, ScopAnalysisManager &SAM, ScopStandardAnalysisResults &SAR, SPMUpdater &U)
PreservedAnalyses run(Scop &S, ScopAnalysisManager &, ScopStandardAnalysisResults &SAR, SPMUpdater &)
int NumValueWritesInLoops
int NumSingletonWritesInLoops
static TupleKindPtr Domain("Domain")
isl_size isl_union_map_n_map(__isl_keep isl_union_map *umap)