Index: polly/trunk/include/polly/CodeGen/BlockGenerators.h =================================================================== --- polly/trunk/include/polly/CodeGen/BlockGenerators.h +++ polly/trunk/include/polly/CodeGen/BlockGenerators.h @@ -366,8 +366,13 @@ /// @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. /// @@ -381,8 +386,10 @@ /// (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. /// @@ -493,6 +500,48 @@ 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. @@ -834,8 +883,11 @@ /// 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. /// Index: polly/trunk/include/polly/ScopInfo.h =================================================================== --- polly/trunk/include/polly/ScopInfo.h +++ polly/trunk/include/polly/ScopInfo.h @@ -317,6 +317,9 @@ /// @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; } @@ -743,11 +746,16 @@ /// 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 @@ -773,14 +781,44 @@ /// @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; @@ -842,26 +880,105 @@ /// 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; } Index: polly/trunk/lib/Analysis/ScopInfo.cpp =================================================================== --- polly/trunk/lib/Analysis/ScopInfo.cpp +++ polly/trunk/lib/Analysis/ScopInfo.cpp @@ -499,7 +499,7 @@ 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(User); @@ -507,10 +507,24 @@ 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(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()); } Index: polly/trunk/lib/CodeGen/BlockGenerators.cpp =================================================================== --- polly/trunk/lib/CodeGen/BlockGenerators.cpp +++ polly/trunk/lib/CodeGen/BlockGenerators.cpp @@ -172,8 +172,17 @@ 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); @@ -182,7 +191,7 @@ // 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()); @@ -191,9 +200,28 @@ 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 { @@ -320,13 +348,13 @@ 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; } @@ -417,12 +445,15 @@ 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(Address) || DT.dominates(cast(Address)->getParent(), Builder.GetInsertBlock())) && @@ -432,8 +463,9 @@ } } -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 " @@ -441,7 +473,7 @@ "RegionGenerator"); for (MemoryAccess *MA : Stmt) { - if (MA->isArrayKind() || MA->isRead()) + if (MA->isOriginalArrayKind() || MA->isRead()) continue; Value *Val = MA->getAccessValue(); @@ -456,7 +488,8 @@ "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(Val) || @@ -1132,7 +1165,7 @@ 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)) @@ -1257,7 +1290,7 @@ 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(); @@ -1329,18 +1362,20 @@ 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(NewVal) || DT.dominates(cast(NewVal)->getParent(), Builder.GetInsertBlock())) && Index: polly/trunk/lib/Exchange/JSONExporter.cpp =================================================================== --- polly/trunk/lib/Exchange/JSONExporter.cpp +++ polly/trunk/lib/Exchange/JSONExporter.cpp @@ -348,7 +348,11 @@ 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); @@ -376,12 +380,14 @@ bool SpecialAlignment = true; if (LoadInst *LoadI = dyn_cast(MA->getAccessInstruction())) { SpecialAlignment = + LoadI->getAlignment() && DL.getABITypeAlignment(LoadI->getType()) != LoadI->getAlignment(); } else if (StoreInst *StoreI = dyn_cast(MA->getAccessInstruction())) { SpecialAlignment = + StoreI->getAlignment() && DL.getABITypeAlignment(StoreI->getValueOperand()->getType()) != - StoreI->getAlignment(); + StoreI->getAlignment(); } if (SpecialAlignment) { Index: polly/trunk/test/Isl/CodeGen/MemAccess/map_scalar_access.ll =================================================================== --- polly/trunk/test/Isl/CodeGen/MemAccess/map_scalar_access.ll +++ polly/trunk/test/Isl/CodeGen/MemAccess/map_scalar_access.ll @@ -0,0 +1,149 @@ +; 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 Index: polly/trunk/test/Isl/CodeGen/MemAccess/map_scalar_access___%outer.for---%return.jscop =================================================================== --- polly/trunk/test/Isl/CodeGen/MemAccess/map_scalar_access___%outer.for---%return.jscop +++ polly/trunk/test/Isl/CodeGen/MemAccess/map_scalar_access___%outer.for---%return.jscop @@ -0,0 +1,83 @@ +{ + "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] }" + } + ] +} Index: polly/trunk/test/Isl/CodeGen/MemAccess/map_scalar_access___%outer.for---%return.jscop.transformed =================================================================== --- polly/trunk/test/Isl/CodeGen/MemAccess/map_scalar_access___%outer.for---%return.jscop.transformed +++ polly/trunk/test/Isl/CodeGen/MemAccess/map_scalar_access___%outer.for---%return.jscop.transformed @@ -0,0 +1,83 @@ +{ + "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] }" + } + ] +}