[DeLICM] Allow non-injective PHIRead->PHIWrite mapping.

Remove an assertion that tests the injectivity of the
PHIRead -> PHIWrite relation.  That is, allow a single PHI write to be
used by multiple PHI reads.  This may happen due to some statements
containing the PHI write not having the statement instances that would
overwrite the previous incoming value due to (assumed/invalid) contexts.
This result in that PHI write is mapped to multiple targets which is not
supported.  Codegen will select one one of the targets using
getAddressFunction().  However, the runtime check should protect us from
this case ever being executed.

We therefore allow injective PHI relations.  Additional calculations to
detect/santitize this case would probably not be worth the compuational
effort.

This fixes llvm.org/PR34485

llvm-svn: 313902
This commit is contained in:
Michael Kruse 2017-09-21 19:08:23 +00:00
parent 0dde08c3cb
commit bfca5f4334
2 changed files with 128 additions and 1 deletions

View File

@ -666,6 +666,19 @@ private:
/// For each PHI instance we can directly determine which was the incoming
/// block, and hence derive which value the PHI has.
///
/// The returned relation generally is injective, meaning that every PHI write
/// has at most one (or zero, if the incoming block's branch does not jump to
/// the PHI's block) PHI Read that reads it. However, due to the SCoP's
/// parameter context it is possible a statement instance that would overwrite
/// the PHI scalar is not in the statement's domain and thus a PHI write
/// appear to be used twice. This is a static property, at runtime the
/// runtime condition should avoid that a configuration is executed. Although
/// incorrect, it should not have any effect in DeLICM. If it passes the
/// conflict check, there are multiple locations, one for each PHI Read it
/// matches, it had to write to. MemoryAccess::getAddressFunction() will
/// select only one of them. That is, statically, not all necessary value are
/// written, but the runtime check guards it from ever being executed.
///
/// @param SAI The ScopArrayInfo representing the PHI's storage.
///
/// @return { DomainPHIRead[] -> DomainPHIWrite[] }
@ -702,7 +715,6 @@ private:
isl_union_map_from_map(LastPerPHIWrites.take()),
isl_union_map_reverse(PHIWriteScatter.take())));
assert(isl_union_map_is_single_valued(Result.keep()) == isl_bool_true);
assert(isl_union_map_is_injective(Result.keep()) == isl_bool_true);
return Result;
}

View File

@ -0,0 +1,115 @@
; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s -match-full-lines
;
; llvm.org/PR34485
; This produces a non-injective PHIRead -> PHIWrite map due to an invalid
; paramter assumption. It does not map anything because the result does pass
; the non-conflicting test. It would be a better test if it did to test whether
; correct code is generated.
;
; unsigned a;
; long b, d;
; short c;
; int e, f;
; void fn1() {
; for (;;) {
; for (; f;)
; for (;;)
; ;
; a -= 0 < b;
; for (; f <= 5; f++) {
; short *g = &c;
; *g = a++ ? e *= 4 : c;
; g = &f;
; d = *g;
; }
; }
; }
;
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
@f = common local_unnamed_addr global i32 0, align 4
@b = common local_unnamed_addr global i32 0, align 4
@a = common local_unnamed_addr global i32 0, align 4
@c = common local_unnamed_addr global i16 0, align 2
@e = common local_unnamed_addr global i32 0, align 4
@d = common local_unnamed_addr global i32 0, align 4
define void @fn1() local_unnamed_addr {
entry:
br label %entry.split
entry.split: ; preds = %entry
%.pr = load i32, i32* @f, align 4
%tobool19 = icmp eq i32 %.pr, 0
br i1 %tobool19, label %for.end.lr.ph, label %for.body
for.end.lr.ph: ; preds = %entry.split
%0 = load i32, i32* @b, align 4
%cmp = icmp sgt i32 %0, 0
%conv = zext i1 %cmp to i32
%a.promoted20 = load i32, i32* @a, align 4
br label %for.end
for.cond.for.body_crit_edge: ; preds = %for.end, %for.end12
%inc.lcssa2125 = phi i32 [ %inc, %for.end12 ], [ %sub, %for.end ]
store i32 %inc.lcssa2125, i32* @a, align 4
br label %for.body
for.body: ; preds = %for.cond.for.body_crit_edge, %entry.split
br label %for.cond2
for.cond2: ; preds = %for.cond2, %for.body
br label %for.cond2
for.end: ; preds = %for.end.lr.ph, %for.end12
%inc.lcssa22 = phi i32 [ %a.promoted20, %for.end.lr.ph ], [ %inc, %for.end12 ]
%sub = sub i32 %inc.lcssa22, %conv
%.pr15 = load i32, i32* @f, align 4
%cmp416 = icmp slt i32 %.pr15, 6
br i1 %cmp416, label %for.body6.lr.ph, label %for.cond.for.body_crit_edge
for.body6.lr.ph: ; preds = %for.end
%c.promoted = load i16, i16* @c, align 2
br label %for.body6
for.body6: ; preds = %for.body6.lr.ph, %cond.end
%conv918 = phi i16 [ %c.promoted, %for.body6.lr.ph ], [ %conv9, %cond.end ]
%inc17 = phi i32 [ %sub, %for.body6.lr.ph ], [ %inc, %cond.end ]
%1 = phi i32 [ %.pr15, %for.body6.lr.ph ], [ %inc11, %cond.end ]
%inc = add i32 %inc17, 1
%tobool7 = icmp eq i32 %inc17, 0
br i1 %tobool7, label %cond.false, label %cond.true
cond.true: ; preds = %for.body6
%2 = load i32, i32* @e, align 4
%mul = shl nsw i32 %2, 2
store i32 %mul, i32* @e, align 4
br label %cond.end
cond.false: ; preds = %for.body6
%conv8 = sext i16 %conv918 to i32
br label %cond.end
cond.end: ; preds = %cond.false, %cond.true
%cond = phi i32 [ %mul, %cond.true ], [ %conv8, %cond.false ]
%conv9 = trunc i32 %cond to i16
%3 = load i16, i16* bitcast (i32* @f to i16*), align 4
%inc11 = add nsw i32 %1, 1
store i32 %inc11, i32* @f, align 4
%cmp4 = icmp slt i32 %1, 5
br i1 %cmp4, label %for.body6, label %for.end12
for.end12: ; preds = %cond.end
%conv10 = sext i16 %3 to i32
store i16 %conv9, i16* @c, align 2
store i32 %conv10, i32* @d, align 4
%tobool = icmp eq i32 %inc11, 0
br i1 %tobool, label %for.end, label %for.cond.for.body_crit_edge
}
; CHECK: Statistics {
; CHECK: Compatible overwrites: 1
; CHECK: }
; CHECK: No modification has been made