Index: include/polly/ScopInfo.h =================================================================== --- include/polly/ScopInfo.h +++ include/polly/ScopInfo.h @@ -1833,6 +1833,21 @@ /// void hoistInvariantLoads(); + /// Unify indirect arrays with base pointers from the same equivalence class. + /// + /// In case the IR we read reloads base pointers multiple times, we will have + /// modeled accesses relative these base pointers as different arrays. This + /// model is obviously incorrect and will cause us to miss data dependences. + /// As we verify the correctness of our model, for example as part of the + /// run-time alias check, this will not result in the incorrect execution of + /// scops, but rather the fallback to the unoptimized code version. + /// + /// After having computed equivalence classes for invariant loads, we can + /// canonicalize memory accesses to a single pointer in the equivalence class. + /// For this we choose for each equivalence class the first pointer in this + /// equivalence class. + void unifyIndirectArrays(); + /// Add invariant loads listed in @p InvMAs with the domain of @p Stmt. void addInvariantLoads(ScopStmt &Stmt, InvariantAccessesTy &InvMAs); Index: lib/Analysis/ScopInfo.cpp =================================================================== --- lib/Analysis/ScopInfo.cpp +++ lib/Analysis/ScopInfo.cpp @@ -1086,8 +1086,8 @@ auto *NewArrayId = isl_space_get_tuple_id(NewAccessSpace, isl_dim_set); auto *SAI = static_cast(isl_id_get_user(NewArrayId)); assert(SAI && "Must set a ScopArrayInfo"); - assert(!SAI->getBasePtrOriginSAI() && - "Indirect array not supported by codegen"); + //assert(!SAI->getBasePtrOriginSAI() && + // "Indirect array not supported by codegen"); auto Dims = SAI->getNumberOfDimensions(); assert(isl_space_dim(NewAccessSpace, isl_dim_set) == Dims && "Access dims must match array dims"); @@ -3288,6 +3288,7 @@ return; hoistInvariantLoads(); + unifyIndirectArrays(); verifyInvariantLoads(); simplifySCoP(true); @@ -3688,6 +3689,52 @@ isl_union_map_free(Writes); } +void Scop::unifyIndirectArrays() { + if (!PollyInvariantLoadHoisting) + return; + + for (InvariantEquivClassTy &EqClass : InvariantEquivClasses) { + int i = 0; + MemoryAccess *CanonicalAccess; + ScopArrayInfo *CanonicalSAI = nullptr; + for (MemoryAccess *InvAccess : EqClass.InvariantAccesses) { + i++; + if (i == 1) { + CanonicalAccess = InvAccess; + + for (ScopArrayInfo *SAI : arrays()) + if (SAI->getBasePtr() == CanonicalAccess->getAccessInstruction()) { + CanonicalSAI = SAI; + break; + } + if (!CanonicalSAI) + break; + + continue; + } + + ScopArrayInfo *OldSAI = nullptr; + for (ScopArrayInfo *SAI : arrays()) + if (SAI->getBasePtr() == InvAccess->getAccessInstruction()) { + OldSAI = SAI; + break; + } + + if (!OldSAI) + continue; + + for (ScopStmt &Stmt : *this) + for (MemoryAccess *Access : Stmt) + if (Access->getScopArrayInfo() == OldSAI) { + isl_id *Id = CanonicalSAI->getBasePtrId(); + isl_map *Map = Access->getAccessRelation(); + Map = isl_map_set_tuple_id(Map, isl_dim_out, Id); + Access->setNewAccessRelation(Map); + } + } + } +} + const ScopArrayInfo *Scop::getOrCreateScopArrayInfo( Value *BasePtr, Type *ElementType, ArrayRef Sizes, ScopArrayInfo::MemoryKind Kind, const char *BaseName) { Index: test/ScopInfo/invariant_load_unify_arrays.ll =================================================================== --- /dev/null +++ test/ScopInfo/invariant_load_unify_arrays.ll @@ -0,0 +1,47 @@ +; RUN: opt %loadPolly -polly-scops -analyze < %s \ +; RUN: -polly-invariant-load-hoisting \ +; RUN: | FileCheck %s + +; CHECK: Stmt_body1 +; CHECK-NEXT: Domain := +; CHECK-NEXT: { Stmt_body1[i0] : 0 <= i0 <= 1022 }; +; CHECK-NEXT: Schedule := +; CHECK-NEXT: { Stmt_body1[i0] -> [i0, 0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: { Stmt_body1[i0] -> MemRef_baseA[0] }; +; CHECK-NEXT: new: { Stmt_body1[i0] -> MemRef_baseB[0] }; +; CHECK-NEXT: Stmt_body2 +; CHECK-NEXT: Domain := +; CHECK-NEXT: { Stmt_body2[i0] : 0 <= i0 <= 1022 }; +; CHECK-NEXT: Schedule := +; CHECK-NEXT: { Stmt_body2[i0] -> [i0, 1] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: { Stmt_body2[i0] -> MemRef_baseB[0] }; + +define void @foo(float** %A) { +start: + br label %loop + +loop: + %indvar = phi i64 [0, %start], [%indvar.next, %latch] + %indvar.next = add nsw i64 %indvar, 1 + %icmp = icmp slt i64 %indvar.next, 1024 + br i1 %icmp, label %body1, label %exit + +body1: + %baseA = load float*, float** %A + store float 42.0, float* %baseA + br label %body2 + +body2: + %baseB = load float*, float** %A + store float 42.0, float* %baseB + br label %latch + +latch: + br label %loop + +exit: + ret void + +}