[FIX] Unsigned comparisons change invalid domain

It does not suffice to take a global assumptions for unsigned comparisons but
  we also need to adjust the invalid domain of the statements guarded by such
  an assumption. To this end we allow to specialize the getPwAff call now in
  order to indicate unsigned interpretation.

llvm-svn: 268025
This commit is contained in:
Johannes Doerfert 2016-04-29 10:44:41 +00:00
parent ae77ab71d8
commit 3e48ee2ab9
5 changed files with 76 additions and 28 deletions

View File

@ -1267,8 +1267,11 @@ public:
/// @brief Compute the isl representation for the SCEV @p E in this stmt.
///
/// @param E The SCEV that should be translated.
/// @param NonNegative Flag to indicate the @p E has to be non-negative.
///
/// Note that this function will also adjust the invalid context accordingly.
__isl_give isl_pw_aff *getPwAff(const SCEV *E);
__isl_give isl_pw_aff *getPwAff(const SCEV *E, bool NonNegative = false);
/// @brief Get the loop for a dimension.
///
@ -2125,15 +2128,18 @@ public:
/// @brief Compute the isl representation for the SCEV @p E
///
/// @param E The SCEV that should be translated.
/// @param BB An (optional) basic block in which the isl_pw_aff is computed.
/// SCEVs known to not reference any loops in the SCoP can be
/// passed without a @p BB.
/// @param NonNegative Flag to indicate the @p E has to be non-negative.
///
/// Note that this function will always return a valid isl_pw_aff. However, if
/// the translation of @p E was deemed to complex the SCoP is invalidated and
/// a dummy value of appropriate dimension is returned. This allows to bail
/// for complex cases without "error handling code" needed on the users side.
__isl_give PWACtx getPwAff(const SCEV *E, BasicBlock *BB = nullptr);
__isl_give PWACtx getPwAff(const SCEV *E, BasicBlock *BB = nullptr,
bool NonNegative = false);
/// @brief Compute the isl representation for the SCEV @p E
///

View File

@ -64,6 +64,9 @@ public:
__isl_give PWACtx getPwAff(const llvm::SCEV *E,
llvm::BasicBlock *BB = nullptr);
/// @brief Take the asumption that @p PWAC is non-negative.
void takeNonNegativeAssumption(PWACtx &PWAC);
/// @brief Check an <nsw> AddRec for the loop @p L is cached.
bool hasNSWAddRecForLoop(llvm::Loop *L) const;

View File

