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:
parent
84174c3771
commit
2b92a0e4ee
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
;
|
||||
|
|
Loading…
Reference in New Issue