diff options
| -rw-r--r-- | polly/include/polly/CodeGen/Cloog.h | 15 | ||||
| -rw-r--r-- | polly/lib/CodeGen/Cloog.cpp | 34 | ||||
| -rw-r--r-- | polly/lib/CodeGen/CodeGeneration.cpp | 55 | ||||
| -rw-r--r-- | polly/test/CodeGen/OpenMP/copy_in_argument.ll | 34 | ||||
| -rw-r--r-- | polly/test/CodeGen/OpenMP/copy_in_temporary.ll | 35 | ||||
| -rw-r--r-- | polly/test/CodeGen/OpenMP/param_referenced_in_stmt.ll | 38 |
6 files changed, 208 insertions, 3 deletions
diff --git a/polly/include/polly/CodeGen/Cloog.h b/polly/include/polly/CodeGen/Cloog.h index de0851618a4..22ddea2792e 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 bdfa8be2ac3..f08aa1c07ae 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 d713ae4721b..bac2427cc81 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<Value*> getOMPValues(); + SetVector<Value*> 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<Value*> 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<Value *> Values; +public: + ParameterVisitor() : ClastVisitor(), Values() { } + + void visitUser(const clast_user_stmt *Stmt) { + const ScopStmt *S = static_cast<const ScopStmt *>(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<Instruction>(SrcVal)) + if (S->getParent()->getRegion().contains(OpInst)) + continue; + + if (isa<Instruction>(SrcVal) || isa<Argument>(SrcVal)) + Values.insert(SrcVal); + } + } + } + + // Iterator to iterate over the values found. + typedef std::set<Value *>::const_iterator const_iterator; + inline const_iterator begin() const { return Values.begin(); } + inline const_iterator end() const { return Values.end(); } +}; + +SetVector<Value*> ClastStmtCodeGen::getOMPValues(const clast_stmt *Body) { SetVector<Value*> Values; // The clast variables @@ -479,6 +514,20 @@ SetVector<Value*> 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 00000000000..cc45cf65a3c --- /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 00000000000..1bd2352cada --- /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 00000000000..f7c2887f40d --- /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 |

