[ZoneAlgo] Allow two writes that write identical values into same array slot

Two write statements which write into the very same array slot generally are
conflicting. However, in case the value that is written is identical, this
does not cause any problem. Hence, allow such write pairs in this specific
situation.

llvm-svn: 310311
This commit is contained in:
Tobias Grosser 2017-08-07 22:01:29 +00:00
parent bd57cea6e4
commit 2ef378120d
2 changed files with 86 additions and 5 deletions

View File

@ -284,6 +284,29 @@ ZoneAlgorithm::ZoneAlgorithm(const char *PassName, Scop *S, LoopInfo *LI)
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();
@ -338,11 +361,13 @@ bool ZoneAlgorithm::isCompatibleStmt(ScopStmt *Stmt) {
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()));

View File

@ -0,0 +1,56 @@
; 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: }