forked from OSchip/llvm-project
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:
parent
26f817497c
commit
780ce0f8e3
|
@ -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();
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue