summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--polly/include/polly/CodeGen/Cloog.h15
-rw-r--r--polly/lib/CodeGen/Cloog.cpp34
-rw-r--r--polly/lib/CodeGen/CodeGeneration.cpp55
-rw-r--r--polly/test/CodeGen/OpenMP/copy_in_argument.ll34
-rw-r--r--polly/test/CodeGen/OpenMP/copy_in_temporary.ll35
-rw-r--r--polly/test/CodeGen/OpenMP/param_referenced_in_stmt.ll38
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
OpenPOWER on IntegriCloud