summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--polly/include/polly/Support/ScopHelper.h4
-rw-r--r--polly/lib/Support/ScopHelper.cpp24
-rw-r--r--polly/test/ScopInfo/user-defined-error-functions.ll114
3 files changed, 134 insertions, 8 deletions
diff --git a/polly/include/polly/Support/ScopHelper.h b/polly/include/polly/Support/ScopHelper.h
index ea5ceddc961..c1c2c43bfbd 100644
--- a/polly/include/polly/Support/ScopHelper.h
+++ b/polly/include/polly/Support/ScopHelper.h
@@ -113,8 +113,8 @@ llvm::Value *expandCodeFor(Scop &S, llvm::ScalarEvolution &SE,
/// the following conditions:
///
/// - It is terminated by an unreachable instruction
-/// - It contains a call to a function named:
-/// + __ubsan_handle_out_of_bounds
+/// - It contains a call to a function listed in the command line argument
+/// --polly-error-functions=name1,name2,name3
///
/// @param BB The block to check.
///
diff --git a/polly/lib/Support/ScopHelper.cpp b/polly/lib/Support/ScopHelper.cpp
index 9acfed661d8..89c4fa33dca 100644
--- a/polly/lib/Support/ScopHelper.cpp
+++ b/polly/lib/Support/ScopHelper.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "polly/Support/ScopHelper.h"
+#include "polly/Options.h"
#include "polly/ScopInfo.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/LoopInfo.h"
@@ -28,6 +29,11 @@ using namespace polly;
#define DEBUG_TYPE "polly-scop-helper"
+static cl::list<std::string>
+ ErrorFunctions("polly-error-functions",
+ cl::desc("A list of error functions"), cl::Hidden,
+ cl::ZeroOrMore, cl::CommaSeparated, cl::cat(PollyCategory));
+
Value *polly::getPointerOperand(Instruction &Inst) {
if (LoadInst *load = dyn_cast<LoadInst>(&Inst))
return load->getPointerOperand();
@@ -343,15 +349,21 @@ Value *polly::expandCodeFor(Scop &S, ScalarEvolution &SE, const DataLayout &DL,
bool polly::isErrorBlock(BasicBlock &BB) {
- for (Instruction &Inst : BB)
- if (CallInst *CI = dyn_cast<CallInst>(&Inst))
- if (Function *F = CI->getCalledFunction())
- if (F->getName().equals("__ubsan_handle_out_of_bounds"))
- return true;
-
if (isa<UnreachableInst>(BB.getTerminator()))
return true;
+ if (ErrorFunctions.empty())
+ return false;
+
+ for (Instruction &Inst : BB)
+ if (CallInst *CI = dyn_cast<CallInst>(&Inst))
+ if (Function *F = CI->getCalledFunction()) {
+ const auto &FnName = F->getName();
+ for (const auto &ErrorFn : ErrorFunctions)
+ if (FnName.equals(ErrorFn))
+ return true;
+ }
+
return false;
}
diff --git a/polly/test/ScopInfo/user-defined-error-functions.ll b/polly/test/ScopInfo/user-defined-error-functions.ll
new file mode 100644
index 00000000000..e11771a35aa
--- /dev/null
+++ b/polly/test/ScopInfo/user-defined-error-functions.ll
@@ -0,0 +1,114 @@
+; RUN: opt %loadPolly -polly-scops -polly-detect-unprofitable -polly-error-functions=timer_start,timer_stop -analyze < %s | FileCheck %s
+;
+; Allow the user to define function names that are treated as
+; error functions and assumed not to be executed.
+;
+; void timer_start(void);
+; void timer_stop(void);
+; void kernel(int *A, int *B, int timeit, int N) {
+;
+; if (timeit)
+; timer_start();
+;
+; for (int i = 0; i < N; i++)
+; A[i] += B[i];
+;
+; if (timeit) {
+; timer_stop();
+; timer_start();
+; }
+;
+; for (int i = 0; i < N; i++)
+; A[i] += B[i];
+;
+; if (timeit)
+; timer_stop();
+; }
+;
+; CHECK: Region: %for.cond---%if.end.20
+; CHECK: Assumed Context:
+; CHECK: [N, timeit] -> { : timeit = 0 }
+; CHECK: Statements {
+; CHECK: Stmt
+; CHECK: Stmt
+; CHECK-NOT Stmt
+; CHECK: }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @kernel(i32* %A, i32* %B, i32 %timeit, i32 %N) {
+entry:
+ %tobool = icmp eq i32 %timeit, 0
+ br i1 %tobool, label %if.end, label %if.then
+
+if.then: ; preds = %entry
+ call void @timer_start()
+ br label %if.end
+
+if.end: ; preds = %entry, %if.then
+ %tmp = sext i32 %N to i64
+ br label %for.cond
+
+for.cond: ; preds = %for.inc, %if.end
+ %indvars.iv1 = phi i64 [ %indvars.iv.next2, %for.inc ], [ 0, %if.end ]
+ %cmp = icmp slt i64 %indvars.iv1, %tmp
+ br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+ %arrayidx = getelementptr inbounds i32, i32* %B, i64 %indvars.iv1
+ %tmp3 = load i32, i32* %arrayidx, align 4
+ %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv1
+ %tmp4 = load i32, i32* %arrayidx2, align 4
+ %add = add nsw i32 %tmp4, %tmp3
+ store i32 %add, i32* %arrayidx2, align 4
+ br label %for.inc
+
+for.inc: ; preds = %for.body
+ %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+ br label %for.cond
+
+for.end: ; preds = %for.cond
+ %tobool3 = icmp eq i32 %timeit, 0
+ br i1 %tobool3, label %if.end.5, label %if.then.4
+
+if.then.4: ; preds = %for.end
+ call void @timer_stop()
+ call void @timer_start()
+ br label %if.end.5
+
+if.end.5: ; preds = %for.end, %if.then.4
+ %tmp5 = sext i32 %N to i64
+ br label %for.cond.7
+
+for.cond.7: ; preds = %for.inc.15, %if.end.5
+ %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc.15 ], [ 0, %if.end.5 ]
+ %cmp8 = icmp slt i64 %indvars.iv, %tmp5
+ br i1 %cmp8, label %for.body.9, label %for.end.17
+
+for.body.9: ; preds = %for.cond.7
+ %arrayidx11 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+ %tmp6 = load i32, i32* %arrayidx11, align 4
+ %arrayidx13 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+ %tmp7 = load i32, i32* %arrayidx13, align 4
+ %add14 = add nsw i32 %tmp7, %tmp6
+ store i32 %add14, i32* %arrayidx13, align 4
+ br label %for.inc.15
+
+for.inc.15: ; preds = %for.body.9
+ %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+ br label %for.cond.7
+
+for.end.17: ; preds = %for.cond.7
+ %tobool18 = icmp eq i32 %timeit, 0
+ br i1 %tobool18, label %if.end.20, label %if.then.19
+
+if.then.19: ; preds = %for.end.17
+ call void @timer_stop()
+ br label %if.end.20
+
+if.end.20: ; preds = %for.end.17, %if.then.19
+ ret void
+}
+
+declare void @timer_start()
+declare void @timer_stop()
OpenPOWER on IntegriCloud