From: Tobias Grosser Date: Thu, 1 Nov 2012 05:34:48 +0000 (+0000) Subject: CodeGen: Add scop-parameters to the OpenMP context X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=177982c478bd1344e68937a10082fd698b42a106;p=platform%2Fupstream%2Fllvm.git CodeGen: Add scop-parameters to the OpenMP context In addition to the arrays and clast variables a SCoP statement may also refer to values defined before the SCoP or to function arguments. Detect these values and add them to the set of values passed to the function generated for OpenMP parallel execution of a clast. Committed with additional test cases and some refactoring. Contributed by: Armin Groesslinger llvm-svn: 167214 --- diff --git a/polly/include/polly/CodeGen/Cloog.h b/polly/include/polly/CodeGen/Cloog.h index de08516..22ddea2 100644 --- a/polly/include/polly/CodeGen/Cloog.h +++ b/polly/include/polly/CodeGen/Cloog.h @@ -64,6 +64,21 @@ namespace polly { virtual void getAnalysisUsage(AnalysisUsage &AU) const; virtual void releaseMemory(); }; + + // Visitor class for clasts. + // Only 'visitUser' has to be implemented by subclasses; the default + // implementations of the other methods traverse the clast recursively. + class ClastVisitor { + public: + virtual void visit(const clast_stmt *stmt); + + virtual void visitAssignment(const clast_assignment *stmt); + virtual void visitBlock(const clast_block *stmt); + virtual void visitFor(const clast_for *stmt); + virtual void visitGuard(const clast_guard *stmt); + + virtual void visitUser(const clast_user_stmt *stmt) = 0; + }; } namespace llvm { diff --git a/polly/lib/CodeGen/Cloog.cpp b/polly/lib/CodeGen/Cloog.cpp index bdfa8be..f08aa1c 100644 --- a/polly/lib/CodeGen/Cloog.cpp +++ b/polly/lib/CodeGen/Cloog.cpp @@ -217,6 +217,40 @@ CloogInput *Cloog::buildCloogInput() { CloogInput *Input = cloog_input_alloc(Context, Statements); return Input; } + +void ClastVisitor::visit(const clast_stmt *stmt) { + if (CLAST_STMT_IS_A(stmt, stmt_root)) + assert(false && "No second root statement expected"); + else if (CLAST_STMT_IS_A(stmt, stmt_ass)) + return visitAssignment((const clast_assignment *)stmt); + else if (CLAST_STMT_IS_A(stmt, stmt_user)) + return visitUser((const clast_user_stmt *)stmt); + else if (CLAST_STMT_IS_A(stmt, stmt_block)) + return visitBlock((const clast_block *)stmt); + else if (CLAST_STMT_IS_A(stmt, stmt_for)) + return visitFor((const clast_for *)stmt); + else if (CLAST_STMT_IS_A(stmt, stmt_guard)) + return visitGuard((const clast_guard *)stmt); + + if (stmt->next) + visit(stmt->next); +} + +void ClastVisitor::visitAssignment(const clast_assignment *stmt) { +} + +void ClastVisitor::visitBlock(const clast_block *stmt) { + visit(stmt->body); +} + +void ClastVisitor::visitFor(const clast_for *stmt) { + visit(stmt->body); +} + +void ClastVisitor::visitGuard(const clast_guard *stmt) { + visit(stmt->then); +} + } // End namespace polly. namespace { diff --git a/polly/lib/CodeGen/CodeGeneration.cpp b/polly/lib/CodeGen/CodeGeneration.cpp index d713ae47..bac2427 100644 --- a/polly/lib/CodeGen/CodeGeneration.cpp +++ b/polly/lib/CodeGen/CodeGeneration.cpp @@ -283,7 +283,7 @@ private: /// /// Create a list of values that has to be stored into the OpenMP subfuncition /// structure. - SetVector getOMPValues(); + SetVector getOMPValues(const clast_stmt *Body); /// @brief Update ClastVars and ValueMap according to a value map. /// @@ -461,7 +461,42 @@ void ClastStmtCodeGen::codegenForSequential(const clast_for *f) { Builder.SetInsertPoint(AfterBB->begin()); } -SetVector ClastStmtCodeGen::getOMPValues() { +// Helper class to determine all scalar parameters used in the basic blocks of a +// clast. Scalar parameters are scalar variables defined outside of the SCoP. +class ParameterVisitor : public ClastVisitor { + std::set Values; +public: + ParameterVisitor() : ClastVisitor(), Values() { } + + void visitUser(const clast_user_stmt *Stmt) { + const ScopStmt *S = static_cast(Stmt->statement->usr); + const BasicBlock *BB = S->getBasicBlock(); + + // Check all the operands of instructions in the basic block. + for (BasicBlock::const_iterator BI = BB->begin(), BE = BB->end(); BI != BE; + ++BI) { + const Instruction &Inst = *BI; + for (Instruction::const_op_iterator II = Inst.op_begin(), + IE = Inst.op_end(); II != IE; ++II) { + Value *SrcVal = *II; + + if (Instruction *OpInst = dyn_cast(SrcVal)) + if (S->getParent()->getRegion().contains(OpInst)) + continue; + + if (isa(SrcVal) || isa(SrcVal)) + Values.insert(SrcVal); + } + } + } + + // Iterator to iterate over the values found. + typedef std::set::const_iterator const_iterator; + inline const_iterator begin() const { return Values.begin(); } + inline const_iterator end() const { return Values.end(); } +}; + +SetVector ClastStmtCodeGen::getOMPValues(const clast_stmt *Body) { SetVector Values; // The clast variables @@ -479,6 +514,20 @@ SetVector ClastStmtCodeGen::getOMPValues() { } } + // Find the temporaries that are referenced in the clast statements' + // basic blocks but are not defined by these blocks (e.g., references + // to function arguments or temporaries defined before the start of + // the SCoP). + ParameterVisitor Params; + Params.visit(Body); + + for (ParameterVisitor::const_iterator PI = Params.begin(), PE = Params.end(); + PI != PE; ++PI) { + Value *V = *PI; + Values.insert(V); + DEBUG(dbgs() << "Adding temporary for OMP copy-in: " << *V << "\n"); + } + return Values; } @@ -525,7 +574,7 @@ void ClastStmtCodeGen::codegenForOpenMP(const clast_for *For) { LB = ExpGen.codegen(For->LB, IntPtrTy); UB = ExpGen.codegen(For->UB, IntPtrTy); - Values = getOMPValues(); + Values = getOMPValues(For->body); IV = OMPGen.createParallelLoop(LB, UB, Stride, Values, VMap, &LoopBody); BasicBlock::iterator AfterLoop = Builder.GetInsertPoint(); diff --git a/polly/test/CodeGen/OpenMP/copy_in_argument.ll b/polly/test/CodeGen/OpenMP/copy_in_argument.ll new file mode 100644 index 0000000..cc45cf6 --- /dev/null +++ b/polly/test/CodeGen/OpenMP/copy_in_argument.ll @@ -0,0 +1,34 @@ +; RUN: opt %loadPolly -polly-codegen -enable-polly-openmp -S %s | FileCheck %s +; +; 'arg' has the same type as A[i], i.e., the function argument has to be +; copied to the function generated for the loop. +; +; float A[100]; +; void copy_in_test(float arg) { +; long i; +; for (i=0; i<100; ++i) +; A[i] = arg; +; } + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@A = common global [100 x float] zeroinitializer, align 16 + +define void @copy_in_test(float %arg) nounwind uwtable { +entry: + br label %for.body + +for.body: ; preds = %for.body, %entry + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] + %arrayidx = getelementptr inbounds [100 x float]* @A, i64 0, i64 %indvars.iv + store float %arg, float* %arrayidx + %indvars.iv.next = add i64 %indvars.iv, 1 + %exitcond = icmp eq i64 %indvars.iv.next, 100 + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +} + +; CHECK: %omp.userContext = alloca { [100 x float]*, float } diff --git a/polly/test/CodeGen/OpenMP/copy_in_temporary.ll b/polly/test/CodeGen/OpenMP/copy_in_temporary.ll new file mode 100644 index 0000000..1bd2352 --- /dev/null +++ b/polly/test/CodeGen/OpenMP/copy_in_temporary.ll @@ -0,0 +1,35 @@ +; RUN: opt %loadPolly -polly-codegen -enable-polly-openmp -S %s | FileCheck %s +; +; 'arg' is converted to float before the loop, so the corresponding temporary +; has to be copied to the function generated for the loop. +; +; float A[100]; +; void copy_in_test(long arg) { +; long i; +; for (i=0; i<100; ++i) +; A[i] = arg; +; } + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@A = common global [100 x float] zeroinitializer, align 16 + +define void @copy_in_test(i64 %arg) nounwind uwtable { +entry: + %conv = sitofp i64 %arg to float + br label %for.body + +for.body: ; preds = %for.body, %entry + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] + %arrayidx = getelementptr inbounds [100 x float]* @A, i64 0, i64 %indvars.iv + store float %conv, float* %arrayidx + %indvars.iv.next = add i64 %indvars.iv, 1 + %exitcond = icmp eq i64 %indvars.iv.next, 100 + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +} + +; CHECK: %omp.userContext = alloca { [100 x float]*, float } diff --git a/polly/test/CodeGen/OpenMP/param_referenced_in_stmt.ll b/polly/test/CodeGen/OpenMP/param_referenced_in_stmt.ll new file mode 100644 index 0000000..f7c2887 --- /dev/null +++ b/polly/test/CodeGen/OpenMP/param_referenced_in_stmt.ll @@ -0,0 +1,38 @@ +; RUN: opt %loadPolly -polly-codegen %s -enable-polly-openmp -S | FileCheck %s +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + + +; This test case implements the following code: +; +; for (i = 0; i < 1024; i++) +; A[i] = A[i] * param +; +; The problem is that 'param' is not references in any subscript of loop +; bound, but it must still be forwarded to the OpenMP subfunction. + +define void @foo(double %param, [1024 x double]* %A) { +entry: + br label %for.preheader + +for.preheader: + br label %for.body + +for.body: + %indvar = phi i64 [ 0, %for.preheader ], [ %indvar.next, %for.inc ] + %arrayidx = getelementptr [1024 x double]* %A, i64 0, i64 %indvar + %val = load double* %arrayidx + %mul = fmul double %param, %val + store double %mul, double* %arrayidx, align 8 + br label %for.inc + +for.inc: + %indvar.next = add i64 %indvar, 1 + %exitcond = icmp eq i64 %indvar.next, 1024 + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} + +; CHECK: omp_subfn