ScatterSpace = getScatterSpace(Schedule);
}
+/// Check if all stores in @p Stmt store the very same value.
+///
+/// TODO: In the future we may want to extent this to make the checks
+/// specific to different memory locations.
+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();
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()));
--- /dev/null
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Rematerialize a load even in case two writes of identical values are in
+; one scop statement.
+;
+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: }