forked from OSchip/llvm-project
Record wrapping assumptions early
Utilizing the record option for assumptions we can simplify the wrapping assumption generation a lot. Additionally, we can now report locations together with wrapping assumptions, though they might not be accurate yet. llvm-svn: 266069
This commit is contained in:
parent
3bf6e4129f
commit
615e0b85f8
|
@ -1398,6 +1398,9 @@ private:
|
|||
|
||||
/// @brief The location that caused this assumption.
|
||||
DebugLoc Loc;
|
||||
|
||||
/// @brief An optional block whos domain can simplify the assumption.
|
||||
BasicBlock *BB;
|
||||
};
|
||||
|
||||
/// @brief Collection to hold taken assumptions.
|
||||
|
@ -1673,9 +1676,6 @@ private:
|
|||
/// @brief Build the Context of the Scop.
|
||||
void buildContext();
|
||||
|
||||
/// @brief Add the restrictions based on the wrapping of expressions.
|
||||
void addWrappingContext();
|
||||
|
||||
/// @brief Add user provided parameter constraints to context (source code).
|
||||
void addUserAssumptions(AssumptionCache &AC, DominatorTree &DT, LoopInfo &LI);
|
||||
|
||||
|
@ -1965,8 +1965,13 @@ public:
|
|||
/// @param Loc The location in the source that caused this assumption.
|
||||
/// @param Sign Enum to indicate if the assumptions in @p Set are positive
|
||||
/// (needed/assumptions) or negative (invalid/restrictions).
|
||||
/// @param BB The block in which this assumption was taken. If it is
|
||||
/// set, the domain of that block will be used to simplify the
|
||||
/// actual assumption in @p Set once it is added. This is useful
|
||||
/// if the assumption was created prior to the domain.
|
||||
void recordAssumption(AssumptionKind Kind, __isl_take isl_set *Set,
|
||||
DebugLoc Loc, AssumptionSign Sign);
|
||||
DebugLoc Loc, AssumptionSign Sign,
|
||||
BasicBlock *BB = nullptr);
|
||||
|
||||
/// @brief Add all recorded assumptions to the assumed context.
|
||||
void addRecordedAssumptions();
|
||||
|
|
|
@ -96,14 +96,12 @@ private:
|
|||
__isl_give isl_pw_aff *addModuloSemantic(__isl_take isl_pw_aff *PWA,
|
||||
llvm::Type *ExprType) const;
|
||||
|
||||
/// @brief Compute the context in which integer wrapping for @p PWA happens.
|
||||
/// @brief If @p Expr might cause an integer wrap record an assumption.
|
||||
///
|
||||
/// @returns The context in which integer wrapping happens or nullptr if
|
||||
/// empty.
|
||||
__isl_give isl_set *getWrappingContext(llvm::SCEV::NoWrapFlags Flags,
|
||||
llvm::Type *ExprType,
|
||||
__isl_keep isl_pw_aff *PWA,
|
||||
__isl_keep isl_set *ExprDomain) const;
|
||||
/// @param Expr The SCEV expression that might wrap.
|
||||
/// @param PWA The isl representation of @p Expr.
|
||||
void checkForWrapping(const llvm::SCEV *Expr,
|
||||
__isl_keep isl_pw_aff *PWA) const;
|
||||
|
||||
__isl_give isl_pw_aff *visit(const llvm::SCEV *E);
|
||||
__isl_give isl_pw_aff *visitConstant(const llvm::SCEVConstant *E);
|
||||
|
|
|
@ -99,12 +99,6 @@ static cl::opt<bool> DetectReductions("polly-detect-reductions",
|
|||
cl::Hidden, cl::ZeroOrMore,
|
||||
cl::init(true), cl::cat(PollyCategory));
|
||||
|
||||
static cl::opt<bool> IgnoreIntegerWrapping(
|
||||
"polly-ignore-integer-wrapping",
|
||||
cl::desc("Do not build run-time checks to proof absence of integer "
|
||||
"wrapping"),
|
||||
cl::Hidden, cl::ZeroOrMore, cl::init(false), cl::cat(PollyCategory));
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Create a sequence of two schedules. Either argument may be null and is
|
||||
|
@ -1847,14 +1841,6 @@ __isl_give isl_set *Scop::addNonEmptyDomainConstraints(isl_set *C) const {
|
|||
return isl_set_intersect_params(C, DomainContext);
|
||||
}
|
||||
|
||||
void Scop::addWrappingContext() {
|
||||
if (IgnoreIntegerWrapping)
|
||||
return;
|
||||
|
||||
auto *WrappingContext = Affinator.getWrappingContext();
|
||||
addAssumption(WRAPPING, WrappingContext, DebugLoc(), AS_RESTRICTION);
|
||||
}
|
||||
|
||||
void Scop::addUserAssumptions(AssumptionCache &AC, DominatorTree &DT,
|
||||
LoopInfo &LI) {
|
||||
auto *R = &getRegion();
|
||||
|
@ -3026,7 +3012,6 @@ void Scop::init(AliasAnalysis &AA, AssumptionCache &AC, ScopDetection &SD,
|
|||
realignParams();
|
||||
addParameterBounds();
|
||||
addUserContext();
|
||||
addWrappingContext();
|
||||
|
||||
// After the context was fully constructed, thus all our knowledge about
|
||||
// the parameters is in there, we add all recorded assumptions to the
|
||||
|
@ -3506,14 +3491,20 @@ void Scop::addAssumption(AssumptionKind Kind, __isl_take isl_set *Set,
|
|||
}
|
||||
|
||||
void Scop::recordAssumption(AssumptionKind Kind, __isl_take isl_set *Set,
|
||||
DebugLoc Loc, AssumptionSign Sign) {
|
||||
RecordedAssumptions.push_back({Kind, Sign, Set, Loc});
|
||||
DebugLoc Loc, AssumptionSign Sign, BasicBlock *BB) {
|
||||
RecordedAssumptions.push_back({Kind, Sign, Set, Loc, BB});
|
||||
}
|
||||
|
||||
void Scop::addRecordedAssumptions() {
|
||||
while (!RecordedAssumptions.empty()) {
|
||||
const Assumption &AS = RecordedAssumptions.pop_back_val();
|
||||
addAssumption(AS.Kind, AS.Set, AS.Loc, AS.Sign);
|
||||
|
||||
isl_set *S = AS.Set;
|
||||
// If a basic block was given use its domain to simplify the assumption.
|
||||
if (AS.BB)
|
||||
S = isl_set_params(isl_set_intersect(S, getDomainConditions(AS.BB)));
|
||||
|
||||
addAssumption(AS.Kind, S, AS.Loc, AS.Sign);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "polly/Support/SCEVAffinator.h"
|
||||
#include "polly/Options.h"
|
||||
#include "polly/ScopInfo.h"
|
||||
#include "polly/Support/GICHelper.h"
|
||||
#include "polly/Support/SCEVValidator.h"
|
||||
|
@ -24,6 +25,12 @@
|
|||
using namespace llvm;
|
||||
using namespace polly;
|
||||
|
||||
static cl::opt<bool> IgnoreIntegerWrapping(
|
||||
"polly-ignore-integer-wrapping",
|
||||
cl::desc("Do not build run-time checks to proof absence of integer "
|
||||
"wrapping"),
|
||||
cl::Hidden, cl::ZeroOrMore, cl::init(false), cl::cat(PollyCategory));
|
||||
|
||||
// The maximal number of basic sets we allow during the construction of a
|
||||
// piecewise affine function. More complex ones will result in very high
|
||||
// compile time.
|
||||
|
@ -84,10 +91,8 @@ __isl_give isl_pw_aff *SCEVAffinator::getPwAff(const SCEV *Expr,
|
|||
return visit(Expr);
|
||||
}
|
||||
|
||||
__isl_give isl_set *
|
||||
SCEVAffinator::getWrappingContext(SCEV::NoWrapFlags Flags, Type *ExprType,
|
||||
__isl_keep isl_pw_aff *PWA,
|
||||
__isl_take isl_set *ExprDomain) const {
|
||||
void SCEVAffinator::checkForWrapping(const SCEV *Expr,
|
||||
__isl_keep isl_pw_aff *PWA) const {
|
||||
// If the SCEV flags do contain NSW (no signed wrap) then PWA already
|
||||
// represents Expr in modulo semantic (it is not allowed to overflow), thus we
|
||||
// are done. Otherwise, we will compute:
|
||||
|
@ -95,44 +100,19 @@ SCEVAffinator::getWrappingContext(SCEV::NoWrapFlags Flags, Type *ExprType,
|
|||
// whereas n is the number of bits of the Expr, hence:
|
||||
// n = bitwidth(ExprType)
|
||||
|
||||
if (Flags & SCEV::FlagNSW)
|
||||
return nullptr;
|
||||
if (IgnoreIntegerWrapping || (getNoWrapFlags(Expr) & SCEV::FlagNSW))
|
||||
return;
|
||||
|
||||
isl_pw_aff *PWAMod = addModuloSemantic(isl_pw_aff_copy(PWA), ExprType);
|
||||
if (isl_pw_aff_is_equal(PWA, PWAMod)) {
|
||||
isl_pw_aff_free(PWAMod);
|
||||
return nullptr;
|
||||
}
|
||||
auto *PWAMod = addModuloSemantic(isl_pw_aff_copy(PWA), Expr->getType());
|
||||
auto *NotEqualSet = isl_pw_aff_ne_set(isl_pw_aff_copy(PWA), PWAMod);
|
||||
|
||||
PWA = isl_pw_aff_copy(PWA);
|
||||
const DebugLoc &Loc = BB ? BB->getTerminator()->getDebugLoc() : DebugLoc();
|
||||
NotEqualSet = BB ? NotEqualSet : isl_set_params(NotEqualSet);
|
||||
|
||||
auto *NotEqualSet = isl_pw_aff_ne_set(PWA, PWAMod);
|
||||
NotEqualSet = isl_set_intersect(NotEqualSet, isl_set_copy(ExprDomain));
|
||||
NotEqualSet = isl_set_gist_params(NotEqualSet, S->getContext());
|
||||
NotEqualSet = isl_set_params(NotEqualSet);
|
||||
return NotEqualSet;
|
||||
}
|
||||
|
||||
__isl_give isl_set *SCEVAffinator::getWrappingContext() const {
|
||||
|
||||
isl_set *WrappingCtx = isl_set_empty(S->getParamSpace());
|
||||
|
||||
for (const auto &CachedPair : CachedExpressions) {
|
||||
const SCEV *Expr = CachedPair.first.first;
|
||||
SCEV::NoWrapFlags Flags = getNoWrapFlags(Expr);
|
||||
|
||||
isl_pw_aff *PWA = CachedPair.second;
|
||||
BasicBlock *BB = CachedPair.first.second;
|
||||
isl_set *ExprDomain = BB ? S->getDomainConditions(BB) : nullptr;
|
||||
|
||||
isl_set *WPWACtx =
|
||||
getWrappingContext(Flags, Expr->getType(), PWA, ExprDomain);
|
||||
isl_set_free(ExprDomain);
|
||||
|
||||
WrappingCtx = WPWACtx ? isl_set_union(WrappingCtx, WPWACtx) : WrappingCtx;
|
||||
}
|
||||
|
||||
return WrappingCtx;
|
||||
if (isl_set_is_empty(NotEqualSet))
|
||||
isl_set_free(NotEqualSet);
|
||||
else
|
||||
S->recordAssumption(WRAPPING, NotEqualSet, Loc, AS_RESTRICTION, BB);
|
||||
}
|
||||
|
||||
__isl_give isl_pw_aff *
|
||||
|
@ -198,6 +178,7 @@ __isl_give isl_pw_aff *SCEVAffinator::visit(const SCEV *Expr) {
|
|||
PWA = isl_pw_aff_alloc(Domain, Affine);
|
||||
} else {
|
||||
PWA = SCEVVisitor<SCEVAffinator, isl_pw_aff *>::visit(Expr);
|
||||
checkForWrapping(Expr, PWA);
|
||||
}
|
||||
|
||||
PWA = isl_pw_aff_mul(visitConstant(Factor), PWA);
|
||||
|
@ -205,6 +186,8 @@ __isl_give isl_pw_aff *SCEVAffinator::visit(const SCEV *Expr) {
|
|||
// For compile time reasons we need to simplify the PWA before we cache and
|
||||
// return it.
|
||||
PWA = isl_pw_aff_coalesce(PWA);
|
||||
checkForWrapping(Key.first, PWA);
|
||||
|
||||
CachedExpressions[Key] = isl_pw_aff_copy(PWA);
|
||||
return PWA;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3
|
|||
; for the delinearization is simplified such that conditions that would not
|
||||
; cause any code to be executed are not generated.
|
||||
|
||||
; CHECK: if (((o >= 1 && q <= 0 && m + q >= 0) || (o <= 0 && m + q >= 100 && q <= 100)) && 0 == ((m >= 1 && n + p >= 9223372036854775809) || (o <= 0 && n >= 1 && m + q >= 9223372036854775909) || (o <= 0 && m >= 1 && n >= 1 && q <= -9223372036854775709)))
|
||||
; CHECK: if (((o >= 1 && q <= 0 && m + q >= 0) || (o <= 0 && m + q >= 100 && q <= 100)) && 0 == ((o <= 0 && n >= 1 && m + q >= 9223372036854775909) || (m >= 1 && n + p >= 9223372036854775809) || (o <= 0 && m >= 1 && n >= 1 && q <= -9223372036854775709)))
|
||||
|
||||
; CHECK: if (o <= 0) {
|
||||
; CHECK: for (int c0 = 0; c0 < n; c0 += 1)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
; CHECK-NEXT: Assumed Context:
|
||||
; CHECK-NEXT: [tmp14, p_1] -> { : }
|
||||
; CHECK-NEXT: Invalid Context:
|
||||
; CHECK-NEXT: [tmp14, p_1] -> { : tmp14 > 0 and (tmp14 >= 1152921504606846977 or p_1 <= -1152921504606846977 or p_1 >= 1152921504606846977 - tmp14)
|
||||
; CHECK-NEXT: [tmp14, p_1] -> { : tmp14 > 0 and (p_1 <= -1152921504606846977 or tmp14 >= 1152921504606846977 or p_1 >= 1152921504606846977 - tmp14) }
|
||||
; CHECK-NEXT: p0: %tmp14
|
||||
; CHECK-NEXT: p1: {0,+,(0 smax %tmp)}<%bb12>
|
||||
; CHECK-NEXT: Arrays {
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
; CHECK-NEXT: Assumed Context:
|
||||
; CHECK-NEXT: [tmp14, p_1] -> { : }
|
||||
; CHECK-NEXT: Invalid Context:
|
||||
; CHECK-NEXT: [tmp14, p_1] -> { : tmp14 > 0 and (tmp14 >= 1152921504606846977 or p_1 <= -1152921504606846977 or p_1 >= 1152921504606846977 - tmp14) }
|
||||
; CHECK-NEXT: [tmp14, p_1] -> { : tmp14 > 0 and (p_1 <= -1152921504606846977 or tmp14 >= 1152921504606846977 or p_1 >= 1152921504606846977 - tmp14) }
|
||||
; CHECK-NEXT: p0: %tmp14
|
||||
; CHECK-NEXT: p1: {0,+,(0 smax %tmp)}<%bb12>
|
||||
; CHECK-NEXT: Arrays {
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
; CHECK-NEXT: Assumed Context:
|
||||
; CHECK-NEXT: [tmp14, p_1] -> { : }
|
||||
; CHECK-NEXT: Invalid Context:
|
||||
; CHECK-NEXT: [tmp14, p_1] -> { : tmp14 > 0 and (tmp14 >= 1152921504606846977 or p_1 <= -1152921504606846977 or p_1 >= 1152921504606846977 - tmp14) }
|
||||
; CHECK-NEXT: [tmp14, p_1] -> { : tmp14 > 0 and (p_1 <= -1152921504606846977 or tmp14 >= 1152921504606846977 or p_1 >= 1152921504606846977 - tmp14) }
|
||||
; CHECK-NEXT: p0: %tmp14
|
||||
; CHECK-NEXT: p1: {0,+,(0 smax %tmp)}<%bb12>
|
||||
; CHECK-NEXT: Arrays {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
; }
|
||||
;
|
||||
; CHECK: Invalid Context:
|
||||
; CHECK-NEXT: [A, B] -> { : (4*floor((-A + B)/4) = -A + B and B >= 9223372036854775808 + A) or (4*floor((A - B)/4) < A - B) or (4*floor((-A + B)/4) = -A + B and B <= -4 + A) }
|
||||
; CHECK-NEXT: [A, B] -> { : (4*floor((A - B)/4) < A - B) or (4*floor((-A + B)/4) = -A + B and B >= 9223372036854775808 + A) or (4*floor((-A + B)/4) = -A + B and B <= -4 + A) }
|
||||
;
|
||||
; CHECK: Domain :=
|
||||
; CHECK-NEXT: [A, B] -> { Stmt_while_body[i0] : 4*floor((A - B)/4) = A - B and B >= A and i0 >= 0 and 4i0 < -A + B }
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
; }
|
||||
;
|
||||
; CHECK: Invalid Context:
|
||||
; CHECK-NEXT: [A, B] -> { : (4*floor((-A + B)/4) = -A + B and B >= 9223372036854775808 + A) or (4*floor((A - B)/4) < A - B) or (4*floor((-A + B)/4) = -A + B and B <= -4 + A) }
|
||||
; CHECK-NEXT: [A, B] -> { : (4*floor((A - B)/4) < A - B) or (4*floor((-A + B)/4) = -A + B and B >= 9223372036854775808 + A) or (4*floor((-A + B)/4) = -A + B and B <= -4 + A) }
|
||||
;
|
||||
; CHECK: Domain :=
|
||||
; CHECK-NEXT: [A, B] -> { Stmt_while_body[i0] : 4*floor((A - B)/4) = A - B and B >= A and i0 >= 0 and 4i0 < -A + B }
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops -disable-output < %s 2>&1 | FileCheck %s
|
||||
;
|
||||
; CHECK: remark: test/ScopInfo/remarks.c:4:7: SCoP begins here.
|
||||
; CHECK: remark: <unknown>:0:0: No-overflows restriction: [N, M, Debug] -> { : M <= -2147483649 - N or M >= 2147483648 - N }
|
||||
; CHECK: remark: test/ScopInfo/remarks.c:9:15: Inbounds assumption: [N, M, Debug] -> { : N <= 0 or (N > 0 and M <= 100) }
|
||||
; CHECK: remark: test/ScopInfo/remarks.c:13:7: No-error restriction: [N, M, Debug] -> { : N > 0 and M >= 0 and (Debug < 0 or Debug > 0) }
|
||||
; CHECK: remark: test/ScopInfo/remarks.c:8:5: Finite loop restriction: [N, M, Debug] -> { : N > 0 and (M <= -2 or M = -1) }
|
||||
; CHECK: remark: test/ScopInfo/remarks.c:4:7: No-overflows restriction: [N, M, Debug] -> { : M <= -2147483649 - N or M >= 2147483648 - N }
|
||||
; CHECK: remark: test/ScopInfo/remarks.c:9:18: Possibly aliasing pointer, use restrict keyword.
|
||||
; CHECK: remark: test/ScopInfo/remarks.c:9:33: Possibly aliasing pointer, use restrict keyword.
|
||||
; CHECK: remark: test/ScopInfo/remarks.c:9:15: Possibly aliasing pointer, use restrict keyword.
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
; to overflow. However (p + q) can, thus checks are needed.
|
||||
;
|
||||
; CHECK: Invalid Context:
|
||||
; CHECK-NEXT: [r1, r2, q, p] -> { : r2 > r1 and (r2 >= 128 + r1 or p <= -2147483649 - q or p >= 2147483648 - q) }
|
||||
; CHECK-NEXT: [r1, r2, q, p] -> { : r2 > r1 and (p <= -2147483649 - q or r2 >= 128 + r1 or p >= 2147483648 - q) }
|
||||
;
|
||||
; void wraps(int *A, int p, short q, char r1, char r2) {
|
||||
; for (char i = r1; i < r2; i++)
|
||||
|
|
Loading…
Reference in New Issue