Allow user defined error functions

The user can provide function names with
    -polly-error-functions=name1,name2,name3
  that will be treated as error functions. Any call to them is assumed
  not to be executed.

  This feature is mainly for developers to play around with the new
  "error block" feature.

llvm-svn: 249098
This commit is contained in:
Johannes Doerfert 2015-10-01 23:45:51 +00:00
parent cbe6411401
commit f80f3b0449
3 changed files with 134 additions and 8 deletions

View File

@ -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.
///

View File

@ -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;
}

View File

@ -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()