@ -1045,8 +1045,8 @@ __isl_give isl_map *ScopStmt::getSchedule() const {
return M;
}
__isl_give isl_pw_aff *ScopStmt::getPwAff(const SCEV *E) {
PWACtx PWAC = getParent()->getPwAff(E, getEntryBlock());
__isl_give isl_pw_aff *ScopStmt::getPwAff(const SCEV *E, bool NonNegative) {
PWACtx PWAC = getParent()->getPwAff(E, getEntryBlock(), NonNegative);
InvalidDomain = isl_set_union(InvalidDomain, PWAC.second);
return PWAC.first;
}
@ -1315,20 +1315,12 @@ buildConditionSets(ScopStmt &Stmt, Value *Condition, TerminatorInst *TI,
ScalarEvolution &SE = *S.getSE();
isl_pw_aff *LHS, *RHS;
LHS = Stmt.getPwAff(SE.getSCEVAtScope(ICond->getOperand(0), L));
RHS = Stmt.getPwAff(SE.getSCEVAtScope(ICond->getOperand(1), L));
if (ICond->isUnsigned()) {
// For unsigned comparisons we assumed the signed bit of neither operand
// to be set. The comparison is equal to a signed comparison under this
// assumption.
auto *BB = Stmt.getEntryBlock();
S.recordAssumption(UNSIGNED, isl_pw_aff_nonneg_set(isl_pw_aff_copy(LHS)),
TI->getDebugLoc(), AS_ASSUMPTION, BB);
S.recordAssumption(UNSIGNED, isl_pw_aff_nonneg_set(isl_pw_aff_copy(RHS)),
TI->getDebugLoc(), AS_ASSUMPTION, BB);
}
// For unsigned comparisons we assumed the signed bit of neither operand
// to be set. The comparison is equal to a signed comparison under this
// assumption.
bool NonNeg = ICond->isUnsigned();
LHS = Stmt.getPwAff(SE.getSCEVAtScope(ICond->getOperand(0), L), NonNeg);
RHS = Stmt.getPwAff(SE.getSCEVAtScope(ICond->getOperand(1), L), NonNeg);
ConsequenceCondSet =
buildConditionSet(ICond->getPredicate(), LHS, RHS, Domain);
}
@ -3789,15 +3781,19 @@ void Scop::dump() const { print(dbgs()); }
isl_ctx *Scop::getIslCtx() const { return IslCtx.get(); }
__isl_give PWACtx Scop::getPwAff(const SCEV *E, BasicBlock *BB) {
__isl_give PWACtx Scop::getPwAff(const SCEV *E, BasicBlock *BB,
bool NonNegative) {
// First try to use the SCEVAffinator to generate a piecewise defined
// affine function from @p E in the context of @p BB. If that tasks becomes to
// complex the affinator might return a nullptr. In such a case we invalidate
// the SCoP and return a dummy value. This way we do not need to add error
// handling cdoe to all users of this function.
auto PWAC = Affinator.getPwAff(E, BB);
if (PWAC.first)
if (PWAC.first) {
if (NonNegative)
Affinator.takeNonNegativeAssumption(PWAC);
return PWAC;
}
auto DL = BB ? BB->getTerminator()->getDebugLoc() : DebugLoc();
invalidate(COMPLEXITY, DL);

View File

@ -119,6 +119,15 @@ SCEVAffinator::~SCEVAffinator() {
freePWACtx(CachedPair.second);
}
void SCEVAffinator::takeNonNegativeAssumption(PWACtx &PWAC) {
auto *NegPWA = isl_pw_aff_neg(isl_pw_aff_copy(PWAC.first));
auto *NegDom = isl_pw_aff_pos_set(NegPWA);
PWAC.second = isl_set_union(PWAC.second, isl_set_copy(NegDom));
auto *Restriction = BB ? NegDom : isl_set_params(NegDom);
auto DL = BB ? BB->getTerminator()->getDebugLoc() : DebugLoc();
S->recordAssumption(UNSIGNED, Restriction, DL, AS_RESTRICTION, BB);
}
__isl_give PWACtx SCEVAffinator::getPWACtxFromPWA(__isl_take isl_pw_aff *PWA) {
return std::make_pair(
PWA, isl_set_empty(isl_space_set_alloc(Ctx, 0, NumIterators)));
@ -334,14 +343,7 @@ SCEVAffinator::visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) {
// If the width is to big we assume the negative part does not occur.
if (!Precise) {
auto *NegOpPWA = isl_pw_aff_neg(isl_pw_aff_copy(OpPWAC.first));
auto *NegDom = isl_pw_aff_pos_set(NegOpPWA);
auto *ExprDomain = BB ? S->getDomainConditions(BB) : nullptr;
NegDom = ExprDomain ? isl_set_intersect(NegDom, ExprDomain) : NegDom;
OpPWAC.second = isl_set_union(OpPWAC.second, isl_set_copy(NegDom));
NegDom = BB ? NegDom : isl_set_params(NegDom);
auto DL = BB ? BB->getTerminator()->getDebugLoc() : DebugLoc();
S->recordAssumption(UNSIGNED, NegDom, DL, AS_RESTRICTION, BB);
takeNonNegativeAssumption(OpPWAC);
return OpPWAC;
}

View File

@ -0,0 +1,41 @@
; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
;
l Check that we model the execution context correctly.
;
; void f(unsigned *I, unsigned *A, int c) {
; for (unsigned i = c; i < 10; i++)
; A[i] += *I;
; }
;
; CHECK: Invariant Accesses: {
; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK-NEXT: [c] -> { Stmt_for_body[i0] -> MemRef_I[0] };
; CHECK-NEXT: Execution Context: [c] -> { : 0 <= c <= 9 }
; CHECK-NEXT: }
;
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
define void @f(i32* %I, i32* %A, i64 %c) {
entry:
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ %c, %entry ]
%exitcond = icmp ult i64 %indvars.iv, 10
br i1 %exitcond, label %for.body, label %for.end
for.body: ; preds = %for.cond
%tmp = load i32, i32* %I, align 4
%arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
%tmp1 = load i32, i32* %arrayidx, align 4
%add = add i32 %tmp1, %tmp
store i32 %add, i32* %arrayidx, align 4
br label %for.inc
for.inc: ; preds = %for.body
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
br label %for.cond
for.end: ; preds = %for.cond
ret void
}