[polly] r310304 - [Polly] Fully-Indexed static expansion
Andreas Simbuerger via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 7 13:54:20 PDT 2017
Author: simbuerg
Date: Mon Aug 7 13:54:20 2017
New Revision: 310304
URL: http://llvm.org/viewvc/llvm-project?rev=310304&view=rev
Log:
[Polly] Fully-Indexed static expansion
This commit implements the initial version of fully-indexed static
expansion.
```
for(int i = 0; i<Ni; i++)
for(int j = 0; j<Ni; j++)
S: B[j] = j;
T: A[i] = B[i]
```
After the pass, we want this :
```
for(int i = 0; i<Ni; i++)
for(int j = 0; j<Ni; j++)
S: B[i][j] = j;
T: A[i] = B[i][i]
```
For now we bail (fail) in the following cases:
- Scalar access
- Multiple writes per SAI
- MayWrite Access
- Expansion that leads to an access to the original array
Furthermore: We still miss checks for escaping references to the array
base pointers. A future commit will add the missing escape-checks to
stay correct in those cases. The expansion is still locked behind a
CLI-Option and should not yet be used.
Patch contributed by: Nicholas Bonfante <bonfante.nicolas at gmail.com>
Reviewers: simbuerg, Meinersbur, bollu
Reviewed By: Meinersbur
Subscribers: mgorny, llvm-commits, pollydev
Differential Revision: https://reviews.llvm.org/D34982
Added:
polly/trunk/lib/Transform/MaximalStaticExpansion.cpp
polly/trunk/test/MaximalStaticExpansion/
polly/trunk/test/MaximalStaticExpansion/read_from_original.ll
polly/trunk/test/MaximalStaticExpansion/too_many_writes.ll
polly/trunk/test/MaximalStaticExpansion/working_expansion.ll
Modified:
polly/trunk/include/polly/LinkAllPasses.h
polly/trunk/lib/CMakeLists.txt
polly/trunk/lib/Support/RegisterPasses.cpp
Modified: polly/trunk/include/polly/LinkAllPasses.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/LinkAllPasses.h?rev=310304&r1=310303&r2=310304&view=diff
==============================================================================
--- polly/trunk/include/polly/LinkAllPasses.h (original)
+++ polly/trunk/include/polly/LinkAllPasses.h Mon Aug 7 13:54:20 2017
@@ -55,6 +55,7 @@ llvm::Pass *createPPCGCodeGenerationPass
llvm::Pass *createIslScheduleOptimizerPass();
llvm::Pass *createFlattenSchedulePass();
llvm::Pass *createDeLICMPass();
+llvm::Pass *createMaximalStaticExpansionPass();
extern char &CodePreparationID;
} // namespace polly
@@ -88,6 +89,7 @@ struct PollyForcePassLinking {
polly::createPPCGCodeGenerationPass();
#endif
polly::createIslScheduleOptimizerPass();
+ polly::createMaximalStaticExpansionPass();
polly::createFlattenSchedulePass();
polly::createDeLICMPass();
polly::createDumpModulePass("", true);
@@ -109,6 +111,7 @@ void initializeCodeGenerationPass(llvm::
void initializePPCGCodeGenerationPass(llvm::PassRegistry &);
#endif
void initializeIslScheduleOptimizerPass(llvm::PassRegistry &);
+void initializeMaximalStaticExpanderPass(llvm::PassRegistry &);
void initializePollyCanonicalizePass(llvm::PassRegistry &);
void initializeFlattenSchedulePass(llvm::PassRegistry &);
void initializeDeLICMPass(llvm::PassRegistry &);
Modified: polly/trunk/lib/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/CMakeLists.txt?rev=310304&r1=310303&r2=310304&view=diff
==============================================================================
--- polly/trunk/lib/CMakeLists.txt (original)
+++ polly/trunk/lib/CMakeLists.txt Mon Aug 7 13:54:20 2017
@@ -62,6 +62,7 @@ add_library(PollyCore OBJECT
Transform/DeLICM.cpp
Transform/ZoneAlgo.cpp
Transform/Simplify.cpp
+ Transform/MaximalStaticExpansion.cpp
${POLLY_HEADER_FILES}
)
set_target_properties(PollyCore PROPERTIES FOLDER "Polly")
Modified: polly/trunk/lib/Support/RegisterPasses.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Support/RegisterPasses.cpp?rev=310304&r1=310303&r2=310304&view=diff
==============================================================================
--- polly/trunk/lib/Support/RegisterPasses.cpp (original)
+++ polly/trunk/lib/Support/RegisterPasses.cpp Mon Aug 7 13:54:20 2017
@@ -149,6 +149,11 @@ static cl::opt<bool> ImportJScop(
cl::desc("Import the polyhedral description of the detected Scops"),
cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+static cl::opt<bool> FullyIndexedStaticExpansion(
+ "polly-enable-mse",
+ cl::desc("Fully expand the memory accesses of the detected Scops"),
+ cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
static cl::opt<bool> ExportJScop(
"polly-export",
cl::desc("Export the polyhedral description of the detected Scops"),
@@ -251,6 +256,7 @@ void initializePollyPasses(PassRegistry
initializeDependenceInfoWrapperPassPass(Registry);
initializeJSONExporterPass(Registry);
initializeJSONImporterPass(Registry);
+ initializeMaximalStaticExpanderPass(Registry);
initializeIslAstInfoWrapperPassPass(Registry);
initializeIslScheduleOptimizerPass(Registry);
initializePollyCanonicalizePass(Registry);
@@ -330,6 +336,9 @@ void registerPollyPasses(llvm::legacy::P
if (DeadCodeElim)
PM.add(polly::createDeadCodeElimPass());
+ if (FullyIndexedStaticExpansion)
+ PM.add(polly::createMaximalStaticExpansionPass());
+
if (EnablePruneUnprofitable)
PM.add(polly::createPruneUnprofitablePass());
Added: polly/trunk/lib/Transform/MaximalStaticExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Transform/MaximalStaticExpansion.cpp?rev=310304&view=auto
==============================================================================
--- polly/trunk/lib/Transform/MaximalStaticExpansion.cpp (added)
+++ polly/trunk/lib/Transform/MaximalStaticExpansion.cpp Mon Aug 7 13:54:20 2017
@@ -0,0 +1,394 @@
+//===---------------- MaximalStaticExpansion.cpp -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass fully expand the memory accesses of a Scop to get rid of
+// dependencies.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/DependenceInfo.h"
+#include "polly/FlattenAlgo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/ISLOStream.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-mse"
+
+namespace {
+class MaximalStaticExpander : public ScopPass {
+public:
+ static char ID;
+ explicit MaximalStaticExpander() : ScopPass(ID) {}
+
+ ~MaximalStaticExpander() {}
+
+ /// Expand the accesses of the SCoP.
+ ///
+ /// @param S The SCoP that must be expanded.
+ bool runOnScop(Scop &S) override;
+
+ /// Print the SCoP.
+ ///
+ /// @param OS The stream where to print.
+ /// @param S The SCop that must be printed.
+ void printScop(raw_ostream &OS, Scop &S) const override;
+
+ /// Register all analyses and transformations required.
+ void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+ /// OptimizationRemarkEmitter object for displaying diagnostic remarks
+ OptimizationRemarkEmitter *ORE;
+
+ /// Emit remark
+ void emitRemark(StringRef Msg, Instruction *Inst);
+
+ /// Return true if the SAI in parameter is expandable.
+ ///
+ /// @param SAI the SAI that need to be checked.
+ /// @param Writes A set that will contains all the write accesses.
+ /// @param Reads A set that will contains all the read accesses.
+ /// @param S The SCop in which the SAI is in.
+ /// @param Dependences The RAW dependences of the SCop.
+ bool isExpandable(const ScopArrayInfo *SAI,
+ SmallPtrSetImpl<MemoryAccess *> &Writes,
+ SmallPtrSetImpl<MemoryAccess *> &Reads, Scop &S,
+ isl::union_map &Dependences);
+
+ /// Expand a write memory access.
+ ///
+ /// @param S The SCop in which the memory access appears in.
+ /// @param MA The memory access that need to be expanded.
+ ScopArrayInfo *expandWrite(Scop &S, MemoryAccess *MA);
+
+ /// Expand the read memory access.
+ ///
+ /// @param The SCop in which the memory access appears in.
+ /// @param The memory access that need to be expanded.
+ /// @param Dependences The RAW dependences of the SCop.
+ /// @param ExpandedSAI The expanded SAI created during write expansion.
+ void expandRead(Scop &S, MemoryAccess *MA, isl::union_map &Dependences,
+ ScopArrayInfo *ExpandedSAI);
+};
+} // namespace
+
+namespace {
+
+/// Whether a dimension of a set is bounded (lower and upper) by a constant,
+/// i.e. there are two constants Min and Max, such that every value x of the
+/// chosen dimensions is Min <= x <= Max.
+bool isDimBoundedByConstant(isl::set Set, unsigned dim) {
+ auto ParamDims = Set.dim(isl::dim::param);
+ Set = Set.project_out(isl::dim::param, 0, ParamDims);
+ Set = Set.project_out(isl::dim::set, 0, dim);
+ auto SetDims = Set.dim(isl::dim::set);
+ Set = Set.project_out(isl::dim::set, 1, SetDims - 1);
+ return bool(Set.is_bounded());
+}
+
+/// If @p PwAff maps to a constant, return said constant. If @p Max/@p Min, it
+/// can also be a piecewise constant and it would return the minimum/maximum
+/// value. Otherwise, return NaN.
+isl::val getConstant(isl::pw_aff PwAff, bool Max, bool Min) {
+ assert(!Max || !Min);
+ isl::val Result;
+ PwAff.foreach_piece([=, &Result](isl::set Set, isl::aff Aff) -> isl::stat {
+ if (Result && Result.is_nan())
+ return isl::stat::ok;
+
+ // TODO: If Min/Max, we can also determine a minimum/maximum value if
+ // Set is constant-bounded.
+ if (!Aff.is_cst()) {
+ Result = isl::val::nan(Aff.get_ctx());
+ return isl::stat::error;
+ }
+
+ auto ThisVal = Aff.get_constant_val();
+ if (!Result) {
+ Result = ThisVal;
+ return isl::stat::ok;
+ }
+
+ if (Result.eq(ThisVal))
+ return isl::stat::ok;
+
+ if (Max && ThisVal.gt(Result)) {
+ Result = ThisVal;
+ return isl::stat::ok;
+ }
+
+ if (Min && ThisVal.lt(Result)) {
+ Result = ThisVal;
+ return isl::stat::ok;
+ }
+
+ // Not compatible
+ Result = isl::val::nan(Aff.get_ctx());
+ return isl::stat::error;
+ });
+ return Result;
+}
+
+} // namespace
+
+char MaximalStaticExpander::ID = 0;
+
+bool MaximalStaticExpander::isExpandable(
+ const ScopArrayInfo *SAI, SmallPtrSetImpl<MemoryAccess *> &Writes,
+ SmallPtrSetImpl<MemoryAccess *> &Reads, Scop &S,
+ isl::union_map &Dependences) {
+
+ int NumberWrites = 0;
+ for (ScopStmt &Stmt : S) {
+ for (MemoryAccess *MA : Stmt) {
+
+ // Check if the current MemoryAccess involved the current SAI.
+ if (SAI != MA->getLatestScopArrayInfo())
+ continue;
+
+ // For now, we are not able to expand Scalar.
+ if (MA->isLatestScalarKind()) {
+ emitRemark(SAI->getName() + " is a Scalar access.",
+ MA->getAccessInstruction());
+ return false;
+ }
+
+ // For now, we are not able to expand MayWrite.
+ if (MA->isMayWrite()) {
+ emitRemark(SAI->getName() + " has a maywrite access.",
+ MA->getAccessInstruction());
+ return false;
+ }
+
+ // For now, we are not able to expand SAI with more than one write.
+ if (MA->isMustWrite()) {
+ Writes.insert(MA);
+ NumberWrites++;
+ if (NumberWrites > 1) {
+ emitRemark(SAI->getName() + " has more than 1 write access.",
+ MA->getAccessInstruction());
+ return false;
+ }
+ }
+
+ // Check if it is possible to expand this read.
+ if (MA->isRead()) {
+
+ // Get the domain of the current ScopStmt.
+ auto StmtDomain = Stmt.getDomain();
+
+ // Get the domain of the future Read access.
+
+ auto ReadDomainSet = MA->getAccessRelation().domain();
+ auto ReadDomain = isl::union_set(ReadDomainSet);
+ auto CurrentReadWriteDependences =
+ Dependences.reverse().intersect_domain(ReadDomain);
+ auto DepsDomain = CurrentReadWriteDependences.domain();
+
+ unsigned NumberElementMap =
+ isl_union_map_n_map(CurrentReadWriteDependences.get());
+
+ // If there are multiple maps in the Deps, we cannot handle this case
+ // for now.
+ if (NumberElementMap != 1) {
+ emitRemark(SAI->getName() +
+ " has too many dependences to be handle for now.",
+ MA->getAccessInstruction());
+ return false;
+ }
+
+ auto DepsDomainSet = isl::set(DepsDomain);
+
+ // For now, read from the original array is not possible.
+ if (!StmtDomain.is_subset(DepsDomainSet)) {
+ emitRemark("The expansion of " + SAI->getName() +
+ " would lead to a read from the original array.",
+ MA->getAccessInstruction());
+ return false;
+ }
+
+ Reads.insert(MA);
+ }
+ }
+ }
+
+ // No need to expand SAI with no write.
+ if (NumberWrites == 0) {
+ emitRemark(SAI->getName() + " has 0 write access.",
+ S.getEnteringBlock()->getFirstNonPHI());
+ return false;
+ }
+
+ return true;
+}
+
+void MaximalStaticExpander::expandRead(Scop &S, MemoryAccess *MA,
+ isl::union_map &Dependences,
+ ScopArrayInfo *ExpandedSAI) {
+
+ // Get the current AM.
+ auto CurrentAccessMap = MA->getAccessRelation();
+
+ // Get RAW dependences for the current WA.
+ auto WriteDomainSet = MA->getAccessRelation().domain();
+ auto WriteDomain = isl::union_set(WriteDomainSet);
+
+ auto CurrentReadWriteDependences =
+ Dependences.reverse().intersect_domain(WriteDomain);
+
+ // If no dependences, no need to modify anything.
+ if (CurrentReadWriteDependences.is_empty()) {
+ return;
+ }
+
+ assert(isl_union_map_n_map(CurrentReadWriteDependences.get()) == 1 &&
+ "There are more than one RAW dependencies in the union map.");
+ auto NewAccessMap = isl::map::from_union_map(CurrentReadWriteDependences);
+
+ auto Id = ExpandedSAI->getBasePtrId();
+
+ // Replace the out tuple id with the one of the access array.
+ NewAccessMap = NewAccessMap.set_tuple_id(isl::dim::out, Id);
+
+ // Set the new access relation.
+ MA->setNewAccessRelation(NewAccessMap);
+}
+
+ScopArrayInfo *MaximalStaticExpander::expandWrite(Scop &S, MemoryAccess *MA) {
+
+ // Get the current AM.
+ auto CurrentAccessMap = MA->getAccessRelation();
+
+ unsigned in_dimensions = CurrentAccessMap.dim(isl::dim::in);
+
+ // Get domain from the current AM.
+ auto Domain = CurrentAccessMap.domain();
+
+ // Create a new AM from the domain.
+ auto NewAccessMap = isl::map::from_domain(Domain);
+
+ // Add dimensions to the new AM according to the current in_dim.
+ NewAccessMap = NewAccessMap.add_dims(isl::dim::out, in_dimensions);
+
+ // Create the string representing the name of the new SAI.
+ // One new SAI for each statement so that each write go to a different memory
+ // cell.
+ auto CurrentStmtDomain = MA->getStatement()->getDomain();
+ auto CurrentStmtName = CurrentStmtDomain.get_tuple_name();
+ auto CurrentOutId = CurrentAccessMap.get_tuple_id(isl::dim::out);
+ std::string CurrentOutIdString =
+ MA->getScopArrayInfo()->getName() + "_" + CurrentStmtName + "_expanded";
+
+ // Set the tuple id for the out dimension.
+ NewAccessMap = NewAccessMap.set_tuple_id(isl::dim::out, CurrentOutId);
+
+ // Create the size vector.
+ std::vector<unsigned> Sizes;
+ for (unsigned i = 0; i < in_dimensions; i++) {
+ assert(isDimBoundedByConstant(CurrentStmtDomain, i) &&
+ "Domain boundary are not constant.");
+ auto UpperBound = getConstant(CurrentStmtDomain.dim_max(i), true, false);
+ assert(!UpperBound.is_null() && UpperBound.is_pos() &&
+ !UpperBound.is_nan() &&
+ "The upper bound is not a positive integer.");
+ assert(UpperBound.le(isl::val(CurrentAccessMap.get_ctx(),
+ std::numeric_limits<int>::max() - 1)) &&
+ "The upper bound overflow a int.");
+ Sizes.push_back(UpperBound.get_num_si() + 1);
+ }
+
+ // Get the ElementType of the current SAI.
+ auto ElementType = MA->getLatestScopArrayInfo()->getElementType();
+
+ // Create (or get if already existing) the new expanded SAI.
+ auto ExpandedSAI =
+ S.createScopArrayInfo(ElementType, CurrentOutIdString, Sizes);
+ ExpandedSAI->setIsOnHeap(true);
+
+ // Get the out Id of the expanded Array.
+ auto NewOutId = ExpandedSAI->getBasePtrId();
+
+ // Set the out id of the new AM to the new SAI id.
+ NewAccessMap = NewAccessMap.set_tuple_id(isl::dim::out, NewOutId);
+
+ // Add constraints to linked output with input id.
+ auto SpaceMap = NewAccessMap.get_space();
+ auto ConstraintBasicMap =
+ isl::basic_map::equal(SpaceMap, SpaceMap.dim(isl::dim::in));
+ NewAccessMap = isl::map(ConstraintBasicMap);
+
+ // Set the new access relation map.
+ MA->setNewAccessRelation(NewAccessMap);
+
+ return ExpandedSAI;
+}
+
+void MaximalStaticExpander::emitRemark(StringRef Msg, Instruction *Inst) {
+ ORE->emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "ExpansionRejection", Inst)
+ << Msg);
+}
+
+bool MaximalStaticExpander::runOnScop(Scop &S) {
+
+ // Get the ORE from OptimizationRemarkEmitterWrapperPass.
+ ORE = &(getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE());
+
+ // Get the RAW Dependences.
+ auto &DI = getAnalysis<DependenceInfo>();
+ auto &D = DI.getDependences(Dependences::AL_Statement);
+ auto Dependences = isl::give(D.getDependences(Dependences::TYPE_RAW));
+
+ SmallPtrSet<ScopArrayInfo *, 4> CurrentSAI(S.arrays().begin(),
+ S.arrays().end());
+
+ for (auto SAI : CurrentSAI) {
+ SmallPtrSet<MemoryAccess *, 4> AllWrites;
+ SmallPtrSet<MemoryAccess *, 4> AllReads;
+ if (!isExpandable(SAI, AllWrites, AllReads, S, Dependences))
+ continue;
+
+ assert(AllWrites.size() == 1);
+
+ auto TheWrite = *(AllWrites.begin());
+ ScopArrayInfo *ExpandedArray = expandWrite(S, TheWrite);
+
+ for (MemoryAccess *MA : AllReads)
+ expandRead(S, MA, Dependences, ExpandedArray);
+ }
+
+ return false;
+}
+
+void MaximalStaticExpander::printScop(raw_ostream &OS, Scop &S) const {
+ S.print(OS, false);
+}
+
+void MaximalStaticExpander::getAnalysisUsage(AnalysisUsage &AU) const {
+ ScopPass::getAnalysisUsage(AU);
+ AU.addRequired<DependenceInfo>();
+ AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
+}
+
+Pass *polly::createMaximalStaticExpansionPass() {
+ return new MaximalStaticExpander();
+}
+
+INITIALIZE_PASS_BEGIN(MaximalStaticExpander, "polly-mse",
+ "Polly - Maximal static expansion of SCoP", false, false);
+INITIALIZE_PASS_DEPENDENCY(DependenceInfo);
+INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass);
+INITIALIZE_PASS_END(MaximalStaticExpander, "polly-mse",
+ "Polly - Maximal static expansion of SCoP", false, false)
Added: polly/trunk/test/MaximalStaticExpansion/read_from_original.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/MaximalStaticExpansion/read_from_original.ll?rev=310304&view=auto
==============================================================================
--- polly/trunk/test/MaximalStaticExpansion/read_from_original.ll (added)
+++ polly/trunk/test/MaximalStaticExpansion/read_from_original.ll Mon Aug 7 13:54:20 2017
@@ -0,0 +1,105 @@
+; RUN: opt -polly-canonicalize %loadPolly -polly-mse -analyze < %s | FileCheck %s
+; RUN: opt -polly-canonicalize %loadPolly -polly-mse -pass-remarks-analysis="polly-mse" -analyze < %s 2>&1| FileCheck %s --check-prefix=MSE
+;
+; Verify that Polly detects problems and does not expand the array
+;
+; Original source code :
+;
+; #define Ni 2000
+; #define Nj 3000
+;
+; double mse(double A[Ni], double B[Nj]) {
+; int i;
+; double tmp = 6;
+; for (i = 0; i < Ni; i++) {
+; for (int j = 2; j<Nj; j++) {
+; B[j-1] = j;
+; }
+; A[i] = B[i];
+; }
+; return tmp;
+; }
+;
+; Check that the pass detects the problem of read from original array after expansion.
+;
+; MSE: The expansion of MemRef_B would lead to a read from the original array.
+;
+; CHECK-NOT: double MemRef_B2_expanded[2000][3000]; // Element size 8
+;
+; Check that the memory accesses are not modified
+;
+; CHECK-NOT: new: { Stmt_for_body3[i0, i1] -> MemRef_B_Stmt_for_body3_expanded[i0, i1] };
+; CHECK-NOT: new: { Stmt_for_end[i0] -> MemRef_B_Stmt_for_body3_expanded
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind uwtable
+define double @mse(double* %A, double* %B) {
+entry:
+ %A.addr = alloca double*, align 8
+ %B.addr = alloca double*, align 8
+ %i = alloca i32, align 4
+ %tmp = alloca double, align 8
+ %j = alloca i32, align 4
+ store double* %A, double** %A.addr, align 8
+ store double* %B, double** %B.addr, align 8
+ store double 6.000000e+00, double* %tmp, align 8
+ store i32 0, i32* %i, align 4
+ br label %for.cond
+
+for.cond: ; preds = %for.inc8, %entry
+ %0 = load i32, i32* %i, align 4
+ %cmp = icmp slt i32 %0, 2000
+ br i1 %cmp, label %for.body, label %for.end10
+
+for.body: ; preds = %for.cond
+ store i32 2, i32* %j, align 4
+ br label %for.cond1
+
+for.cond1: ; preds = %for.inc, %for.body
+ %1 = load i32, i32* %j, align 4
+ %cmp2 = icmp slt i32 %1, 3000
+ br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3: ; preds = %for.cond1
+ %2 = load i32, i32* %j, align 4
+ %conv = sitofp i32 %2 to double
+ %3 = load double*, double** %B.addr, align 8
+ %4 = load i32, i32* %j, align 4
+ %sub = sub nsw i32 %4, 1
+ %idxprom = sext i32 %sub to i64
+ %arrayidx = getelementptr inbounds double, double* %3, i64 %idxprom
+ store double %conv, double* %arrayidx, align 8
+ br label %for.inc
+
+for.inc: ; preds = %for.body3
+ %5 = load i32, i32* %j, align 4
+ %inc = add nsw i32 %5, 1
+ store i32 %inc, i32* %j, align 4
+ br label %for.cond1
+
+for.end: ; preds = %for.cond1
+ %6 = load double*, double** %B.addr, align 8
+ %7 = load i32, i32* %i, align 4
+ %idxprom4 = sext i32 %7 to i64
+ %arrayidx5 = getelementptr inbounds double, double* %6, i64 %idxprom4
+ %8 = load double, double* %arrayidx5, align 8
+ %9 = load double*, double** %A.addr, align 8
+ %10 = load i32, i32* %i, align 4
+ %idxprom6 = sext i32 %10 to i64
+ %arrayidx7 = getelementptr inbounds double, double* %9, i64 %idxprom6
+ store double %8, double* %arrayidx7, align 8
+ br label %for.inc8
+
+for.inc8: ; preds = %for.end
+ %11 = load i32, i32* %i, align 4
+ %inc9 = add nsw i32 %11, 1
+ store i32 %inc9, i32* %i, align 4
+ br label %for.cond
+
+for.end10: ; preds = %for.cond
+ %12 = load double, double* %tmp, align 8
+ ret double %12
+}
+
Added: polly/trunk/test/MaximalStaticExpansion/too_many_writes.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/MaximalStaticExpansion/too_many_writes.ll?rev=310304&view=auto
==============================================================================
--- polly/trunk/test/MaximalStaticExpansion/too_many_writes.ll (added)
+++ polly/trunk/test/MaximalStaticExpansion/too_many_writes.ll Mon Aug 7 13:54:20 2017
@@ -0,0 +1,111 @@
+; RUN: opt -polly-canonicalize %loadPolly -polly-mse -analyze < %s | FileCheck %s
+; RUN: opt -polly-canonicalize %loadPolly -polly-mse -pass-remarks-analysis="polly-mse" -analyze < %s 2>&1 | FileCheck %s --check-prefix=MSE
+;
+; Verify that Polly detects problems and does not expand the array
+;
+; Original source code :
+;
+; #define Ni 2000
+; #define Nj 2000
+;
+; double mse(double A[Ni], double B[Nj]) {
+; int i;
+; double tmp = 6;
+; for (i = 0; i < Ni; i++) {
+; B[i] = 2;
+; for (int j = 0; j<Nj; j++) {
+; B[j] = j;
+; }
+; A[i] = B[i];
+; }
+; return tmp;
+; }
+;
+; Check that the pass detects that there are more than 1 write access per array.
+;
+; MSE: MemRef_B has more than 1 write access.
+;
+; Check that the SAI is not expanded
+;
+; CHECK-NOT: double MemRef_B2_expanded[2000][3000]; // Element size 8
+;
+; Check that the memory accesses are not modified
+;
+; CHECK-NOT: new: { Stmt_for_body3[i0, i1] -> MemRef_B_Stmt_for_body3_expanded[i0, i1] };
+; CHECK-NOT: new: { Stmt_for_end[i0] -> MemRef_B_Stmt_for_body3_expanded
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind uwtable
+define double @mse(double* %A, double* %B) {
+entry:
+ %A.addr = alloca double*, align 8
+ %B.addr = alloca double*, align 8
+ %i = alloca i32, align 4
+ %tmp = alloca double, align 8
+ %j = alloca i32, align 4
+ store double* %A, double** %A.addr, align 8
+ store double* %B, double** %B.addr, align 8
+ store double 6.000000e+00, double* %tmp, align 8
+ store i32 0, i32* %i, align 4
+ br label %for.cond
+
+for.cond: ; preds = %for.inc10, %entry
+ %0 = load i32, i32* %i, align 4
+ %cmp = icmp slt i32 %0, 2000
+ br i1 %cmp, label %for.body, label %for.end12
+
+for.body: ; preds = %for.cond
+ %1 = load double*, double** %B.addr, align 8
+ %2 = load i32, i32* %i, align 4
+ %idxprom = sext i32 %2 to i64
+ %arrayidx = getelementptr inbounds double, double* %1, i64 %idxprom
+ store double 2.000000e+00, double* %arrayidx, align 8
+ store i32 0, i32* %j, align 4
+ br label %for.cond1
+
+for.cond1: ; preds = %for.inc, %for.body
+ %3 = load i32, i32* %j, align 4
+ %cmp2 = icmp slt i32 %3, 2000
+ br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3: ; preds = %for.cond1
+ %4 = load i32, i32* %j, align 4
+ %conv = sitofp i32 %4 to double
+ %5 = load double*, double** %B.addr, align 8
+ %6 = load i32, i32* %j, align 4
+ %idxprom4 = sext i32 %6 to i64
+ %arrayidx5 = getelementptr inbounds double, double* %5, i64 %idxprom4
+ store double %conv, double* %arrayidx5, align 8
+ br label %for.inc
+
+for.inc: ; preds = %for.body3
+ %7 = load i32, i32* %j, align 4
+ %inc = add nsw i32 %7, 1
+ store i32 %inc, i32* %j, align 4
+ br label %for.cond1
+
+for.end: ; preds = %for.cond1
+ %8 = load double*, double** %B.addr, align 8
+ %9 = load i32, i32* %i, align 4
+ %idxprom6 = sext i32 %9 to i64
+ %arrayidx7 = getelementptr inbounds double, double* %8, i64 %idxprom6
+ %10 = load double, double* %arrayidx7, align 8
+ %11 = load double*, double** %A.addr, align 8
+ %12 = load i32, i32* %i, align 4
+ %idxprom8 = sext i32 %12 to i64
+ %arrayidx9 = getelementptr inbounds double, double* %11, i64 %idxprom8
+ store double %10, double* %arrayidx9, align 8
+ br label %for.inc10
+
+for.inc10: ; preds = %for.end
+ %13 = load i32, i32* %i, align 4
+ %inc11 = add nsw i32 %13, 1
+ store i32 %inc11, i32* %i, align 4
+ br label %for.cond
+
+for.end12: ; preds = %for.cond
+ %14 = load double, double* %tmp, align 8
+ ret double %14
+}
Added: polly/trunk/test/MaximalStaticExpansion/working_expansion.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/MaximalStaticExpansion/working_expansion.ll?rev=310304&view=auto
==============================================================================
--- polly/trunk/test/MaximalStaticExpansion/working_expansion.ll (added)
+++ polly/trunk/test/MaximalStaticExpansion/working_expansion.ll Mon Aug 7 13:54:20 2017
@@ -0,0 +1,101 @@
+; RUN: opt -polly-canonicalize %loadPolly -polly-mse -analyze < %s | FileCheck %s
+;
+; Verify that the accesses are correctly expanded
+;
+; Original source code :
+;
+; #define Ni 2000
+; #define Nj 3000
+;
+; double mse(double A[Ni], double B[Nj]) {
+; int i;
+; double tmp = 6;
+; for (i = 0; i < Ni; i++) {
+; for (int j = 0; j<Nj; j++) {
+; B[j] = j;
+; }
+; A[i] = B[i];
+; }
+; return tmp;
+; }
+;
+; Check if the expanded SAI are created
+;
+; CHECK: double MemRef_B_Stmt_for_body3_expanded[2000][3000]; // Element size 8
+;
+; Check if the memory accesses are modified
+;
+; CHECK: new: { Stmt_for_body3[i0, i1] -> MemRef_B_Stmt_for_body3_expanded[i0, i1] };
+; CHECK: new: { Stmt_for_end[i0] -> MemRef_B_Stmt_for_body3_expanded[i0, i0] };
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind uwtable
+define double @mse(double* %A, double* %B) {
+entry:
+ %A.addr = alloca double*, align 8
+ %B.addr = alloca double*, align 8
+ %i = alloca i32, align 4
+ %tmp = alloca double, align 8
+ %j = alloca i32, align 4
+ store double* %A, double** %A.addr, align 8
+ store double* %B, double** %B.addr, align 8
+ store double 6.000000e+00, double* %tmp, align 8
+ store i32 0, i32* %i, align 4
+ br label %for.cond
+
+for.cond: ; preds = %for.inc8, %entry
+ %0 = load i32, i32* %i, align 4
+ %cmp = icmp slt i32 %0, 2000
+ br i1 %cmp, label %for.body, label %for.end10
+
+for.body: ; preds = %for.cond
+ store i32 0, i32* %j, align 4
+ br label %for.cond1
+
+for.cond1: ; preds = %for.inc, %for.body
+ %1 = load i32, i32* %j, align 4
+ %cmp2 = icmp slt i32 %1, 3000
+ br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3: ; preds = %for.cond1
+ %2 = load i32, i32* %j, align 4
+ %conv = sitofp i32 %2 to double
+ %3 = load double*, double** %B.addr, align 8
+ %4 = load i32, i32* %j, align 4
+ %idxprom = sext i32 %4 to i64
+ %arrayidx = getelementptr inbounds double, double* %3, i64 %idxprom
+ store double %conv, double* %arrayidx, align 8
+ br label %for.inc
+
+for.inc: ; preds = %for.body3
+ %5 = load i32, i32* %j, align 4
+ %inc = add nsw i32 %5, 1
+ store i32 %inc, i32* %j, align 4
+ br label %for.cond1
+
+for.end: ; preds = %for.cond1
+ %6 = load double*, double** %B.addr, align 8
+ %7 = load i32, i32* %i, align 4
+ %idxprom4 = sext i32 %7 to i64
+ %arrayidx5 = getelementptr inbounds double, double* %6, i64 %idxprom4
+ %8 = load double, double* %arrayidx5, align 8
+ %9 = load double*, double** %A.addr, align 8
+ %10 = load i32, i32* %i, align 4
+ %idxprom6 = sext i32 %10 to i64
+ %arrayidx7 = getelementptr inbounds double, double* %9, i64 %idxprom6
+ store double %8, double* %arrayidx7, align 8
+ br label %for.inc8
+
+for.inc8: ; preds = %for.end
+ %11 = load i32, i32* %i, align 4
+ %inc9 = add nsw i32 %11, 1
+ store i32 %inc9, i32* %i, align 4
+ br label %for.cond
+
+for.end10: ; preds = %for.cond
+ %12 = load double, double* %tmp, align 8
+ ret double %12
+}
+
More information about the llvm-commits
mailing list