23#include "llvm/ADT/STLExtras.h"
24#include "llvm/ADT/SmallVector.h"
25#include "llvm/ADT/Statistic.h"
26#include "llvm/Analysis/LoopInfo.h"
27#include "llvm/Analysis/ValueTracking.h"
28#include "llvm/IR/Instruction.h"
29#include "llvm/IR/Instructions.h"
30#include "llvm/IR/Value.h"
31#include "llvm/InitializePasses.h"
32#include "llvm/Support/Casting.h"
33#include "llvm/Support/CommandLine.h"
34#include "llvm/Support/Compiler.h"
35#include "llvm/Support/Debug.h"
36#include "llvm/Support/ErrorHandling.h"
37#include "llvm/Support/raw_ostream.h"
44#define DEBUG_TYPE "polly-optree"
51 cl::desc(
"Analyze array contents for load forwarding"),
56 cl::desc(
"Replace PHIs by their incoming values"),
59static cl::opt<unsigned>
61 cl::desc(
"Maximum number of ISL operations to invest for known "
62 "analysis; 0=no limit"),
65STATISTIC(KnownAnalyzed,
"Number of successfully analyzed SCoPs");
67 "Analyses aborted because max_operations was reached");
69STATISTIC(TotalInstructionsCopied,
"Number of copied instructions");
71 "Number of forwarded loads because their value was known");
72STATISTIC(TotalReloads,
"Number of reloaded values");
73STATISTIC(TotalReadOnlyCopied,
"Number of copied read-only accesses");
74STATISTIC(TotalForwardedTrees,
"Number of forwarded operand trees");
76 "Number of statements with at least one forwarded tree");
78STATISTIC(ScopsModified,
"Number of SCoPs with at least one forwarded tree");
80STATISTIC(NumValueWrites,
"Number of scalar value writes after OpTree");
82 "Number of scalar value writes nested in affine loops after OpTree");
83STATISTIC(NumPHIWrites,
"Number of scalar phi writes after OpTree");
85 "Number of scalar phi writes nested in affine loops after OpTree");
86STATISTIC(NumSingletonWrites,
"Number of singleton writes after OpTree");
88 "Number of singleton writes nested in affine loops after OpTree");
97enum ForwardingDecision {
124 FD_CanForwardProfitably,
134struct ForwardingAction {
135 using KeyTy = std::pair<Value *, ScopStmt *>;
138 ForwardingDecision Decision = FD_Unknown;
146 std::function<bool()> Execute = []() ->
bool {
147 llvm_unreachable(
"unspecified how to forward");
152 SmallVector<KeyTy, 4> Depends;
156 static ForwardingAction notApplicable() {
157 ForwardingAction Result;
158 Result.Decision = FD_NotApplicable;
163 static ForwardingAction cannotForward() {
164 ForwardingAction Result;
165 Result.Decision = FD_CannotForward;
170 static ForwardingAction triviallyForwardable(
bool IsProfitable, Value *Val) {
171 ForwardingAction Result;
173 IsProfitable ? FD_CanForwardProfitably : FD_CanForwardLeaf;
174 Result.Execute = [=]() {
175 POLLY_DEBUG(dbgs() <<
" trivially forwarded: " << *Val <<
"\n");
182 static ForwardingAction canForward(std::function<
bool()> Execute,
183 ArrayRef<KeyTy> Depends,
185 ForwardingAction Result;
187 IsProfitable ? FD_CanForwardProfitably : FD_CanForwardLeaf;
188 Result.Execute = std::move(Execute);
189 Result.Depends.append(Depends.begin(), Depends.end());
203 using MemoizationTy = DenseMap<ForwardingAction::KeyTy, ForwardingAction>;
209 int NumInstructionsCopied = 0;
212 int NumKnownLoadsForwarded = 0;
218 int NumReadOnlyCopied = 0;
221 int NumForwardedTrees = 0;
224 int NumModifiedStmts = 0;
227 bool Modified =
false;
239 MemoizationTy ForwardingActions;
328 if (!
Domain.is_subset(MapDom).is_true())
349 bool computeKnownValues() {
367 if (Known.
is_null() || Translator.
is_null() || NormalizeMap.is_null()) {
372 POLLY_DEBUG(dbgs() <<
"Known analysis exceeded max_operations\n");
377 POLLY_DEBUG(dbgs() <<
"All known: " << Known <<
"\n");
382 void printStatistics(raw_ostream &OS,
int Indent = 0) {
383 OS.indent(Indent) <<
"Statistics {\n";
384 OS.indent(Indent + 4) <<
"Instructions copied: " << NumInstructionsCopied
386 OS.indent(Indent + 4) <<
"Known loads forwarded: " << NumKnownLoadsForwarded
388 OS.indent(Indent + 4) <<
"Reloads: " << NumReloads <<
'\n';
389 OS.indent(Indent + 4) <<
"Read-only accesses copied: " << NumReadOnlyCopied
391 OS.indent(Indent + 4) <<
"Operand trees forwarded: " << NumForwardedTrees
393 OS.indent(Indent + 4) <<
"Statements with forwarded operand trees: "
394 << NumModifiedStmts <<
'\n';
395 OS.indent(Indent) <<
"}\n";
398 void printStatements(raw_ostream &OS,
int Indent = 0)
const {
399 OS.indent(Indent) <<
"After statements {\n";
400 for (
auto &Stmt : *
S) {
401 OS.indent(Indent + 4) << Stmt.getBaseName() <<
"\n";
402 for (
auto *MA : Stmt)
405 OS.indent(Indent + 12);
406 Stmt.printInstructions(OS);
408 OS.indent(Indent) <<
"}\n";
425 SmallVector<const SCEV *, 4> Sizes;
427 SmallVector<const SCEV *, 4> Subscripts;
431 Subscripts.push_back(
nullptr);
436 LI->getType(),
true, {}, Sizes, LI, MemoryKind::Array);
437 S->addAccessFunction(Access);
458 ForwardingAction forwardKnownLoad(
ScopStmt *TargetStmt, Instruction *Inst,
464 return ForwardingAction::notApplicable();
466 LoadInst *LI = dyn_cast<LoadInst>(Inst);
468 return ForwardingAction::notApplicable();
470 ForwardingDecision OpDecision =
471 forwardTree(TargetStmt, LI->getPointerOperand(), DefStmt, DefLoop);
472 switch (OpDecision) {
473 case FD_CanForwardProfitably:
474 case FD_CanForwardLeaf:
476 case FD_CannotForward:
477 return ForwardingAction::cannotForward();
479 llvm_unreachable(
"Shouldn't return this");
492 auto ExecAction = [
this, TargetStmt,
LI, Access]() ->
bool {
495 dbgs() <<
" forwarded known load with preexisting MemoryAccess"
499 NumKnownLoadsForwarded++;
500 TotalKnownLoadsForwarded++;
503 return ForwardingAction::canForward(
504 ExecAction, {{LI->getPointerOperand(), DefStmt}},
true);
515 "LoadInsts are always normalized");
526 isl::union_map Candidates = findSameContentElements(TranslatedExpectedVal);
530 return ForwardingAction::notApplicable();
532 POLLY_DEBUG(dbgs() <<
" expected values where " << TargetExpectedVal
534 POLLY_DEBUG(dbgs() <<
" candidate elements where " << Candidates
572 POLLY_DEBUG(dbgs() <<
" local translator is " << LocalTranslator
576 return ForwardingAction::notApplicable();
579 auto ExecAction = [
this, TargetStmt,
LI, SameVal,
580 LocalTranslator]() ->
bool {
582 MemoryAccess *Access = makeReadArrayAccess(TargetStmt, LI, SameVal);
583 POLLY_DEBUG(dbgs() <<
" forwarded known load with new MemoryAccess"
587 if (!LocalTranslator.
is_null())
588 Translator = Translator.
unite(LocalTranslator);
590 NumKnownLoadsForwarded++;
591 TotalKnownLoadsForwarded++;
594 return ForwardingAction::canForward(
595 ExecAction, {{LI->getPointerOperand(), DefStmt}},
true);
611 ForwardingAction reloadKnownContent(
ScopStmt *TargetStmt, Instruction *Inst,
617 return ForwardingAction::notApplicable();
634 isl::union_map Candidates = findSameContentElements(TranslatedExpectedVal);
639 return ForwardingAction::notApplicable();
641 auto ExecAction = [
this, TargetStmt, Inst, SameVal]() {
647 POLLY_DEBUG(dbgs() <<
" forwarded known content of " << *Inst
648 <<
" which is " << SameVal <<
"\n");
654 return ForwardingAction::canForward(ExecAction, {},
true);
667 ForwardingAction forwardSpeculatable(
ScopStmt *TargetStmt,
668 Instruction *UseInst,
ScopStmt *DefStmt,
671 if (isa<PHINode>(UseInst))
672 return ForwardingAction::notApplicable();
686 if (mayHaveNonDefUseDependency(*UseInst))
687 return ForwardingAction::notApplicable();
689 SmallVector<ForwardingAction::KeyTy, 4> Depends;
690 Depends.reserve(UseInst->getNumOperands());
691 for (Value *OpVal : UseInst->operand_values()) {
692 ForwardingDecision OpDecision =
693 forwardTree(TargetStmt, OpVal, DefStmt, DefLoop);
694 switch (OpDecision) {
695 case FD_CannotForward:
696 return ForwardingAction::cannotForward();
698 case FD_CanForwardLeaf:
699 case FD_CanForwardProfitably:
700 Depends.emplace_back(OpVal, DefStmt);
703 case FD_NotApplicable:
706 "forwardTree should never return FD_NotApplicable/FD_Unknown");
710 auto ExecAction = [
this, TargetStmt, UseInst]() {
716 POLLY_DEBUG(dbgs() <<
" forwarded speculable instruction: " << *UseInst
718 NumInstructionsCopied++;
719 TotalInstructionsCopied++;
722 return ForwardingAction::canForward(ExecAction, Depends,
true);
737 ForwardingAction forwardTreeImpl(
ScopStmt *TargetStmt, Value *UseVal,
740 Loop *DefLoop =
nullptr;
751 return ForwardingAction::triviallyForwardable(
false, UseVal);
767 return ForwardingAction::triviallyForwardable(
false, UseVal);
770 dbgs() <<
" Synthesizable would not be synthesizable anymore: "
772 return ForwardingAction::cannotForward();
777 return ForwardingAction::triviallyForwardable(
false, UseVal);
780 auto ExecAction = [
this, TargetStmt, UseVal]() {
783 POLLY_DEBUG(dbgs() <<
" forwarded read-only value " << *UseVal
786 TotalReadOnlyCopied++;
797 return ForwardingAction::canForward(ExecAction, {},
false);
807 Instruction *Inst = cast<Instruction>(UseVal);
810 DefStmt =
S->getStmtFor(Inst);
812 return ForwardingAction::cannotForward();
815 DefLoop = LI->getLoopFor(Inst->getParent());
817 ForwardingAction SpeculativeResult =
818 forwardSpeculatable(TargetStmt, Inst, DefStmt, DefLoop);
819 if (SpeculativeResult.Decision != FD_NotApplicable)
820 return SpeculativeResult;
822 ForwardingAction KnownResult = forwardKnownLoad(
823 TargetStmt, Inst, UseStmt, UseLoop, DefStmt, DefLoop);
824 if (KnownResult.Decision != FD_NotApplicable)
827 ForwardingAction ReloadResult = reloadKnownContent(
828 TargetStmt, Inst, UseStmt, UseLoop, DefStmt, DefLoop);
829 if (ReloadResult.Decision != FD_NotApplicable)
834 POLLY_DEBUG(dbgs() <<
" Cannot forward instruction: " << *Inst
836 return ForwardingAction::cannotForward();
839 llvm_unreachable(
"Case unhandled");
856 ForwardingDecision forwardTree(
ScopStmt *TargetStmt, Value *UseVal,
859 auto It = ForwardingActions.find({UseVal, UseStmt});
860 if (It != ForwardingActions.end())
861 return It->second.Decision;
864 ForwardingAction Action =
865 forwardTreeImpl(TargetStmt, UseVal, UseStmt, UseLoop);
866 ForwardingDecision Result = Action.Decision;
869 assert(!ForwardingActions.count({UseVal, UseStmt}) &&
870 "circular dependency?");
871 ForwardingActions.insert({{UseVal, UseStmt}, std::move(Action)});
884 decltype(std::declval<ForwardingAction>().Depends.begin());
885 using EdgeTy = std::pair<ForwardingAction *, ChildItTy>;
887 DenseSet<ForwardingAction::KeyTy> Visited;
888 SmallVector<EdgeTy, 32> Stack;
889 SmallVector<ForwardingAction *, 32> Ordered;
892 assert(ForwardingActions.count({UseVal, Stmt}));
893 ForwardingAction *RootAction = &ForwardingActions[{UseVal, Stmt}];
894 Stack.emplace_back(RootAction, RootAction->Depends.begin());
906 while (!Stack.empty()) {
907 EdgeTy &Top = Stack.back();
908 ForwardingAction *TopAction = Top.first;
909 ChildItTy &TopEdge = Top.second;
911 if (TopEdge == TopAction->Depends.end()) {
913 Ordered.push_back(TopAction);
917 ForwardingAction::KeyTy Key = *TopEdge;
922 auto VisitIt = Visited.insert(Key);
926 assert(ForwardingActions.count(Key) &&
927 "Must not insert new actions during execution phase");
928 ForwardingAction *ChildAction = &ForwardingActions[Key];
929 Stack.emplace_back(ChildAction, ChildAction->Depends.begin());
935 assert(Ordered.back() == RootAction);
936 if (RootAction->Execute())
939 for (
auto DepAction : reverse(Ordered)) {
940 assert(DepAction->Decision != FD_Unknown &&
941 DepAction->Decision != FD_CannotForward);
942 assert(DepAction != RootAction);
943 DepAction->Execute();
950 POLLY_DEBUG(dbgs() <<
"Trying to forward operand tree " << RA <<
"...\n");
962 ForwardingDecision Assessment =
966 bool Changed =
false;
967 if (Assessment == FD_CanForwardProfitably) {
972 ForwardingActions.clear();
981 bool forwardOperandTrees() {
983 bool StmtModified =
false;
987 SmallVector<MemoryAccess *, 16> Accs(Stmt.
begin(), Stmt.
end());
995 if (tryForwardTree(RA)) {
999 TotalForwardedTrees++;
1005 TotalModifiedStmts++;
1018 void print(raw_ostream &OS,
int Indent = 0) {
1019 printStatistics(OS, Indent);
1023 OS <<
"ForwardOpTree executed, but did not modify anything\n";
1027 printStatements(OS, Indent);
1030 bool isModified()
const {
return Modified; }
1033static std::unique_ptr<ForwardOpTreeImpl> runForwardOpTree(
Scop &
S,
1035 std::unique_ptr<ForwardOpTreeImpl> Impl;
1038 Impl = std::make_unique<ForwardOpTreeImpl>(&
S, &LI, MaxOpGuard);
1042 Impl->computeKnownValues();
1045 POLLY_DEBUG(dbgs() <<
"Forwarding operand trees...\n");
1046 Impl->forwardOperandTrees();
1049 POLLY_DEBUG(dbgs() <<
"Not all operations completed because of "
1050 "max_operations exceeded\n");
1070static PreservedAnalyses
1074 LoopInfo &LI = SAR.
LI;
1076 std::unique_ptr<ForwardOpTreeImpl> Impl = runForwardOpTree(
S, LI);
1078 *OS <<
"Printing analysis 'Polly - Forward operand tree' for region: '"
1079 <<
S.getName() <<
"' in function '" <<
S.getFunction().getName()
1082 assert(Impl->getScop() == &
S);
1088 if (!Impl->isModified())
1089 return PreservedAnalyses::all();
1091 PreservedAnalyses PA;
1092 PA.preserveSet<AllAnalysesOn<Module>>();
1093 PA.preserveSet<AllAnalysesOn<Function>>();
1094 PA.preserveSet<AllAnalysesOn<Loop>>();
1106class ForwardOpTreeWrapperPass final :
public ScopPass {
1109 std::unique_ptr<ForwardOpTreeImpl> Impl;
1114 explicit ForwardOpTreeWrapperPass() :
ScopPass(ID) {}
1115 ForwardOpTreeWrapperPass(
const ForwardOpTreeWrapperPass &) =
delete;
1116 ForwardOpTreeWrapperPass &
1117 operator=(
const ForwardOpTreeWrapperPass &) =
delete;
1121 AU.addRequired<LoopInfoWrapperPass>();
1122 AU.setPreservesAll();
1129 LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
1131 Impl = runForwardOpTree(
S, LI);
1140 assert(Impl->getScop() == &
S);
1144 void releaseMemory()
override { Impl.reset(); }
1147char ForwardOpTreeWrapperPass::ID;
1150class ForwardOpTreePrinterLegacyPass final :
public ScopPass {
1154 ForwardOpTreePrinterLegacyPass() : ForwardOpTreePrinterLegacyPass(outs()) {}
1155 explicit ForwardOpTreePrinterLegacyPass(llvm::raw_ostream &OS)
1159 ForwardOpTreeWrapperPass &P = getAnalysis<ForwardOpTreeWrapperPass>();
1161 OS <<
"Printing analysis '" << P.getPassName() <<
"' for region: '"
1162 <<
S.getRegion().getNameStr() <<
"' in function '"
1163 <<
S.getFunction().getName() <<
"':\n";
1171 AU.addRequired<ForwardOpTreeWrapperPass>();
1172 AU.setPreservesAll();
1176 llvm::raw_ostream &OS;
1179char ForwardOpTreePrinterLegacyPass::ID = 0;
1183 return new ForwardOpTreeWrapperPass();
1187 return new ForwardOpTreePrinterLegacyPass(OS);
1194 return runForwardOpTreeUsingNPM(
S, SAM, SAR, U,
nullptr);
1197llvm::PreservedAnalyses
1200 return runForwardOpTreeUsingNPM(
S, SAM, SAR, U, &
OS);
1204 "Polly - Forward operand tree",
false,
false)
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)
static cl::opt< bool > NormalizePHIs("polly-optree-normalize-phi", cl::desc("Replace PHIs by their incoming values"), cl::cat(PollyCategory), cl::init(false), cl::Hidden)
static cl::opt< bool > AnalyzeKnown("polly-optree-analyze-known", cl::desc("Analyze array contents for load forwarding"), cl::cat(PollyCategory), cl::init(true), cl::Hidden)
static cl::opt< unsigned > MaxOps("polly-optree-max-ops", cl::desc("Maximum number of ISL operations to invest for known " "analysis; 0=no limit"), cl::init(1000000), cl::cat(PollyCategory), cl::Hidden)
polly Polly Forward operand tree
STATISTIC(KnownAnalyzed, "Number of successfully analyzed SCoPs")
polly print import Polly Print Scop import result
llvm::cl::OptionCategory PollyCategory
isl::map product(isl::map map2) const
isl::id get_tuple_id(isl::dim type) const
isl::map apply_domain(isl::map map2) const
static isl::map identity(isl::space space)
isl::space get_space() const
isl::space map_from_domain_and_range(isl::space range) const
isl::space unwrap() const
boolean is_wrapping() const
isl::union_map range_map() const
isl::union_set range() const
isl::union_map reverse() const
isl::union_map uncurry() const
isl::union_map unite(isl::union_map umap2) const
isl::union_set domain() const
isl::map_list get_map_list() const
isl::union_map apply_domain(isl::union_map umap2) const
isl::union_map apply_range(isl::union_map umap2) const
isl::union_map range_product(isl::union_map umap2) const
boolean is_single_valued() const
isl::union_map domain_map() const
isl::union_map unwrap() const
Scoped limit of ISL operations.
bool hasQuotaExceeded() const
Return whether the current quota has exceeded.
IslQuotaScope enter(bool AllowReturnNull=true)
Enter a scope that can handle out-of-quota errors.
Scope guard for code that allows arbitrary isl function to return an error if the max-operations quot...
Represent memory accesses in statements.
bool isLatestScalarKind() const
Whether this access is an array to a scalar memory object, also considering changes by setNewAccessRe...
bool isRead() const
Is this a read memory access?
ScopStmt * getStatement() const
Get the statement that contains this memory access.
Value * getAccessValue() const
Return the access value of this memory access.
void setNewAccessRelation(isl::map NewAccessRelation)
Set the updated access relation read from JSCOP file.
A class to store information about arrays in the SCoP.
const SCEV * getDimensionSize(unsigned Dim) const
Return the size of dimension dim as SCEV*.
Value * getBasePtr() const
Return the base pointer.
unsigned getNumberOfDimensions() const
Return the number of dimensions.
const ScopArrayInfo * getBasePtrOriginSAI() const
For indirect accesses return the origin SAI of the BP, else null.
The legacy pass manager's analysis pass to compute scop information for a region.
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.
void addAccess(MemoryAccess *Access, bool Preprend=false)
Add Access to this statement's list of accesses.
void removeSingleMemoryAccess(MemoryAccess *MA, bool AfterHoisting=true)
Remove MA from this statement.
MemoryAccess * ensureValueRead(Value *V)
Check whether there is a value read access for V in this statement, and if not, create one.
MemoryAccess * lookupInputAccessOf(Value *Val) const
Return the input access of the value, or null if no such MemoryAccess exists.
void prependInstruction(Instruction *Inst)
Insert an instruction before all other instructions in this statement.
MemoryAccess * getArrayAccessOrNULLFor(const Instruction *Inst) const
Return the only array access for Inst, if existing.
Loop * getSurroundingLoop() const
Return the closest innermost loop that contains this statement, but is not contained in it.
isl::space getDomainSpace() const
Get the space of the iteration domain.
Determine the nature of a value's use within a statement.
static VirtualUse create(Scop *S, const Use &U, LoopInfo *LI, bool Virtual)
Get a VirtualUse for an llvm::Use.
UseKind getKind() const
Return the type of use.
Base class for algorithms based on zones, like DeLICM.
llvm::LoopInfo * LI
LoopInfo analysis used to determine whether values are synthesizable.
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 makeNormalizedValInst(llvm::Value *Val, ScopStmt *UserStmt, llvm::Loop *Scope, bool IsCertain=true)
Create and normalize a ValInst.
void computeNormalizedPHIs()
Compute the normalization map that replaces PHIs by their incoming values.
Scop * S
The analyzed Scop.
isl::map getDefToTarget(ScopStmt *DefStmt, ScopStmt *TargetStmt)
Get a domain translation map from a (scalar) definition to the statement where the definition is bein...
Scop * getScop() const
Return the SCoP this object is analyzing.
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::boolean isNormalized(isl::map Map)
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 makeIdentityMap(const isl::set &Set, bool RestrictDomain)
Construct an identity map for the given domain values.
llvm::Pass * createForwardOpTreeWrapperPass()
bool ModelReadOnlyScalars
Command line switch whether to model read-only accesses.
isl::union_set convertZoneToTimepoints(isl::union_set Zone, bool InclStart, bool InclEnd)
Convert a zone (range between timepoints) to timepoints.
AnalysisManager< Scop, ScopStandardAnalysisResults & > ScopAnalysisManager
llvm::Pass * createForwardOpTreePrinterLegacyPass(llvm::raw_ostream &OS)
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")