From 43e1eadf263bb8a25bb9ac6705d3ab51eeeab1d0 Mon Sep 17 00:00:00 2001 From: Johannes Doerfert Date: Tue, 15 Jul 2014 21:06:48 +0000 Subject: [PATCH] [Refactor] Use attributes to mark function as invalid for polly + Test case annotated with the new attribute + Modified test case to check if subfunctions are annotated llvm-svn: 213093 --- polly/include/polly/ScopDetection.h | 17 +++------ polly/lib/Analysis/ScopDetection.cpp | 7 +++- polly/lib/CodeGen/LoopGenerators.cpp | 2 +- .../Cloog/CodeGen/OpenMP/invalidate_subfn_scops.ll | 4 +- .../Cloog/CodeGen/OpenMP/simple_nested_loop.ll | 4 ++ polly/test/ScopDetect/skip_function_attribute.ll | 44 ++++++++++++++++++++++ 6 files changed, 63 insertions(+), 15 deletions(-) create mode 100644 polly/test/ScopDetect/skip_function_attribute.ll diff --git a/polly/include/polly/ScopDetection.h b/polly/include/polly/ScopDetection.h index e62db93..96eeaef 100644 --- a/polly/include/polly/ScopDetection.h +++ b/polly/include/polly/ScopDetection.h @@ -108,6 +108,9 @@ typedef std::map BaseToElSize; extern bool PollyTrackFailures; extern bool PollyDelinearize; +/// @brief A function attribute which will cause Polly to skip the function +extern llvm::StringRef PollySkipFnAttr; + //===----------------------------------------------------------------------===// /// @brief Pass to detect the maximal static control parts (Scops) of a /// function. @@ -146,10 +149,6 @@ class ScopDetection : public FunctionPass { // Remember a list of errors for every region. mutable RejectLogsContainer RejectLogs; - // Remember the invalid functions producted by backends; - typedef std::set FunctionSet; - FunctionSet InvalidFunctions; - // Delinearize all non affine memory accesses and return false when there // exists a non affine memory access that cannot be delinearized. Return true // when all array accesses are affine after delinearization. @@ -249,13 +248,9 @@ class ScopDetection : public FunctionPass { /// @return True if the loop is valid in the region. bool isValidLoop(Loop *L, DetectionContext &Context) const; - /// @brief Check if a function is an OpenMP subfunction. - /// - /// An OpenMP subfunction is not valid for Scop detection. - /// - /// @param F The function to check. + /// @brief Check if the function @p F is marked as invalid. /// - /// @return True if the function is not an OpenMP subfunction. + /// @note An OpenMP subfunction will be marked as invalid. bool isValidFunction(llvm::Function &F); /// @brief Print the locations of all detected scops. @@ -347,7 +342,7 @@ public: /// the function. /// /// @param F The function to mark as invalid. - void markFunctionAsInvalid(const Function *F) { InvalidFunctions.insert(F); } + void markFunctionAsInvalid(Function *F) const; /// @brief Verify if all valid Regions in this Function are still valid /// after some transformations. diff --git a/polly/lib/Analysis/ScopDetection.cpp b/polly/lib/Analysis/ScopDetection.cpp index 53c5ed7..f061f01 100644 --- a/polly/lib/Analysis/ScopDetection.cpp +++ b/polly/lib/Analysis/ScopDetection.cpp @@ -136,6 +136,7 @@ static cl::opt bool polly::PollyTrackFailures = false; bool polly::PollyDelinearize = false; +StringRef polly::PollySkipFnAttr = "polly.skip.fn"; //===----------------------------------------------------------------------===// // Statistics. @@ -769,8 +770,12 @@ bool ScopDetection::isValidRegion(DetectionContext &Context) const { return true; } +void ScopDetection::markFunctionAsInvalid(Function *F) const { + F->addFnAttr(PollySkipFnAttr); +} + bool ScopDetection::isValidFunction(llvm::Function &F) { - return !InvalidFunctions.count(&F); + return !F.hasFnAttribute(PollySkipFnAttr); } void ScopDetection::printLocations(llvm::Function &F) { diff --git a/polly/lib/CodeGen/LoopGenerators.cpp b/polly/lib/CodeGen/LoopGenerators.cpp index 52a47ef..432960d 100644 --- a/polly/lib/CodeGen/LoopGenerators.cpp +++ b/polly/lib/CodeGen/LoopGenerators.cpp @@ -229,7 +229,7 @@ Function *OMPGenerator::createSubfunctionDefinition() { Function *FN = Function::Create(FT, Function::InternalLinkage, F->getName() + ".omp_subfn", M); // Do not run any polly pass on the new function. - P->getAnalysis().markFunctionAsInvalid(FN); + FN->addFnAttr(PollySkipFnAttr); Function::arg_iterator AI = FN->arg_begin(); AI->setName("omp.userContext"); diff --git a/polly/test/Cloog/CodeGen/OpenMP/invalidate_subfn_scops.ll b/polly/test/Cloog/CodeGen/OpenMP/invalidate_subfn_scops.ll index 6e75fe8..b4eec09 100644 --- a/polly/test/Cloog/CodeGen/OpenMP/invalidate_subfn_scops.ll +++ b/polly/test/Cloog/CodeGen/OpenMP/invalidate_subfn_scops.ll @@ -1,4 +1,4 @@ -; RUN: opt %loadPolly %defaultOpts -polly-codegen -enable-polly-openmp -analyze < %s 2>&1 | not FileCheck %s +; RUN: opt %loadPolly %defaultOpts -polly-codegen -enable-polly-openmp -analyze < %s 2>&1 | FileCheck %s ;#define N 500000 ;float A[N]; @@ -47,4 +47,4 @@ for.end11: ; preds = %for.inc8 } -; CHECK: Checking region: omp.setup +; CHECK-NOT: Checking region: omp.setup diff --git a/polly/test/Cloog/CodeGen/OpenMP/simple_nested_loop.ll b/polly/test/Cloog/CodeGen/OpenMP/simple_nested_loop.ll index 1f4d68a..27cecf2 100644 --- a/polly/test/Cloog/CodeGen/OpenMP/simple_nested_loop.ll +++ b/polly/test/Cloog/CodeGen/OpenMP/simple_nested_loop.ll @@ -86,3 +86,7 @@ declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i32, i1) nounwind ; CHECK: call void @loop_openmp.omp_subfn(i8* %omp_data) ; CHECK: call void @GOMP_parallel_end() +; Verify the new subfunction is annotated such that SCoP detection will skip it. +; CHECK: @loop_openmp.omp_subfn({{.*}}) [[ATTR:#[0-9]+]] +; CHECK: attributes [[ATTR]] = {{{[^\}]*}}polly.skip.fn{{[^\}]*}}} + diff --git a/polly/test/ScopDetect/skip_function_attribute.ll b/polly/test/ScopDetect/skip_function_attribute.ll new file mode 100644 index 0000000..9d181fe --- /dev/null +++ b/polly/test/ScopDetect/skip_function_attribute.ll @@ -0,0 +1,44 @@ +; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s +; +; Verify polly skips this function +; +; CHECK-NOT: Valid Region for Scop +; +; void polly_skip_me(int *A, int N) { +; for (int i = 0; i < N; i++) +; A[i] = A[i] * A[i] + A[i]; +; } +; +target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64" + +define void @polly_skip_me(i32* %A, i32 %N) #0 { +entry: + br label %entry.split + +entry.split: ; preds = %entry + %cmp1 = icmp sgt i32 %N, 0 + br i1 %cmp1, label %for.body.preheader, label %for.end + +for.body.preheader: ; preds = %entry.split + br label %for.body + +for.body: ; preds = %for.body.preheader, %for.body + %i.02 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ] + %arrayidx = getelementptr inbounds i32* %A, i32 %i.02 + %tmp = load i32* %arrayidx, align 4 + %mul = mul nsw i32 %tmp, %tmp + %add = add nsw i32 %mul, %tmp + %arrayidx3 = getelementptr inbounds i32* %A, i32 %i.02 + store i32 %add, i32* %arrayidx3, align 4 + %inc = add nsw i32 %i.02, 1 + %cmp = icmp slt i32 %inc, %N + br i1 %cmp, label %for.body, label %for.end.loopexit + +for.end.loopexit: ; preds = %for.body + br label %for.end + +for.end: ; preds = %for.end.loopexit, %entry.split + ret void +} + +attributes #0 = { "polly.skip.fn" } -- 2.7.4