DeadCodeElim: Compute correct liveout for non-affine accesses

Thanks to Johannes Doerfert for narrowing down the bug.

Reported-by: Chris Jenneisch <chrisj@codeaurora.org>
llvm-svn: 212796
This commit is contained in:
Tobias Grosser 2014-07-11 07:12:10 +00:00
parent 26f817497c
commit 780ce0f8e3
5 changed files with 150 additions and 13 deletions

View File

@ -702,6 +702,12 @@ public:
/// @brief Get a union set containing the iteration domains of all statements.
__isl_give isl_union_set *getDomains();
/// @brief Get a union map of all may-writes performed in the SCoP.
__isl_give isl_union_map *getMayWrites();
/// @brief Get a union map of all must-writes performed in the SCoP.
__isl_give isl_union_map *getMustWrites();
/// @brief Get a union map of all writes performed in the SCoP.
__isl_give isl_union_map *getWrites();

View File

@ -1269,6 +1269,40 @@ __isl_give isl_union_set *Scop::getDomains() {
return Domain;
}
__isl_give isl_union_map *Scop::getMustWrites() {
isl_union_map *Write = isl_union_map_empty(this->getParamSpace());
for (ScopStmt *Stmt : *this) {
for (MemoryAccess *MA : *Stmt) {
if (!MA->isMustWrite())
continue;
isl_set *Domain = Stmt->getDomain();
isl_map *AccessDomain = MA->getAccessRelation();
AccessDomain = isl_map_intersect_domain(AccessDomain, Domain);
Write = isl_union_map_add_map(Write, AccessDomain);
}
}
return isl_union_map_coalesce(Write);
}
__isl_give isl_union_map *Scop::getMayWrites() {
isl_union_map *Write = isl_union_map_empty(this->getParamSpace());
for (ScopStmt *Stmt : *this) {
for (MemoryAccess *MA : *Stmt) {
if (!MA->isMayWrite())
continue;
isl_set *Domain = Stmt->getDomain();
isl_map *AccessDomain = MA->getAccessRelation();
AccessDomain = isl_map_intersect_domain(AccessDomain, Domain);
Write = isl_union_map_add_map(Write, AccessDomain);
}
}
return isl_union_map_coalesce(Write);
}
__isl_give isl_union_map *Scop::getWrites() {
isl_union_map *Write = isl_union_map_empty(this->getParamSpace());

View File

@ -36,6 +36,7 @@
#include "polly/LinkAllPasses.h"
#include "polly/ScopInfo.h"
#include "llvm/Support/CommandLine.h"
#include "isl/flow.h"
#include "isl/set.h"
#include "isl/map.h"
#include "isl/union_map.h"
@ -63,26 +64,35 @@ public:
void getAnalysisUsage(AnalysisUsage &AU) const;
private:
isl_union_set *getLastWrites(isl_union_map *Writes, isl_union_map *Schedule);
/// @brief Return the set of live iterations.
///
/// The set of live iterations are all iterations that write to memory and for
/// which we can not prove that there will be a later write that _must_
/// overwrite the same memory location and is consequently the only one that
/// is visible after the execution of the SCoP.
///
isl_union_set *getLiveOut(Scop &S);
bool eliminateDeadCode(Scop &S, int PreciseSteps);
};
}
char DeadCodeElim::ID = 0;
/// Return the set of iterations that contains the last write for each location.
isl_union_set *DeadCodeElim::getLastWrites(__isl_take isl_union_map *Writes,
__isl_take isl_union_map *Schedule) {
isl_union_map *WriteIterations = isl_union_map_reverse(Writes);
isl_union_map *WriteTimes =
isl_union_map_apply_range(WriteIterations, isl_union_map_copy(Schedule));
// To compute the live outs, we first assume all must and may-writes are exposed
// and then subtract the set of statements that are definitely overwritten.
isl_union_set *DeadCodeElim::getLiveOut(Scop &S) {
__isl_take isl_union_map *Kills = S.getMustWrites();
__isl_take isl_union_map *Empty = isl_union_map_empty(S.getParamSpace());
isl_union_map *LastWriteTimes = isl_union_map_lexmax(WriteTimes);
isl_union_map *LastWriteIterations = isl_union_map_apply_range(
LastWriteTimes, isl_union_map_reverse(Schedule));
isl_union_map *Covering;
isl_union_map *Writes = S.getWrites();
isl_union_map_compute_flow(Kills, Empty, isl_union_map_copy(Writes),
S.getSchedule(), NULL, &Covering, NULL, NULL);
isl_union_set *Live = isl_union_map_range(LastWriteIterations);
return isl_union_set_coalesce(Live);
isl_union_map *Exposed = Writes;
Exposed =
isl_union_map_subtract_domain(Exposed, isl_union_map_domain(Covering));
return isl_union_map_domain(Exposed);
}
/// Performs polyhedral dead iteration elimination by:
@ -99,7 +109,7 @@ bool DeadCodeElim::eliminateDeadCode(Scop &S, int PreciseSteps) {
if (!D->hasValidDependences())
return false;
isl_union_set *Live = this->getLastWrites(S.getWrites(), S.getSchedule());
isl_union_set *Live = getLiveOut(S);
isl_union_map *Dep =
D->getDependences(Dependences::TYPE_RAW | Dependences::TYPE_RED);
Dep = isl_union_map_reverse(Dep);

View File

@ -0,0 +1,53 @@
; RUN: opt %loadPolly -polly-allow-nonaffine -polly-dce -polly-ast -analyze < %s | FileCheck %s
;
; void f(int *A) {
; for (int i = 0; i < 1024; i++)
; S1: A[i % 2] = i;
; for (int i = 0; i < 1024; i++)
; S2: A[i2] = i;
; }
; CHECK-NOT: Stmt_S1
; CHECK: for (int c1 = 0; c1 <= 1023; c1 += 1)
; CHECK: Stmt_S2(c1);
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
define void @f(i32* %A) {
entry:
br label %for.cond
for.cond:
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%exitcond = icmp ne i32 %i.0, 1024
br i1 %exitcond, label %S1, label %for.cond.2
S1:
%rem = srem i32 %i.0, 2
%arrayidx = getelementptr inbounds i32* %A, i32 %rem
store i32 %i.0, i32* %arrayidx, align 4
br label %for.inc
for.inc:
%inc = add nsw i32 %i.0, 1
br label %for.cond
for.cond.2:
%i.2 = phi i32 [ 0, %for.cond ], [ %inc.2, %for.inc.2 ]
%exitcond.2 = icmp ne i32 %i.2, 1024
br i1 %exitcond.2, label %S2, label %for.end
S2:
%arrayidx.2 = getelementptr inbounds i32* %A, i32 %i.2
store i32 %i.2, i32* %arrayidx.2, align 4
br label %for.inc.2
for.inc.2:
%inc.2 = add nsw i32 %i.2, 1
br label %for.cond.2
for.end:
ret void
}

View File

@ -0,0 +1,34 @@
; RUN: opt %loadPolly -polly-allow-nonaffine -polly-dce -polly-ast -analyze < %s | FileCheck %s
;
; CHECK: for (int c1 = 0; c1 <= 1023; c1 += 1)
;
; void f(int *A) {
; for (int i = 0; i < 1024; i++)
; A[i % 2] = i;
; }
;
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
define void @f(i32* %A) {
entry:
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%exitcond = icmp ne i32 %i.0, 1024
br i1 %exitcond, label %for.body, label %for.end
for.body: ; preds = %for.cond
%rem = srem i32 %i.0, 2
%arrayidx = getelementptr inbounds i32* %A, i32 %rem
store i32 %i.0, i32* %arrayidx, align 4
br label %for.inc
for.inc: ; preds = %for.body
%inc = add nsw i32 %i.0, 1
br label %for.cond
for.end: ; preds = %for.cond
ret void
}