Handle llvm.assume inside the SCoP

The assumption attached to an llvm.assume in the SCoP needs to be
  combined with the domain of the surrounding statement but can
  nevertheless be used to refine the context.

  This fixes the problems mentioned in PR27067.

llvm-svn: 269060
This commit is contained in:
Johannes Doerfert 2016-05-10 14:00:57 +00:00
parent 84174c3771
commit 2b92a0e4ee
9 changed files with 186 additions and 30 deletions

View File

@ -1273,7 +1273,7 @@ public:
///
/// @param Dimension The dimension of the induction variable
/// @return The loop at a certain dimension.
const Loop *getLoopForDimension(unsigned Dimension) const;
Loop *getLoopForDimension(unsigned Dimension) const;
/// @brief Align the parameters in the statement to the scop context
void realignParams();

View File

@ -56,10 +56,10 @@ bool isAffineExpr(const llvm::Region *R, llvm::Loop *Scope,
const llvm::SCEV *Expression, llvm::ScalarEvolution &SE,
InvariantLoadsSetTy *ILS = nullptr);
/// @brief Check if @p V describes an affine parameter constraint in @p R.
bool isAffineParamConstraint(llvm::Value *V, const llvm::Region *R,
llvm::Loop *Scope, llvm::ScalarEvolution &SE,
ParameterSetTy &Params, bool OrExpr = false);
/// @brief Check if @p V describes an affine constraint in @p R.
bool isAffineConstraint(llvm::Value *V, const llvm::Region *R,
llvm::Loop *Scope, llvm::ScalarEvolution &SE,
ParameterSetTy &Params, bool OrExpr = false);
ParameterSetTy getParamsInAffineExpr(const llvm::Region *R, llvm::Loop *Scope,
const llvm::SCEV *Expression,

View File

@ -1668,7 +1668,7 @@ unsigned ScopStmt::getNumIterators() const { return NestLoops.size(); }
const char *ScopStmt::getBaseName() const { return BaseName.c_str(); }
const Loop *ScopStmt::getLoopForDimension(unsigned Dimension) const {
Loop *ScopStmt::getLoopForDimension(unsigned Dimension) const {
return NestLoops[Dimension];
}
@ -1881,13 +1881,15 @@ void Scop::addUserAssumptions(AssumptionCache &AC, DominatorTree &DT,
auto *CI = dyn_cast_or_null<CallInst>(Assumption);
if (!CI || CI->getNumArgOperands() != 1)
continue;
if (!DT.dominates(CI->getParent(), R->getEntry()))
bool InR = R->contains(CI);
if (!InR && !DT.dominates(CI->getParent(), R->getEntry()))
continue;
auto *L = LI.getLoopFor(CI->getParent());
auto *Val = CI->getArgOperand(0);
ParameterSetTy DetectedParams;
if (!isAffineParamConstraint(Val, R, L, *SE, DetectedParams)) {
if (!isAffineConstraint(Val, R, L, *SE, DetectedParams)) {
emitOptimizationRemarkAnalysis(F.getContext(), DEBUG_TYPE, F,
CI->getDebugLoc(),
"Non-affine user assumption ignored.");
@ -1905,14 +1907,23 @@ void Scop::addUserAssumptions(AssumptionCache &AC, DominatorTree &DT,
}
SmallVector<isl_set *, 2> ConditionSets;
if (!buildConditionSets(*Stmts.begin(), Val, nullptr, L, Context,
ConditionSets))
auto *TI = InR ? CI->getParent()->getTerminator() : nullptr;
auto &Stmt = InR ? *getStmtFor(CI->getParent()) : *Stmts.begin();
auto *Dom = InR ? getDomainConditions(&Stmt) : isl_set_copy(Context);
bool Valid = buildConditionSets(Stmt, Val, TI, L, Dom, ConditionSets);
isl_set_free(Dom);
if (!Valid)
continue;
assert(ConditionSets.size() == 2);
isl_set_free(ConditionSets[1]);
auto *AssumptionCtx = ConditionSets[0];
isl_set *AssumptionCtx = nullptr;
if (InR) {
AssumptionCtx = isl_set_complement(isl_set_params(ConditionSets[1]));
isl_set_free(ConditionSets[0]);
} else {
AssumptionCtx = isl_set_complement(ConditionSets[1]);
AssumptionCtx = isl_set_intersect(AssumptionCtx, ConditionSets[0]);
}
// Project out newly introduced parameters as they are not otherwise useful.
if (!NewParams.empty()) {

View File

@ -540,15 +540,15 @@ bool isAffineExpr(const Region *R, llvm::Loop *Scope, const SCEV *Expr,
return Result.isValid();
}
static bool isAffineParamExpr(Value *V, const Region *R, Loop *Scope,
ScalarEvolution &SE, ParameterSetTy &Params) {
static bool isAffineExpr(Value *V, const Region *R, Loop *Scope,
ScalarEvolution &SE, ParameterSetTy &Params) {
auto *E = SE.getSCEV(V);
if (isa<SCEVCouldNotCompute>(E))
return false;
SCEVValidator Validator(R, Scope, SE, nullptr);
ValidatorResult Result = Validator.visit(E);
if (!Result.isConstant())
if (!Result.isValid())
return false;
auto ResultParams = Result.getParameters();
@ -557,28 +557,27 @@ static bool isAffineParamExpr(Value *V, const Region *R, Loop *Scope,
return true;
}
bool isAffineParamConstraint(Value *V, const Region *R, llvm::Loop *Scope,
ScalarEvolution &SE, ParameterSetTy &Params,
bool OrExpr) {
bool isAffineConstraint(Value *V, const Region *R, llvm::Loop *Scope,
ScalarEvolution &SE, ParameterSetTy &Params,
bool OrExpr) {
if (auto *ICmp = dyn_cast<ICmpInst>(V)) {
return isAffineParamConstraint(ICmp->getOperand(0), R, Scope, SE, Params,
true) &&
isAffineParamConstraint(ICmp->getOperand(1), R, Scope, SE, Params,
true);
return isAffineConstraint(ICmp->getOperand(0), R, Scope, SE, Params,
true) &&
isAffineConstraint(ICmp->getOperand(1), R, Scope, SE, Params, true);
} else if (auto *BinOp = dyn_cast<BinaryOperator>(V)) {
auto Opcode = BinOp->getOpcode();
if (Opcode == Instruction::And || Opcode == Instruction::Or)
return isAffineParamConstraint(BinOp->getOperand(0), R, Scope, SE, Params,
false) &&
isAffineParamConstraint(BinOp->getOperand(1), R, Scope, SE, Params,
false);
return isAffineConstraint(BinOp->getOperand(0), R, Scope, SE, Params,
false) &&
isAffineConstraint(BinOp->getOperand(1), R, Scope, SE, Params,
false);
/* Fall through */
}
if (!OrExpr)
return false;
return isAffineParamExpr(V, R, Scope, SE, Params);
return isAffineExpr(V, R, Scope, SE, Params);
}
ParameterSetTy getParamsInAffineExpr(const Region *R, Loop *Scope,

View File

@ -0,0 +1,55 @@
; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops -disable-output < %s 2>&1 | FileCheck %s --check-prefix=REMARK
; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
;
; REMARK: remark: <unknown>:0:0: Use user assumption: [n, b] -> { : n <= 100 or (b = 0 and n >= 101) }
;
; CHECK: Context:
; CHECK-NEXT: [n, b] -> { : -9223372036854775808 <= n <= 9223372036854775807 and ((n <= 100 and -9223372036854775808 <= b <= 9223372036854775807) or (b = 0 and n >= 101)) }
; CHECK-NEXT: Assumed Context:
; CHECK-NEXT: [n, b] -> { : }
; CHECK-NEXT: Invalid Context:
; CHECK-NEXT: [n, b] -> { : 1 = 0 }
;
; void foo(float A[][100], long b, long n) {
; for (long i = 0; i < n; i++)
; if (b)
; A[42][i] = 42.0;
; }
;
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@.src = private unnamed_addr constant [12 x i8] c"/tmp/test.c\00", align 1
@0 = private unnamed_addr constant { i16, i16, [14 x i8] } { i16 -1, i16 0, [14 x i8] c"'float [100]'\00" }
@1 = private unnamed_addr constant { i16, i16, [7 x i8] } { i16 0, i16 13, [7 x i8] c"'long'\00" }
define void @foo([100 x float]* %A, i64 %b, i64 %n) {
entry:
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
%cmp = icmp slt i64 %i.0, %n
br i1 %cmp, label %if.cond, label %for.end
if.cond:
%bcmp = icmp ne i64 %b, 0
br i1 %bcmp, label %for.body, label %for.inc
for.body: ; preds = %for.cond
%tmp = icmp slt i64 %i.0, 100
call void @llvm.assume(i1 %tmp)
%arrayidx1 = getelementptr inbounds [100 x float], [100 x float]* %A, i64 42, i64 %i.0
store float 4.200000e+01, float* %arrayidx1, align 4
br label %for.inc
for.inc: ; preds = %for.body
%inc = add nuw nsw i64 %i.0, 1
br label %for.cond
for.end: ; preds = %for.cond
ret void
}
declare void @llvm.assume(i1) #1

View File

@ -0,0 +1,42 @@
; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
;
; CHECK: Context:
; CHECK-NEXT: [n] -> { : -9223372036854775808 <= n <= 100 }
;
; void foo(float A[][100], long n) {
; for (long i = 0; i < n; i++)
; A[42][i] = 42.0;
; }
;
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@.src = private unnamed_addr constant [12 x i8] c"/tmp/test.c\00", align 1
@0 = private unnamed_addr constant { i16, i16, [14 x i8] } { i16 -1, i16 0, [14 x i8] c"'float [100]'\00" }
@1 = private unnamed_addr constant { i16, i16, [7 x i8] } { i16 0, i16 13, [7 x i8] c"'long'\00" }
define void @foo([100 x float]* %A, i64 %n) {
entry:
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
%cmp = icmp slt i64 %i.0, %n
br i1 %cmp, label %for.body, label %for.end
for.body: ; preds = %for.cond
%tmp = icmp slt i64 %i.0, 100
call void @llvm.assume(i1 %tmp)
%arrayidx1 = getelementptr inbounds [100 x float], [100 x float]* %A, i64 42, i64 %i.0
store float 4.200000e+01, float* %arrayidx1, align 4
br label %for.inc
for.inc: ; preds = %for.body
%inc = add nuw nsw i64 %i.0, 1
br label %for.cond
for.end: ; preds = %for.cond
ret void
}
declare void @llvm.assume(i1) #1

View File

@ -0,0 +1,48 @@
; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops -disable-output < %s 2>&1 | FileCheck %s --check-prefix=REMARK
; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
;
; REMARK: remark: <unknown>:0:0: SCoP begins here.
; REMARK-NEXT: remark: <unknown>:0:0: Use user assumption: [n] -> { : n <= 100 }
; REMARK-NEXT: remark: <unknown>:0:0: Signed-unsigned restriction: [n] -> { : n < 0 }
; REMARK-NEXT: remark: <unknown>:0:0: SCoP ends here.
;
; CHECK: Context:
; CHECK-NEXT: [n] -> { : -9223372036854775808 <= n <= 100 }
;
; void foo(float A[][100], long n) {
; for (long i = 0; i < n; i++)
; A[42][i] = 42.0;
; }
;
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@.src = private unnamed_addr constant [12 x i8] c"/tmp/test.c\00", align 1
@0 = private unnamed_addr constant { i16, i16, [14 x i8] } { i16 -1, i16 0, [14 x i8] c"'float [100]'\00" }
@1 = private unnamed_addr constant { i16, i16, [7 x i8] } { i16 0, i16 13, [7 x i8] c"'long'\00" }
define void @foo([100 x float]* %A, i64 %n) {
entry:
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
%cmp = icmp ult i64 %i.0, %n
br i1 %cmp, label %for.body, label %for.end
for.body: ; preds = %for.cond
%tmp = icmp slt i64 %i.0, 100
call void @llvm.assume(i1 %tmp)
%arrayidx1 = getelementptr inbounds [100 x float], [100 x float]* %A, i64 42, i64 %i.0
store float 4.200000e+01, float* %arrayidx1, align 4
br label %for.inc
for.inc: ; preds = %for.body
%inc = add nuw nsw i64 %i.0, 1
br label %for.cond
for.end: ; preds = %for.cond
ret void
}
declare void @llvm.assume(i1) #1

View File

@ -5,7 +5,7 @@
; CHECK-NEXT: remark: <unknown>:0:0: Use user assumption: [M, N] -> { : N <= 2147483647 - M }
; CHECK-NEXT: remark: <unknown>:0:0: Use user assumption: [M, N] -> { : -2147483648 - M <= N <= 2147483647 - M }
; CHECK-NEXT: remark: <unknown>:0:0: Use user assumption: [M, N, Debug] -> { : Debug = 0 and 0 < M <= 100 and -2147483648 - M <= N <= 2147483647 - M }
; CHECK-NEXT: remark: <unknown>:0:0: Use user assumption: [M, N, Debug] -> { : Debug = 0 and 0 < M <= 100 and 0 < N <= 2147483647 - M }
; CHECK-NEXT: remark: <unknown>:0:0: Use user assumption: [M, N, Debug] -> { : Debug = 0 and 0 < M <= 100 and 0 < N <= 2147483647 - M }
; CHECK-NEXT: remark: <unknown>:0:0: SCoP ends here.
; SCOP: Context:

View File

@ -1,6 +1,7 @@
; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops -disable-output < %s 2>&1 | FileCheck %s
;
; CHECK: remark: <unknown>:0:0: SCoP begins here.
; CHECK-NEXT: remark: <unknown>:0:0: Use user assumption: [i, N, M] -> { : N <= i or (N > i and N >= 0) }
; CHECK-NEXT: remark: <unknown>:0:0: Inbounds assumption: [i, N, M] -> { : N <= i or (N > i and M <= 100) }
; CHECK-NEXT: remark: <unknown>:0:0: SCoP ends here.
;