/// @brief Generate reload of scalars demoted to memory and needed by @p Stmt.
///
/// @param Stmt The statement we generate code for.
+ /// @param LTS A mapping from loops virtual canonical induction
+ /// variable to their new values.
/// @param BBMap A mapping from old values to their new values in this block.
- void generateScalarLoads(ScopStmt &Stmt, ValueMapT &BBMap);
+ /// @param NewAccesses A map from memory access ids to new ast expressions.
+ void generateScalarLoads(ScopStmt &Stmt, LoopToScevMapT <S,
+ ValueMapT &BBMap,
+ __isl_keep isl_id_to_ast_expr *NewAccesses);
/// @brief Generate the scalar stores for the given statement.
///
/// (for values recalculated in the new ScoP, but not
/// within this basic block)
/// @param BBMap A mapping from old values to their new values in this block.
+ /// @param NewAccesses A map from memory access ids to new ast expressions.
virtual void generateScalarStores(ScopStmt &Stmt, LoopToScevMapT <S,
- ValueMapT &BBMap);
+ ValueMapT &BBMap,
+ __isl_keep isl_id_to_ast_expr *NewAccesses);
/// @brief Handle users of @p Inst outside the SCoP.
///
ValueMapT &BBMap, LoopToScevMapT <S,
isl_id_to_ast_expr *NewAccesses);
+ /// @brief Generate the operand address.
+ ///
+ /// @param Stmt The statement to generate code for.
+ /// @param L The innermost loop that surrounds the statement.
+ /// @param Pointer If the access expression is not changed (ie. not found
+ /// in @p LTS), use this Pointer from the original code
+ /// instead.
+ /// @param BBMap A mapping from old values to their new values.
+ /// @param LTS A mapping from loops virtual canonical induction
+ /// variable to their new values.
+ /// @param NewAccesses Ahead-of-time generated access expressions.
+ /// @param Id Identifier of the MemoryAccess to generate.
+ /// @param ExpectedType The type the returned value should have.
+ ///
+ /// @return The generated address.
+ Value *generateLocationAccessed(ScopStmt &Stmt, Loop *L, Value *Pointer,
+ ValueMapT &BBMap, LoopToScevMapT <S,
+ isl_id_to_ast_expr *NewAccesses,
+ __isl_take isl_id *Id, Type *ExpectedType);
+
+ /// @brief Generate the pointer value that is accesses by @p Access.
+ ///
+ /// For write accesses, generate the target address. For read accesses,
+ /// generate the source address.
+ /// The access can be either an array access or a scalar access. In the first
+ /// case, the returned address will point to an element into that array. In
+ /// the scalar case, an alloca is used.
+ /// If a new AccessRelation is set for the MemoryAccess, the new relation will
+ /// be used.
+ ///
+ /// @param Access The access to generate a pointer for.
+ /// @param L The innermost loop that surrounds the statement.
+ /// @param LTS A mapping from loops virtual canonical induction
+ /// variable to their new values.
+ /// @param BBMap A mapping from old values to their new values.
+ /// @param NewAccesses A map from memory access ids to new ast expressions.
+ ///
+ /// @return The generated address.
+ Value *getImplicitAddress(MemoryAccess &Access, Loop *L, LoopToScevMapT <S,
+ ValueMapT &BBMap,
+ __isl_keep isl_id_to_ast_expr *NewAccesses);
+
/// @param NewAccesses A map from memory access ids to new ast expressions,
/// which may contain new access expressions for certain
/// memory accesses.
/// their new values (for values recalculated in the new ScoP,
/// but not within this basic block)
/// @param BBMap A mapping from old values to their new values in this block.
- virtual void generateScalarStores(ScopStmt &Stmt, LoopToScevMapT <S,
- ValueMapT &BBMAp) override;
+ /// @param LTS A mapping from loops virtual canonical induction variable to
+ /// their new values.
+ virtual void
+ generateScalarStores(ScopStmt &Stmt, LoopToScevMapT <S, ValueMapT &BBMAp,
+ __isl_keep isl_id_to_ast_expr *NewAccesses) override;
/// @brief Copy a single PHI instruction.
///
/// @brief Return the isl id for the base pointer.
__isl_give isl_id *getBasePtrId() const;
+ /// @brief Return what kind of memory this represents.
+ enum MemoryKind getKind() const { return Kind; }
+
/// @brief Is this array info modeling an llvm::Value?
bool isValueKind() const { return Kind == MK_Value; }
/// As 2) is by construction "newer" than 1) we return the new access
/// relation if present.
///
- __isl_give isl_map *getAccessRelation() const {
+ __isl_give isl_map *getLatestAccessRelation() const {
return hasNewAccessRelation() ? getNewAccessRelation()
: getOriginalAccessRelation();
}
+ /// @brief Old name of getLatestAccessRelation().
+ __isl_give isl_map *getAccessRelation() const {
+ return getLatestAccessRelation();
+ }
+
/// @brief Get an isl map describing the memory address accessed.
///
/// In most cases the memory address accessed is well described by the access
/// @brief Get an isl string representing a new access function, if available.
std::string getNewAccessRelationStr() const;
- /// @brief Get the base address of this access (e.g. A for A[i+j]).
- Value *getBaseAddr() const { return BaseAddr; }
+ /// @brief Get the base address of this access (e.g. A for A[i+j]) when
+ /// detected.
+ Value *getOriginalBaseAddr() const {
+ assert(!getOriginalScopArrayInfo() /* may noy yet be initialized */ ||
+ getOriginalScopArrayInfo()->getBasePtr() == BaseAddr);
+ return BaseAddr;
+ }
+
+ /// @brief Get the base address of this access (e.g. A for A[i+j]) after a
+ /// potential change by setNewAccessRelation().
+ Value *getLatestBaseAddr() const {
+ return getLatestScopArrayInfo()->getBasePtr();
+ }
+
+ /// @brief Old name for getOriginalBaseAddr().
+ Value *getBaseAddr() const { return getOriginalBaseAddr(); }
+
+ /// @brief Get the detection-time base array isl_id for this access.
+ __isl_give isl_id *getOriginalArrayId() const;
+
+ /// @brief Get the base array isl_id for this access, modifiable through
+ /// setNewAccessRelation().
+ __isl_give isl_id *getLatestArrayId() const;
- /// @brief Get the base array isl_id for this access.
- __isl_give isl_id *getArrayId() const;
+ /// @brief Old name of getOriginalArrayId().
+ __isl_give isl_id *getArrayId() const { return getOriginalArrayId(); }
- /// @brief Get the ScopArrayInfo object for the base address.
- const ScopArrayInfo *getScopArrayInfo() const;
+ /// @brief Get the detection-time ScopArrayInfo object for the base address.
+ const ScopArrayInfo *getOriginalScopArrayInfo() const;
+
+ /// @brief Get the ScopArrayInfo object for the base address, or the one set
+ /// by setNewAccessRelation().
+ const ScopArrayInfo *getLatestScopArrayInfo() const;
+
+ /// @brief Legacy name of getOriginalScopArrayInfo().
+ const ScopArrayInfo *getScopArrayInfo() const {
+ return getOriginalScopArrayInfo();
+ }
/// @brief Return a string representation of the access's reduction type.
const std::string getReductionOperatorStr() const;
/// statement.
bool isStrideZero(__isl_take const isl_map *Schedule) const;
+ /// @brief Return the kind when this access was first detected.
+ ScopArrayInfo::MemoryKind getOriginalKind() const {
+ assert(!getOriginalScopArrayInfo() /* not yet initialized */ ||
+ getOriginalScopArrayInfo()->getKind() == Kind);
+ return Kind;
+ }
+
+ /// @brief Return the kind considering a potential setNewAccessRelation.
+ ScopArrayInfo::MemoryKind getLatestKind() const {
+ return getLatestScopArrayInfo()->getKind();
+ }
+
/// @brief Whether this is an access of an explicit load or store in the IR.
- bool isArrayKind() const { return Kind == ScopArrayInfo::MK_Array; }
+ bool isOriginalArrayKind() const {
+ return getOriginalKind() == ScopArrayInfo::MK_Array;
+ }
+
+ /// @brief Whether storage memory is either an custom .s2a/.phiops alloca
+ /// (false) or an existing pointer into an array (true).
+ bool isLatestArrayKind() const {
+ return getLatestKind() == ScopArrayInfo::MK_Array;
+ }
+
+ /// @brief Old name of isOriginalArrayKind.
+ bool isArrayKind() const { return isOriginalArrayKind(); }
- /// @brief Whether this access is an array to a scalar memory object.
+ /// @brief Whether this access is an array to a scalar memory object, without
+ /// considering changes by setNewAccessRelation.
///
/// Scalar accesses are accesses to MK_Value, MK_PHI or MK_ExitPHI.
- bool isScalarKind() const { return !isArrayKind(); }
+ bool isOriginalScalarKind() const {
+ return getOriginalKind() != ScopArrayInfo::MK_Array;
+ }
- /// @brief Is this MemoryAccess modeling scalar dependences?
- bool isValueKind() const { return Kind == ScopArrayInfo::MK_Value; }
+ /// @brief Whether this access is an array to a scalar memory object, also
+ /// considering changes by setNewAccessRelation.
+ bool isLatestScalarKind() const {
+ return getLatestKind() != ScopArrayInfo::MK_Array;
+ }
- /// @brief Is this MemoryAccess modeling special PHI node accesses?
- bool isPHIKind() const { return Kind == ScopArrayInfo::MK_PHI; }
+ /// @brief Old name of isOriginalScalarKind.
+ bool isScalarKind() const { return isOriginalScalarKind(); }
- /// @brief Is this MemoryAccess modeling the accesses of a PHI node in the
+ /// @brief Was this MemoryAccess detected as a scalar dependences?
+ bool isOriginalValueKind() const {
+ return getOriginalKind() == ScopArrayInfo::MK_Value;
+ }
+
+ /// @brief Is this MemoryAccess currently modeling scalar dependences?
+ bool isLatestValueKind() const {
+ return getLatestKind() == ScopArrayInfo::MK_Value;
+ }
+
+ /// @brief Old name of isOriginalValueKind().
+ bool isValueKind() const { return isOriginalValueKind(); }
+
+ /// @brief Was this MemoryAccess detected as a special PHI node access?
+ bool isOriginalPHIKind() const {
+ return getOriginalKind() == ScopArrayInfo::MK_PHI;
+ }
+
+ /// @brief Is this MemoryAccess modeling special PHI node accesses, also
+ /// considering a potential change by setNewAccessRelation?
+ bool isLatestPHIKind() const {
+ return getLatestKind() == ScopArrayInfo::MK_PHI;
+ }
+
+ /// @brief Old name of isOriginalPHIKind.
+ bool isPHIKind() const { return isOriginalPHIKind(); }
+
+ /// @brief Was this MemoryAccess detected as the accesses of a PHI node in the
/// SCoP's exit block?
- bool isExitPHIKind() const { return Kind == ScopArrayInfo::MK_ExitPHI; }
+ bool isOriginalExitPHIKind() const {
+ return getOriginalKind() == ScopArrayInfo::MK_ExitPHI;
+ }
+
+ /// @brief Is this MemoryAccess modeling the accesses of a PHI node in the
+ /// SCoP's exit block? Can be changed to an array access using
+ /// setNewAccessRelation().
+ bool isLatestExitPHIKind() const {
+ return getLatestKind() == ScopArrayInfo::MK_ExitPHI;
+ }
+
+ /// @brief Old name of isOriginalExitPHIKind().
+ bool isExitPHIKind() const { return isOriginalExitPHIKind(); }
+
+ /// @brief Was this access detected as one of the two PHI types?
+ bool isOriginalAnyPHIKind() const {
+ return isOriginalPHIKind() || isOriginalExitPHIKind();
+ }
+
+ /// @brief Does this access orginate from one of the two PHI types? Can be
+ /// changed to an array access using setNewAccessRelation().
+ bool isLatestAnyPHIKind() const {
+ return isLatestPHIKind() || isLatestExitPHIKind();
+ }
- /// @brief Does this access orginate from one of the two PHI types?
- bool isAnyPHIKind() const { return isPHIKind() || isExitPHIKind(); }
+ /// @brief Old name of isOriginalAnyPHIKind().
+ bool isAnyPHIKind() const { return isOriginalAnyPHIKind(); }
/// @brief Get the statement that contains this memory access.
ScopStmt *getStatement() const { return Statement; }
isl_map_free(NewAccessRelation);
}
-const ScopArrayInfo *MemoryAccess::getScopArrayInfo() const {
+const ScopArrayInfo *MemoryAccess::getOriginalScopArrayInfo() const {
isl_id *ArrayId = getArrayId();
void *User = isl_id_get_user(ArrayId);
const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
return SAI;
}
-__isl_give isl_id *MemoryAccess::getArrayId() const {
+const ScopArrayInfo *MemoryAccess::getLatestScopArrayInfo() const {
+ isl_id *ArrayId = getLatestArrayId();
+ void *User = isl_id_get_user(ArrayId);
+ const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
+ isl_id_free(ArrayId);
+ return SAI;
+}
+
+__isl_give isl_id *MemoryAccess::getOriginalArrayId() const {
return isl_map_get_tuple_id(AccessRelation, isl_dim_out);
}
+__isl_give isl_id *MemoryAccess::getLatestArrayId() const {
+ if (!hasNewAccessRelation())
+ return getOriginalArrayId();
+ return isl_map_get_tuple_id(NewAccessRelation, isl_dim_out);
+}
+
__isl_give isl_map *MemoryAccess::getAddressFunction() const {
return isl_map_lexmin(getAccessRelation());
}
ValueMapT &BBMap, LoopToScevMapT <S,
isl_id_to_ast_expr *NewAccesses) {
const MemoryAccess &MA = Stmt.getArrayAccessFor(Inst);
+ return generateLocationAccessed(
+ Stmt, getLoopForStmt(Stmt),
+ Inst.isNull() ? nullptr : Inst.getPointerOperand(), BBMap, LTS,
+ NewAccesses, MA.getId(), MA.getAccessValue()->getType());
+}
- isl_ast_expr *AccessExpr = isl_id_to_ast_expr_get(NewAccesses, MA.getId());
+Value *BlockGenerator::generateLocationAccessed(
+ ScopStmt &Stmt, Loop *L, Value *Pointer, ValueMapT &BBMap,
+ LoopToScevMapT <S, isl_id_to_ast_expr *NewAccesses, __isl_take isl_id *Id,
+ Type *ExpectedType) {
+ isl_ast_expr *AccessExpr = isl_id_to_ast_expr_get(NewAccesses, Id);
if (AccessExpr) {
AccessExpr = isl_ast_expr_address_of(AccessExpr);
// Cast the address of this memory access to a pointer type that has the
// same element type as the original access, but uses the address space of
// the newly generated pointer.
- auto OldPtrTy = MA.getAccessValue()->getType()->getPointerTo();
+ auto OldPtrTy = ExpectedType->getPointerTo();
auto NewPtrTy = Address->getType();
OldPtrTy = PointerType::get(OldPtrTy->getElementType(),
NewPtrTy->getPointerAddressSpace());
Address = Builder.CreateBitOrPointerCast(Address, OldPtrTy);
return Address;
}
+ assert(
+ Pointer &&
+ "If expression was not generated, must use the original pointer value");
+ return getNewValue(Stmt, Pointer, BBMap, LTS, L);
+}
+
+Value *
+BlockGenerator::getImplicitAddress(MemoryAccess &Access, Loop *L,
+ LoopToScevMapT <S, ValueMapT &BBMap,
+ __isl_keep isl_id_to_ast_expr *NewAccesses) {
+ if (Access.isLatestArrayKind())
+ return generateLocationAccessed(*Access.getStatement(), L, nullptr, BBMap,
+ LTS, NewAccesses, Access.getId(),
+ Access.getAccessValue()->getType());
+
+ if (Access.isLatestValueKind() || Access.isLatestExitPHIKind())
+ return getOrCreateScalarAlloca(Access.getBaseAddr());
+
+ if (Access.isLatestPHIKind())
+ return getOrCreatePHIAlloca(Access.getBaseAddr());
- return getNewValue(Stmt, Inst.getPointerOperand(), BBMap, LTS,
- getLoopForStmt(Stmt));
+ llvm_unreachable("Unknown access type");
}
Loop *BlockGenerator::getLoopForStmt(const ScopStmt &Stmt) const {
isl_id_to_ast_expr *NewAccesses) {
BasicBlock *CopyBB = splitBB(BB);
Builder.SetInsertPoint(&CopyBB->front());
- generateScalarLoads(Stmt, BBMap);
+ generateScalarLoads(Stmt, LTS, BBMap, NewAccesses);
copyBB(Stmt, BB, CopyBB, BBMap, LTS, NewAccesses);
// After a basic block was copied store all scalars that escape this block in
// their alloca.
- generateScalarStores(Stmt, LTS, BBMap);
+ generateScalarStores(Stmt, LTS, BBMap, NewAccesses);
return CopyBB;
}
EscapeMap[Inst] = std::make_pair(ScalarAddr, std::move(EscapeUsers));
}
-void BlockGenerator::generateScalarLoads(ScopStmt &Stmt, ValueMapT &BBMap) {
+void BlockGenerator::generateScalarLoads(
+ ScopStmt &Stmt, LoopToScevMapT <S, ValueMapT &BBMap,
+ __isl_keep isl_id_to_ast_expr *NewAccesses) {
for (MemoryAccess *MA : Stmt) {
- if (MA->isArrayKind() || MA->isWrite())
+ if (MA->isOriginalArrayKind() || MA->isWrite())
continue;
- auto *Address = getOrCreateAlloca(*MA);
+ auto *Address =
+ getImplicitAddress(*MA, getLoopForStmt(Stmt), LTS, BBMap, NewAccesses);
assert((!isa<Instruction>(Address) ||
DT.dominates(cast<Instruction>(Address)->getParent(),
Builder.GetInsertBlock())) &&
}
}
-void BlockGenerator::generateScalarStores(ScopStmt &Stmt, LoopToScevMapT <S,
- ValueMapT &BBMap) {
+void BlockGenerator::generateScalarStores(
+ ScopStmt &Stmt, LoopToScevMapT <S, ValueMapT &BBMap,
+ __isl_keep isl_id_to_ast_expr *NewAccesses) {
Loop *L = LI.getLoopFor(Stmt.getBasicBlock());
assert(Stmt.isBlockStmt() && "Region statements need to use the "
"RegionGenerator");
for (MemoryAccess *MA : Stmt) {
- if (MA->isArrayKind() || MA->isRead())
+ if (MA->isOriginalArrayKind() || MA->isRead())
continue;
Value *Val = MA->getAccessValue();
"Incoming block must be statement's block");
Val = MA->getIncoming()[0].second;
}
- auto *Address = getOrCreateAlloca(*MA);
+ auto Address =
+ getImplicitAddress(*MA, getLoopForStmt(Stmt), LTS, BBMap, NewAccesses);
Val = getNewValue(Stmt, Val, BBMap, LTS, L);
assert((!isa<Instruction>(Val) ||
Builder.SetInsertPoint(&EntryBBCopy->front());
ValueMapT &EntryBBMap = RegionMaps[EntryBBCopy];
- generateScalarLoads(Stmt, EntryBBMap);
+ generateScalarLoads(Stmt, LTS, EntryBBMap, IdToAstExp);
for (auto PI = pred_begin(EntryBB), PE = pred_end(EntryBB); PI != PE; ++PI)
if (!R->contains(*PI))
Builder.SetInsertPoint(&*ExitBBCopy->getFirstInsertionPt());
// Write values visible to other statements.
- generateScalarStores(Stmt, LTS, ValueMap);
+ generateScalarStores(Stmt, LTS, ValueMap, IdToAstExp);
BlockMap.clear();
RegionMaps.clear();
IncompletePHINodeMap.clear();
return getNewValue(*Stmt, OldVal, BBMap, LTS, L);
}
-void RegionGenerator::generateScalarStores(ScopStmt &Stmt, LoopToScevMapT <S,
- ValueMapT &BBMap) {
+void RegionGenerator::generateScalarStores(
+ ScopStmt &Stmt, LoopToScevMapT <S, ValueMapT &BBMap,
+ __isl_keep isl_id_to_ast_expr *NewAccesses) {
assert(Stmt.getRegion() &&
"Block statements need to use the generateScalarStores() "
"function in the BlockGenerator");
for (MemoryAccess *MA : Stmt) {
- if (MA->isArrayKind() || MA->isRead())
+ if (MA->isOriginalArrayKind() || MA->isRead())
continue;
Value *NewVal = getExitScalar(MA, LTS, BBMap);
- Value *Address = getOrCreateAlloca(*MA);
+ Value *Address =
+ getImplicitAddress(*MA, getLoopForStmt(Stmt), LTS, BBMap, NewAccesses);
assert((!isa<Instruction>(NewVal) ||
DT.dominates(cast<Instruction>(NewVal)->getParent(),
Builder.GetInsertBlock())) &&
isl_id *NewOutId;
- if (MA->isArrayKind()) {
+ // If the NewAccessMap has zero dimensions, it is the scalar access; it
+ // must be the same as before.
+ // If it has at least one dimension, it's an array access; search for its
+ // ScopArrayInfo.
+ if (isl_map_dim(NewAccessMap, isl_dim_out) >= 1) {
NewOutId = isl_map_get_tuple_id(NewAccessMap, isl_dim_out);
auto *SAI = S.getArrayInfoByName(isl_id_get_name(NewOutId));
isl_id *OutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out);
bool SpecialAlignment = true;
if (LoadInst *LoadI = dyn_cast<LoadInst>(MA->getAccessInstruction())) {
SpecialAlignment =
+ LoadI->getAlignment() &&
DL.getABITypeAlignment(LoadI->getType()) != LoadI->getAlignment();
} else if (StoreInst *StoreI =
dyn_cast<StoreInst>(MA->getAccessInstruction())) {
SpecialAlignment =
+ StoreI->getAlignment() &&
DL.getABITypeAlignment(StoreI->getValueOperand()->getType()) !=
- StoreI->getAlignment();
+ StoreI->getAlignment();
}
if (SpecialAlignment) {
--- /dev/null
+; RUN: opt %loadPolly -polly-import-jscop-dir=%S -polly-import-jscop-postfix=transformed -polly-import-jscop -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-import-jscop-dir=%S -polly-import-jscop-postfix=transformed -polly-import-jscop -polly-codegen -S < %s | FileCheck %s --check-prefix=CODEGEN
+
+define void @map_scalar_access(double* noalias nonnull %A) {
+entry:
+ br label %outer.for
+
+outer.for:
+ %j = phi i32 [0, %entry], [%j.inc, %outer.inc]
+ %j.cmp = icmp slt i32 %j, 1
+ br i1 %j.cmp, label %reduction.for, label %outer.exit
+
+
+ reduction.for:
+ %i = phi i32 [0, %outer.for], [%i.inc, %reduction.inc]
+ %phi = phi double [0.0, %outer.for], [%add, %reduction.inc]
+ %i.cmp = icmp slt i32 %i, 4
+ br i1 %i.cmp, label %body, label %reduction.exit
+
+ body:
+ %add = fadd double %phi, 4.2
+ br label %reduction.inc
+
+ reduction.inc:
+ %i.inc = add nuw nsw i32 %i, 1
+ br label %reduction.for
+
+ reduction.exit:
+ %A_idx = getelementptr inbounds double, double* %A, i32 %j
+ store double %phi, double* %A_idx
+ br label %outer.inc
+
+
+outer.inc:
+ %j.inc = add nuw nsw i32 %j, 1
+ br label %outer.for
+
+outer.exit:
+ br label %return
+
+return:
+ ret void
+}
+
+
+
+; CHECK: Arrays {
+; CHECK-NEXT: double MemRef_phi__phi; // Element size 8
+; CHECK-NEXT: double MemRef_phi; // Element size 8
+; CHECK-NEXT: double MemRef_add; // Element size 8
+; CHECK-NEXT: double MemRef_A[*]; // Element size 8
+; CHECK-NEXT: }
+; CHECK: Statements {
+; CHECK-NEXT: Stmt_outer_for
+; CHECK-NEXT: Domain :=
+; CHECK-NEXT: { Stmt_outer_for[i0] : 0 <= i0 <= 1 };
+; CHECK-NEXT: Schedule :=
+; CHECK-NEXT: { Stmt_outer_for[i0] -> [i0, 0, 0, 0] };
+; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT: { Stmt_outer_for[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT: new: { Stmt_outer_for[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: Stmt_reduction_for
+; CHECK-NEXT: Domain :=
+; CHECK-NEXT: { Stmt_reduction_for[0, i1] : 0 <= i1 <= 4 };
+; CHECK-NEXT: Schedule :=
+; CHECK-NEXT: { Stmt_reduction_for[i0, i1] -> [0, 1, i1, 0] };
+; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT: { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT: new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT: { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT: new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT: Stmt_body
+; CHECK-NEXT: Domain :=
+; CHECK-NEXT: { Stmt_body[0, i1] : 0 <= i1 <= 3 };
+; CHECK-NEXT: Schedule :=
+; CHECK-NEXT: { Stmt_body[i0, i1] -> [0, 1, i1, 1] };
+; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT: { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT: new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT: { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT: new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT: Stmt_reduction_inc
+; CHECK-NEXT: Domain :=
+; CHECK-NEXT: { Stmt_reduction_inc[0, i1] : 0 <= i1 <= 3 };
+; CHECK-NEXT: Schedule :=
+; CHECK-NEXT: { Stmt_reduction_inc[i0, i1] -> [0, 1, i1, 2] };
+; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT: { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT: new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT: { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT: new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT: Stmt_reduction_exit
+; CHECK-NEXT: Domain :=
+; CHECK-NEXT: { Stmt_reduction_exit[0] };
+; CHECK-NEXT: Schedule :=
+; CHECK-NEXT: { Stmt_reduction_exit[i0] -> [0, 2, 0, 0] };
+; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT: { Stmt_reduction_exit[i0] -> MemRef_A[0] };
+; CHECK-NEXT: new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT: { Stmt_reduction_exit[i0] -> MemRef_phi[] };
+; CHECK-NEXT: new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+; CHECK: New access function '{ Stmt_outer_for[i0] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_reduction_for[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_reduction_for[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_body[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_body[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_reduction_exit[i0] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_reduction_exit[i0] -> MemRef_A[i0] }' detected in JSCOP file
+
+; CODEGEN: polly.stmt.outer.for:
+; CODEGEN-NEXT: %polly.access.A[[R0:[0-9]*]] = getelementptr double, double* %A, i64 %polly.indvar
+; CODEGEN-NEXT: store double 0.000000e+00, double* %polly.access.A[[R0]]
+; CODEGEN-NEXT: br label %polly.cond
+
+; CODEGEN: polly.stmt.reduction.exit:
+; CODEGEN-NEXT: %polly.access.A[[R1:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT: %polly.access.A[[R1]].reload = load double, double* %polly.access.A[[R1]]
+; CODEGEN-NEXT: %polly.access.A[[R2:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT: store double %polly.access.A[[R1]].reload, double* %polly.access.A[[R2]]
+; CODEGEN-NEXT: br label %polly.merge
+
+; CODEGEN: polly.stmt.reduction.for:
+; CODEGEN-NEXT: %polly.access.A[[R3:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT: %polly.access.A[[R3]].reload = load double, double* %polly.access.A[[R3]]
+; CODEGEN-NEXT: %polly.access.A[[R4:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT: store double %polly.access.A[[R3]].reload, double* %polly.access.A[[R4]]
+; CODEGEN-NEXT: br label %polly.cond9
+
+; CODEGEN: polly.stmt.body:
+; CODEGEN-NEXT: %polly.access.A[[R5:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT: %polly.access.A[[R5]].reload = load double, double* %polly.access.A[[R5]]
+; CODEGEN-NEXT: %p_add = fadd double %polly.access.A13.reload, 4.200000e+00
+; CODEGEN-NEXT: %polly.access.A[[R6:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT: store double %p_add, double* %polly.access.A[[R6]]
+; CODEGEN-NEXT: br label %polly.stmt.reduction.inc
+
+; CODEGEN: polly.stmt.reduction.inc:
+; CODEGEN-NEXT: %polly.access.A[[R7:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT: %polly.access.A[[R7]].reload = load double, double* %polly.access.A[[R7]]
+; CODEGEN-NEXT: %polly.access.A[[R8:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT: store double %polly.access.A[[R7]].reload, double* %polly.access.A[[R8]]
+; CODEGEN-NEXT: br label %polly.merge10
--- /dev/null
+{
+ "arrays" : [
+ {
+ "name" : "MemRef_A",
+ "type" : "double"
+ }
+ ],
+ "context" : "{ : }",
+ "name" : "%outer.for---%return",
+ "statements" : [
+ {
+ "accesses" : [
+ {
+ "kind" : "write",
+ "relation" : "{ Stmt_outer_for[i0] -> MemRef_phi__phi[] }"
+ }
+ ],
+ "domain" : "{ Stmt_outer_for[i0] : 0 <= i0 <= 1 }",
+ "name" : "Stmt_outer_for",
+ "schedule" : "{ Stmt_outer_for[i0] -> [i0, 0, 0, 0] }"
+ },
+ {
+ "accesses" : [
+ {
+ "kind" : "read",
+ "relation" : "{ Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] }"
+ },
+ {
+ "kind" : "write",
+ "relation" : "{ Stmt_reduction_for[i0, i1] -> MemRef_phi[] }"
+ }
+ ],
+ "domain" : "{ Stmt_reduction_for[0, i1] : 0 <= i1 <= 4 }",
+ "name" : "Stmt_reduction_for",
+ "schedule" : "{ Stmt_reduction_for[i0, i1] -> [0, 1, i1, 0] }"
+ },
+ {
+ "accesses" : [
+ {
+ "kind" : "write",
+ "relation" : "{ Stmt_body[i0, i1] -> MemRef_add[] }"
+ },
+ {
+ "kind" : "read",
+ "relation" : "{ Stmt_body[i0, i1] -> MemRef_phi[] }"
+ }
+ ],
+ "domain" : "{ Stmt_body[0, i1] : 0 <= i1 <= 3 }",
+ "name" : "Stmt_body",
+ "schedule" : "{ Stmt_body[i0, i1] -> [0, 1, i1, 1] }"
+ },
+ {
+ "accesses" : [
+ {
+ "kind" : "read",
+ "relation" : "{ Stmt_reduction_inc[i0, i1] -> MemRef_add[] }"
+ },
+ {
+ "kind" : "write",
+ "relation" : "{ Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] }"
+ }
+ ],
+ "domain" : "{ Stmt_reduction_inc[0, i1] : 0 <= i1 <= 3 }",
+ "name" : "Stmt_reduction_inc",
+ "schedule" : "{ Stmt_reduction_inc[i0, i1] -> [0, 1, i1, 2] }"
+ },
+ {
+ "accesses" : [
+ {
+ "kind" : "write",
+ "relation" : "{ Stmt_reduction_exit[i0] -> MemRef_A[0] }"
+ },
+ {
+ "kind" : "read",
+ "relation" : "{ Stmt_reduction_exit[i0] -> MemRef_phi[] }"
+ }
+ ],
+ "domain" : "{ Stmt_reduction_exit[0] }",
+ "name" : "Stmt_reduction_exit",
+ "schedule" : "{ Stmt_reduction_exit[i0] -> [0, 2, 0, 0] }"
+ }
+ ]
+}
--- /dev/null
+{
+ "arrays" : [
+ {
+ "name" : "MemRef_A",
+ "type" : "double"
+ }
+ ],
+ "context" : "{ : }",
+ "name" : "%outer.for---%return",
+ "statements" : [
+ {
+ "accesses" : [
+ {
+ "kind" : "write",
+ "relation" : "{ Stmt_outer_for[i0] -> MemRef_A[i0] }"
+ }
+ ],
+ "domain" : "{ Stmt_outer_for[i0] : 0 <= i0 <= 1 }",
+ "name" : "Stmt_outer_for",
+ "schedule" : "{ Stmt_outer_for[i0] -> [i0, 0, 0, 0] }"
+ },
+ {
+ "accesses" : [
+ {
+ "kind" : "read",
+ "relation" : "{ Stmt_reduction_for[i0, i1] -> MemRef_A[i0] }"
+ },
+ {
+ "kind" : "write",
+ "relation" : "{ Stmt_reduction_for[i0, i1] -> MemRef_A[i0] }"
+ }
+ ],
+ "domain" : "{ Stmt_reduction_for[0, i1] : 0 <= i1 <= 4 }",
+ "name" : "Stmt_reduction_for",
+ "schedule" : "{ Stmt_reduction_for[i0, i1] -> [0, 1, i1, 0] }"
+ },
+ {
+ "accesses" : [
+ {
+ "kind" : "write",
+ "relation" : "{ Stmt_body[i0, i1] -> MemRef_A[i0] }"
+ },
+ {
+ "kind" : "read",
+ "relation" : "{ Stmt_body[i0, i1] -> MemRef_A[i0] }"
+ }
+ ],
+ "domain" : "{ Stmt_body[0, i1] : 0 <= i1 <= 3 }",
+ "name" : "Stmt_body",
+ "schedule" : "{ Stmt_body[i0, i1] -> [0, 1, i1, 1] }"
+ },
+ {
+ "accesses" : [
+ {
+ "kind" : "read",
+ "relation" : "{ Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] }"
+ },
+ {
+ "kind" : "write",
+ "relation" : "{ Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] }"
+ }
+ ],
+ "domain" : "{ Stmt_reduction_inc[0, i1] : 0 <= i1 <= 3 }",
+ "name" : "Stmt_reduction_inc",
+ "schedule" : "{ Stmt_reduction_inc[i0, i1] -> [0, 1, i1, 2] }"
+ },
+ {
+ "accesses" : [
+ {
+ "kind" : "write",
+ "relation" : "{ Stmt_reduction_exit[i0] -> MemRef_A[i0] }"
+ },
+ {
+ "kind" : "read",
+ "relation" : "{ Stmt_reduction_exit[i0] -> MemRef_A[i0] }"
+ }
+ ],
+ "domain" : "{ Stmt_reduction_exit[0] }",
+ "name" : "Stmt_reduction_exit",
+ "schedule" : "{ Stmt_reduction_exit[i0] -> [0, 2, 0, 0] }"
+ }
+ ]
+}