Index: lib/CodeGen/PPCGCodeGeneration.cpp =================================================================== --- lib/CodeGen/PPCGCodeGeneration.cpp +++ lib/CodeGen/PPCGCodeGeneration.cpp @@ -196,8 +196,8 @@ KillMemIds.push_back(isl::manage(SAI->getBasePtrId().release())); } - Info.TaggedMustKills = isl::union_map::empty(isl::space(ParamSpace)); - Info.MustKills = isl::union_map::empty(isl::space(ParamSpace)); + Info.TaggedMustKills = isl::union_map::empty(ParamSpace); + Info.MustKills = isl::union_map::empty(ParamSpace); // Initialising KillsSchedule to `isl_set_empty` creates an empty node in the // schedule: @@ -225,7 +225,7 @@ // [param] -> { [Stmt[] -> phantom_ref[]] -> scalar_to_kill[] } // 2a. [param] -> { Stmt[] -> scalar_to_kill[] } - isl::map StmtToScalar = isl::map::universe(isl::space(ParamSpace)); + isl::map StmtToScalar = isl::map::universe(ParamSpace); StmtToScalar = StmtToScalar.set_tuple_id(isl::dim::in, isl::id(KillStmtId)); StmtToScalar = StmtToScalar.set_tuple_id(isl::dim::out, isl::id(ToKillId)); @@ -234,7 +234,7 @@ nullptr); // 2b. [param] -> { phantom_ref[] -> scalar_to_kill[] } - isl::map PhantomRefToScalar = isl::map::universe(isl::space(ParamSpace)); + isl::map PhantomRefToScalar = isl::map::universe(ParamSpace); PhantomRefToScalar = PhantomRefToScalar.set_tuple_id(isl::dim::in, PhantomRefId); PhantomRefToScalar = Index: lib/Transform/ZoneAlgo.cpp =================================================================== --- lib/Transform/ZoneAlgo.cpp +++ lib/Transform/ZoneAlgo.cpp @@ -284,6 +284,26 @@ ScatterSpace = getScatterSpace(Schedule); } +/// Check if all stores in @p Stmt store the very same value. +static bool onlySameValueWrites(ScopStmt *Stmt) { + Value *V = nullptr; + + for (auto *MA : *Stmt) { + if (!MA->isLatestArrayKind() || !MA->isMustWrite() || + !MA->isOriginalArrayKind()) + continue; + + if (!V) { + V = MA->getAccessValue(); + continue; + } + + if (V != MA->getAccessValue()) + return false; + } + return true; +} + bool ZoneAlgorithm::isCompatibleStmt(ScopStmt *Stmt) { auto Stores = makeEmptyUnionMap(); auto Loads = makeEmptyUnionMap(); @@ -338,11 +358,13 @@ if (!isl_union_map_is_disjoint(Stores.keep(), AccRel.keep())) { OptimizationRemarkMissed R(PassName, "StoreAfterStore", MA->getAccessInstruction()); - R << "store after store of same element in same statement"; - R << " (previous stores: " << Stores; - R << ", storing: " << AccRel << ")"; - S->getFunction().getContext().diagnose(R); - return false; + if (!onlySameValueWrites(Stmt)) { + R << "store after store of same element in same statement"; + R << " (previous stores: " << Stores; + R << ", storing: " << AccRel << ")"; + S->getFunction().getContext().diagnose(R); + return false; + } } Stores = give(isl_union_map_union(Stores.take(), AccRel.take())); Index: test/ForwardOpTree/forward_load_double_write.ll =================================================================== --- /dev/null +++ test/ForwardOpTree/forward_load_double_write.ll @@ -0,0 +1,55 @@ +; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines +; +; Rematerialize a load. +; +define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) { +entry: + br label %for + +for: + %j = phi i32 [0, %entry], [%j.inc, %inc] + %j.cmp = icmp slt i32 %j, %n + br i1 %j.cmp, label %bodyA, label %exit + + bodyA: + %B_idx = getelementptr inbounds double, double* %B, i32 %j + %val = load double, double* %B_idx + br label %bodyB + + bodyB: + %A_idx = getelementptr inbounds double, double* %A, i32 %j + store double %val, double* %A_idx + store double %val, double* %A_idx + br label %inc + +inc: + %j.inc = add nuw nsw i32 %j, 1 + br label %for + +exit: + br label %return + +return: + ret void +} + + +; CHECK: Statistics { +; CHECK: Known loads forwarded: 1 +; CHECK: Operand trees forwarded: 1 +; CHECK: Statements with forwarded operand trees: 1 +; CHECK: } + +; CHECK: Stmt_bodyB +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: null; +; CHECK-NEXT: new: [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] }; +; CHECK-NEXT: Instructions { +; CHECK-NEXT: %val = load double, double* %B_idx +; CHECK-NEXT: store double %val, double* %A_idx +; CHECK-NEXT: store double %val, double* %A_idx +; CHECK-NEXT: }