[OPENMP] Codegen for 'ordered' directive.
Add codegen for 'ordered' directive: __kmpc_ordered(ident_t *, gtid); <associated statement>; __kmpc_end_ordered(ident_t *, gtid); Also for 'for' directives with the dynamic scheduling and an 'ordered' clause added a call to '__kmpc_dispatch_fini_(4|8)[u]()' function after increment expression for loop control variable: while(__kmpc_dispatch_next(&LB, &UB)) { idx = LB; while (idx <= UB) { BODY; ++idx; __kmpc_dispatch_fini_(4|8)[u](); // For ordered loops only. } // inner loop } Differential Revision: http://reviews.llvm.org/D9070 llvm-svn: 235496
This commit is contained in:
parent
e7508c9fc7
commit
98eb6e3d41
|
@ -710,6 +710,22 @@ CGOpenMPRuntime::createRuntimeFunction(OpenMPRTLFunction Function) {
|
||||||
CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_end_reduce_nowait");
|
CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_end_reduce_nowait");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OMPRTL__kmpc_ordered: {
|
||||||
|
// Build void __kmpc_ordered(ident_t *loc, kmp_int32 global_tid);
|
||||||
|
llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
|
||||||
|
llvm::FunctionType *FnTy =
|
||||||
|
llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
|
||||||
|
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_ordered");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OMPRTL__kmpc_end_ordered: {
|
||||||
|
// Build void __kmpc_ordered(ident_t *loc, kmp_int32 global_tid);
|
||||||
|
llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
|
||||||
|
llvm::FunctionType *FnTy =
|
||||||
|
llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
|
||||||
|
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_ordered");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return RTLFn;
|
return RTLFn;
|
||||||
}
|
}
|
||||||
|
@ -762,6 +778,23 @@ llvm::Constant *CGOpenMPRuntime::createDispatchInitFunction(unsigned IVSize,
|
||||||
return CGM.CreateRuntimeFunction(FnTy, Name);
|
return CGM.CreateRuntimeFunction(FnTy, Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::Constant *CGOpenMPRuntime::createDispatchFiniFunction(unsigned IVSize,
|
||||||
|
bool IVSigned) {
|
||||||
|
assert((IVSize == 32 || IVSize == 64) &&
|
||||||
|
"IV size is not compatible with the omp runtime");
|
||||||
|
auto Name =
|
||||||
|
IVSize == 32
|
||||||
|
? (IVSigned ? "__kmpc_dispatch_fini_4" : "__kmpc_dispatch_fini_4u")
|
||||||
|
: (IVSigned ? "__kmpc_dispatch_fini_8" : "__kmpc_dispatch_fini_8u");
|
||||||
|
llvm::Type *TypeParams[] = {
|
||||||
|
getIdentTyPointerTy(), // loc
|
||||||
|
CGM.Int32Ty, // tid
|
||||||
|
};
|
||||||
|
llvm::FunctionType *FnTy =
|
||||||
|
llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
|
||||||
|
return CGM.CreateRuntimeFunction(FnTy, Name);
|
||||||
|
}
|
||||||
|
|
||||||
llvm::Constant *CGOpenMPRuntime::createDispatchNextFunction(unsigned IVSize,
|
llvm::Constant *CGOpenMPRuntime::createDispatchNextFunction(unsigned IVSize,
|
||||||
bool IVSigned) {
|
bool IVSigned) {
|
||||||
assert((IVSize == 32 || IVSize == 64) &&
|
assert((IVSize == 32 || IVSize == 64) &&
|
||||||
|
@ -1246,6 +1279,25 @@ void CGOpenMPRuntime::emitSingleRegion(CodeGenFunction &CGF,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGOpenMPRuntime::emitOrderedRegion(CodeGenFunction &CGF,
|
||||||
|
const RegionCodeGenTy &OrderedOpGen,
|
||||||
|
SourceLocation Loc) {
|
||||||
|
// __kmpc_ordered(ident_t *, gtid);
|
||||||
|
// OrderedOpGen();
|
||||||
|
// __kmpc_end_ordered(ident_t *, gtid);
|
||||||
|
// Prepare arguments and build a call to __kmpc_ordered
|
||||||
|
{
|
||||||
|
CodeGenFunction::RunCleanupsScope Scope(CGF);
|
||||||
|
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
|
||||||
|
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_ordered), Args);
|
||||||
|
// Build a call to __kmpc_end_ordered
|
||||||
|
CGF.EHStack.pushCleanup<CallEndCleanup>(
|
||||||
|
NormalAndEHCleanup, createRuntimeFunction(OMPRTL__kmpc_end_ordered),
|
||||||
|
llvm::makeArrayRef(Args));
|
||||||
|
emitInlinedDirective(CGF, OrderedOpGen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CGOpenMPRuntime::emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
|
void CGOpenMPRuntime::emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
|
||||||
OpenMPDirectiveKind Kind) {
|
OpenMPDirectiveKind Kind) {
|
||||||
// Build call __kmpc_cancel_barrier(loc, thread_id);
|
// Build call __kmpc_cancel_barrier(loc, thread_id);
|
||||||
|
@ -1378,12 +1430,8 @@ void CGOpenMPRuntime::emitForInit(CodeGenFunction &CGF, SourceLocation Loc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGOpenMPRuntime::emitForFinish(CodeGenFunction &CGF, SourceLocation Loc,
|
void CGOpenMPRuntime::emitForStaticFinish(CodeGenFunction &CGF,
|
||||||
OpenMPScheduleClauseKind ScheduleKind) {
|
SourceLocation Loc) {
|
||||||
assert((ScheduleKind == OMPC_SCHEDULE_static ||
|
|
||||||
ScheduleKind == OMPC_SCHEDULE_unknown) &&
|
|
||||||
"Non-static schedule kinds are not yet implemented");
|
|
||||||
(void)ScheduleKind;
|
|
||||||
// Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid);
|
// Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid);
|
||||||
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, OMP_IDENT_KMPC),
|
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, OMP_IDENT_KMPC),
|
||||||
getThreadID(CGF, Loc)};
|
getThreadID(CGF, Loc)};
|
||||||
|
@ -1391,6 +1439,16 @@ void CGOpenMPRuntime::emitForFinish(CodeGenFunction &CGF, SourceLocation Loc,
|
||||||
Args);
|
Args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGOpenMPRuntime::emitForOrderedDynamicIterationEnd(CodeGenFunction &CGF,
|
||||||
|
SourceLocation Loc,
|
||||||
|
unsigned IVSize,
|
||||||
|
bool IVSigned) {
|
||||||
|
// Call __kmpc_for_dynamic_fini_(4|8)[u](ident_t *loc, kmp_int32 tid);
|
||||||
|
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, OMP_IDENT_KMPC),
|
||||||
|
getThreadID(CGF, Loc)};
|
||||||
|
CGF.EmitRuntimeCall(createDispatchFiniFunction(IVSize, IVSigned), Args);
|
||||||
|
}
|
||||||
|
|
||||||
llvm::Value *CGOpenMPRuntime::emitForNext(CodeGenFunction &CGF,
|
llvm::Value *CGOpenMPRuntime::emitForNext(CodeGenFunction &CGF,
|
||||||
SourceLocation Loc, unsigned IVSize,
|
SourceLocation Loc, unsigned IVSize,
|
||||||
bool IVSigned, llvm::Value *IL,
|
bool IVSigned, llvm::Value *IL,
|
||||||
|
|
|
@ -118,6 +118,10 @@ private:
|
||||||
// Call to void __kmpc_end_reduce_nowait(ident_t *loc, kmp_int32 global_tid,
|
// Call to void __kmpc_end_reduce_nowait(ident_t *loc, kmp_int32 global_tid,
|
||||||
// kmp_critical_name *lck);
|
// kmp_critical_name *lck);
|
||||||
OMPRTL__kmpc_end_reduce_nowait,
|
OMPRTL__kmpc_end_reduce_nowait,
|
||||||
|
// Call to void __kmpc_ordered(ident_t *loc, kmp_int32 global_tid);
|
||||||
|
OMPRTL__kmpc_ordered,
|
||||||
|
// Call to void __kmpc_end_ordered(ident_t *loc, kmp_int32 global_tid);
|
||||||
|
OMPRTL__kmpc_end_ordered,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Values for bit flags used in the ident_t to describe the fields.
|
/// \brief Values for bit flags used in the ident_t to describe the fields.
|
||||||
|
@ -252,6 +256,10 @@ private:
|
||||||
/// size \a IVSize and sign \a IVSigned.
|
/// size \a IVSize and sign \a IVSigned.
|
||||||
llvm::Constant *createDispatchNextFunction(unsigned IVSize, bool IVSigned);
|
llvm::Constant *createDispatchNextFunction(unsigned IVSize, bool IVSigned);
|
||||||
|
|
||||||
|
/// \brief Returns __kmpc_dispatch_fini_* runtime function for the specified
|
||||||
|
/// size \a IVSize and sign \a IVSigned.
|
||||||
|
llvm::Constant *createDispatchFiniFunction(unsigned IVSize, bool IVSigned);
|
||||||
|
|
||||||
/// \brief If the specified mangled name is not in the module, create and
|
/// \brief If the specified mangled name is not in the module, create and
|
||||||
/// return threadprivate cache object. This object is a pointer's worth of
|
/// return threadprivate cache object. This object is a pointer's worth of
|
||||||
/// storage that's reserved for use by the OpenMP runtime.
|
/// storage that's reserved for use by the OpenMP runtime.
|
||||||
|
@ -378,6 +386,13 @@ public:
|
||||||
ArrayRef<const Expr *> SrcExprs,
|
ArrayRef<const Expr *> SrcExprs,
|
||||||
ArrayRef<const Expr *> AssignmentOps);
|
ArrayRef<const Expr *> AssignmentOps);
|
||||||
|
|
||||||
|
/// \brief Emit an ordered region.
|
||||||
|
/// \param OrderedOpGen Generator for the statement associated with the given
|
||||||
|
/// critical region.
|
||||||
|
virtual void emitOrderedRegion(CodeGenFunction &CGF,
|
||||||
|
const RegionCodeGenTy &OrderedOpGen,
|
||||||
|
SourceLocation Loc);
|
||||||
|
|
||||||
/// \brief Emit an implicit/explicit barrier for OpenMP threads.
|
/// \brief Emit an implicit/explicit barrier for OpenMP threads.
|
||||||
/// \param Kind Directive for which this implicit barrier call must be
|
/// \param Kind Directive for which this implicit barrier call must be
|
||||||
/// generated. Must be OMPD_barrier for explicit barrier generation.
|
/// generated. Must be OMPD_barrier for explicit barrier generation.
|
||||||
|
@ -428,15 +443,26 @@ public:
|
||||||
llvm::Value *UB, llvm::Value *ST,
|
llvm::Value *UB, llvm::Value *ST,
|
||||||
llvm::Value *Chunk = nullptr);
|
llvm::Value *Chunk = nullptr);
|
||||||
|
|
||||||
|
/// \brief Call the appropriate runtime routine to notify that we finished
|
||||||
|
/// iteration of the ordered loop with the dynamic scheduling.
|
||||||
|
///
|
||||||
|
/// \param CGF Reference to current CodeGenFunction.
|
||||||
|
/// \param Loc Clang source location.
|
||||||
|
/// \param IVSize Size of the iteration variable in bits.
|
||||||
|
/// \param IVSigned Sign of the interation variable.
|
||||||
|
///
|
||||||
|
virtual void emitForOrderedDynamicIterationEnd(CodeGenFunction &CGF,
|
||||||
|
SourceLocation Loc,
|
||||||
|
unsigned IVSize,
|
||||||
|
bool IVSigned);
|
||||||
|
|
||||||
/// \brief Call the appropriate runtime routine to notify that we finished
|
/// \brief Call the appropriate runtime routine to notify that we finished
|
||||||
/// all the work with current loop.
|
/// all the work with current loop.
|
||||||
///
|
///
|
||||||
/// \param CGF Reference to current CodeGenFunction.
|
/// \param CGF Reference to current CodeGenFunction.
|
||||||
/// \param Loc Clang source location.
|
/// \param Loc Clang source location.
|
||||||
/// \param ScheduleKind Schedule kind, specified by the 'schedule' clause.
|
|
||||||
///
|
///
|
||||||
virtual void emitForFinish(CodeGenFunction &CGF, SourceLocation Loc,
|
virtual void emitForStaticFinish(CodeGenFunction &CGF, SourceLocation Loc);
|
||||||
OpenMPScheduleClauseKind ScheduleKind);
|
|
||||||
|
|
||||||
/// Call __kmpc_dispatch_next(
|
/// Call __kmpc_dispatch_next(
|
||||||
/// ident_t *loc, kmp_int32 tid, kmp_int32 *p_lastiter,
|
/// ident_t *loc, kmp_int32 tid, kmp_int32 *p_lastiter,
|
||||||
|
|
|
@ -576,7 +576,8 @@ void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &S,
|
||||||
void CodeGenFunction::EmitOMPInnerLoop(
|
void CodeGenFunction::EmitOMPInnerLoop(
|
||||||
const Stmt &S, bool RequiresCleanup, const Expr *LoopCond,
|
const Stmt &S, bool RequiresCleanup, const Expr *LoopCond,
|
||||||
const Expr *IncExpr,
|
const Expr *IncExpr,
|
||||||
const llvm::function_ref<void(CodeGenFunction &)> &BodyGen) {
|
const llvm::function_ref<void(CodeGenFunction &)> &BodyGen,
|
||||||
|
const llvm::function_ref<void(CodeGenFunction &)> &PostIncGen) {
|
||||||
auto LoopExit = getJumpDestInCurrentScope("omp.inner.for.end");
|
auto LoopExit = getJumpDestInCurrentScope("omp.inner.for.end");
|
||||||
auto Cnt = getPGORegionCounter(&S);
|
auto Cnt = getPGORegionCounter(&S);
|
||||||
|
|
||||||
|
@ -612,6 +613,7 @@ void CodeGenFunction::EmitOMPInnerLoop(
|
||||||
// Emit "IV = IV + 1" and a back-edge to the condition block.
|
// Emit "IV = IV + 1" and a back-edge to the condition block.
|
||||||
EmitBlock(Continue.getBlock());
|
EmitBlock(Continue.getBlock());
|
||||||
EmitIgnoredExpr(IncExpr);
|
EmitIgnoredExpr(IncExpr);
|
||||||
|
PostIncGen(*this);
|
||||||
BreakContinueStack.pop_back();
|
BreakContinueStack.pop_back();
|
||||||
EmitBranch(CondBlock);
|
EmitBranch(CondBlock);
|
||||||
LoopStack.pop();
|
LoopStack.pop();
|
||||||
|
@ -799,7 +801,8 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
|
||||||
[&S](CodeGenFunction &CGF) {
|
[&S](CodeGenFunction &CGF) {
|
||||||
CGF.EmitOMPLoopBody(S);
|
CGF.EmitOMPLoopBody(S);
|
||||||
CGF.EmitStopPoint(&S);
|
CGF.EmitStopPoint(&S);
|
||||||
});
|
},
|
||||||
|
[](CodeGenFunction &) {});
|
||||||
CGF.EmitOMPLoopBody(S, /* SeparateIter */ true);
|
CGF.EmitOMPLoopBody(S, /* SeparateIter */ true);
|
||||||
}
|
}
|
||||||
CGF.EmitOMPSimdFinal(S);
|
CGF.EmitOMPSimdFinal(S);
|
||||||
|
@ -818,7 +821,8 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
|
||||||
[&S](CodeGenFunction &CGF) {
|
[&S](CodeGenFunction &CGF) {
|
||||||
CGF.EmitOMPLoopBody(S);
|
CGF.EmitOMPLoopBody(S);
|
||||||
CGF.EmitStopPoint(&S);
|
CGF.EmitStopPoint(&S);
|
||||||
});
|
},
|
||||||
|
[](CodeGenFunction &) {});
|
||||||
}
|
}
|
||||||
CGF.EmitOMPSimdFinal(S);
|
CGF.EmitOMPSimdFinal(S);
|
||||||
}
|
}
|
||||||
|
@ -873,7 +877,9 @@ void CodeGenFunction::EmitOMPForOuterLoop(OpenMPScheduleClauseKind ScheduleKind,
|
||||||
//
|
//
|
||||||
// while(__kmpc_dispatch_next(&LB, &UB)) {
|
// while(__kmpc_dispatch_next(&LB, &UB)) {
|
||||||
// idx = LB;
|
// idx = LB;
|
||||||
// while (idx <= UB) { BODY; ++idx; } // inner loop
|
// while (idx <= UB) { BODY; ++idx;
|
||||||
|
// __kmpc_dispatch_fini_(4|8)[u](); // For ordered loops only.
|
||||||
|
// } // inner loop
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// OpenMP [2.7.1, Loop Construct, Description, table 2-1]
|
// OpenMP [2.7.1, Loop Construct, Description, table 2-1]
|
||||||
|
@ -940,12 +946,22 @@ void CodeGenFunction::EmitOMPForOuterLoop(OpenMPScheduleClauseKind ScheduleKind,
|
||||||
auto Continue = getJumpDestInCurrentScope("omp.dispatch.inc");
|
auto Continue = getJumpDestInCurrentScope("omp.dispatch.inc");
|
||||||
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
|
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
|
||||||
|
|
||||||
EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
|
bool DynamicWithOrderedClause =
|
||||||
S.getCond(/*SeparateIter=*/false), S.getInc(),
|
Dynamic && S.getSingleClause(OMPC_ordered) != nullptr;
|
||||||
[&S](CodeGenFunction &CGF) {
|
SourceLocation Loc = S.getLocStart();
|
||||||
CGF.EmitOMPLoopBody(S);
|
EmitOMPInnerLoop(
|
||||||
CGF.EmitStopPoint(&S);
|
S, LoopScope.requiresCleanups(), S.getCond(/*SeparateIter=*/false),
|
||||||
});
|
S.getInc(),
|
||||||
|
[&S](CodeGenFunction &CGF) {
|
||||||
|
CGF.EmitOMPLoopBody(S);
|
||||||
|
CGF.EmitStopPoint(&S);
|
||||||
|
},
|
||||||
|
[DynamicWithOrderedClause, IVSize, IVSigned, Loc](CodeGenFunction &CGF) {
|
||||||
|
if (DynamicWithOrderedClause) {
|
||||||
|
CGF.CGM.getOpenMPRuntime().emitForOrderedDynamicIterationEnd(
|
||||||
|
CGF, Loc, IVSize, IVSigned);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
EmitBlock(Continue.getBlock());
|
EmitBlock(Continue.getBlock());
|
||||||
BreakContinueStack.pop_back();
|
BreakContinueStack.pop_back();
|
||||||
|
@ -961,9 +977,8 @@ void CodeGenFunction::EmitOMPForOuterLoop(OpenMPScheduleClauseKind ScheduleKind,
|
||||||
EmitBlock(LoopExit.getBlock());
|
EmitBlock(LoopExit.getBlock());
|
||||||
|
|
||||||
// Tell the runtime we are done.
|
// Tell the runtime we are done.
|
||||||
// FIXME: Also call fini for ordered loops with dynamic scheduling.
|
|
||||||
if (!Dynamic)
|
if (!Dynamic)
|
||||||
RT.emitForFinish(*this, S.getLocStart(), ScheduleKind);
|
RT.emitForStaticFinish(*this, S.getLocEnd());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Emit a helper variable and return corresponding lvalue.
|
/// \brief Emit a helper variable and return corresponding lvalue.
|
||||||
|
@ -1058,9 +1073,10 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
|
||||||
[&S](CodeGenFunction &CGF) {
|
[&S](CodeGenFunction &CGF) {
|
||||||
CGF.EmitOMPLoopBody(S);
|
CGF.EmitOMPLoopBody(S);
|
||||||
CGF.EmitStopPoint(&S);
|
CGF.EmitStopPoint(&S);
|
||||||
});
|
},
|
||||||
|
[](CodeGenFunction &) {});
|
||||||
// Tell the runtime we are done.
|
// Tell the runtime we are done.
|
||||||
RT.emitForFinish(*this, S.getLocStart(), ScheduleKind);
|
RT.emitForStaticFinish(*this, S.getLocStart());
|
||||||
} else {
|
} else {
|
||||||
// Emit the outer loop, which requests its work chunk [LB..UB] from
|
// Emit the outer loop, which requests its work chunk [LB..UB] from
|
||||||
// runtime and runs the inner loop to process it.
|
// runtime and runs the inner loop to process it.
|
||||||
|
@ -1177,10 +1193,10 @@ static OpenMPDirectiveKind emitSections(CodeGenFunction &CGF,
|
||||||
// IV = LB;
|
// IV = LB;
|
||||||
CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getLocStart()), IV);
|
CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getLocStart()), IV);
|
||||||
// while (idx <= UB) { BODY; ++idx; }
|
// while (idx <= UB) { BODY; ++idx; }
|
||||||
CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, &Cond, &Inc, BodyGen);
|
CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, &Cond, &Inc, BodyGen,
|
||||||
|
[](CodeGenFunction &) {});
|
||||||
// Tell the runtime we are done.
|
// Tell the runtime we are done.
|
||||||
CGF.CGM.getOpenMPRuntime().emitForFinish(CGF, S.getLocStart(),
|
CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocStart());
|
||||||
OMPC_SCHEDULE_static);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, CodeGen);
|
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, CodeGen);
|
||||||
|
@ -1372,8 +1388,13 @@ void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &S) {
|
||||||
}(), S.getLocStart());
|
}(), S.getLocStart());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &) {
|
void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &S) {
|
||||||
llvm_unreachable("CodeGen for 'omp ordered' is not supported yet.");
|
LexicalScope Scope(*this, S.getSourceRange());
|
||||||
|
auto &&CodeGen = [&S](CodeGenFunction &CGF) {
|
||||||
|
CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
|
||||||
|
CGF.EnsureInsertPoint();
|
||||||
|
};
|
||||||
|
CGM.getOpenMPRuntime().emitOrderedRegion(*this, CodeGen, S.getLocStart());
|
||||||
}
|
}
|
||||||
|
|
||||||
static llvm::Value *convertToScalarValue(CodeGenFunction &CGF, RValue Val,
|
static llvm::Value *convertToScalarValue(CodeGenFunction &CGF, RValue Val,
|
||||||
|
|
|
@ -2139,10 +2139,21 @@ public:
|
||||||
void EmitOMPTargetDirective(const OMPTargetDirective &S);
|
void EmitOMPTargetDirective(const OMPTargetDirective &S);
|
||||||
void EmitOMPTeamsDirective(const OMPTeamsDirective &S);
|
void EmitOMPTeamsDirective(const OMPTeamsDirective &S);
|
||||||
|
|
||||||
void
|
/// \brief Emit inner loop of the worksharing/simd construct.
|
||||||
EmitOMPInnerLoop(const Stmt &S, bool RequiresCleanup, const Expr *LoopCond,
|
///
|
||||||
const Expr *IncExpr,
|
/// \param S Directive, for which the inner loop must be emitted.
|
||||||
const llvm::function_ref<void(CodeGenFunction &)> &BodyGen);
|
/// \param RequiresCleanup true, if directive has some associated private
|
||||||
|
/// variables.
|
||||||
|
/// \param LoopCond Bollean condition for loop continuation.
|
||||||
|
/// \param IncExpr Increment expression for loop control variable.
|
||||||
|
/// \param BodyGen Generator for the inner body of the inner loop.
|
||||||
|
/// \param PostIncGen Genrator for post-increment code (required for ordered
|
||||||
|
/// loop directvies).
|
||||||
|
void EmitOMPInnerLoop(
|
||||||
|
const Stmt &S, bool RequiresCleanup, const Expr *LoopCond,
|
||||||
|
const Expr *IncExpr,
|
||||||
|
const llvm::function_ref<void(CodeGenFunction &)> &BodyGen,
|
||||||
|
const llvm::function_ref<void(CodeGenFunction &)> &PostIncGen);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
|
||||||
|
// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
|
||||||
|
// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
|
||||||
|
//
|
||||||
|
// expected-no-diagnostics
|
||||||
|
#ifndef HEADER
|
||||||
|
#define HEADER
|
||||||
|
|
||||||
|
// CHECK: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
|
||||||
|
// CHECK: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
|
||||||
|
// CHECK-LABEL: define {{.*void}} @{{.*}}static_not_chunked{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
|
||||||
|
void static_not_chunked(float *a, float *b, float *c, float *d) {
|
||||||
|
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]])
|
||||||
|
#pragma omp for schedule(static) ordered
|
||||||
|
// CHECK: call void @__kmpc_for_static_init_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 34, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 1)
|
||||||
|
// UB = min(UB, GlobalUB)
|
||||||
|
// CHECK-NEXT: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
|
||||||
|
// CHECK-NEXT: [[UBCMP:%.+]] = icmp sgt i32 [[UB]], 4571423
|
||||||
|
// CHECK-NEXT: br i1 [[UBCMP]], label [[UB_TRUE:%[^,]+]], label [[UB_FALSE:%[^,]+]]
|
||||||
|
// CHECK: [[UBRESULT:%.+]] = phi i32 [ 4571423, [[UB_TRUE]] ], [ [[UBVAL:%[^,]+]], [[UB_FALSE]] ]
|
||||||
|
// CHECK-NEXT: store i32 [[UBRESULT]], i32* [[OMP_UB]]
|
||||||
|
// CHECK-NEXT: [[LB:%.+]] = load i32, i32* [[OMP_LB]]
|
||||||
|
// CHECK-NEXT: store i32 [[LB]], i32* [[OMP_IV:[^,]+]]
|
||||||
|
// Loop header
|
||||||
|
// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]]
|
||||||
|
// CHECK-NEXT: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
|
||||||
|
// CHECK-NEXT: [[CMP:%.+]] = icmp sle i32 [[IV]], [[UB]]
|
||||||
|
// CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1_BODY:[^,]+]], label %[[LOOP1_END:[^,]+]]
|
||||||
|
for (int i = 32000000; i > 33; i += -7) {
|
||||||
|
// CHECK: [[LOOP1_BODY]]
|
||||||
|
// Start of body: calculate i from IV:
|
||||||
|
// CHECK: [[IV1_1:%.+]] = load i32, i32* [[OMP_IV]]
|
||||||
|
// CHECK-NEXT: [[CALC_I_1:%.+]] = mul nsw i32 [[IV1_1]], 7
|
||||||
|
// CHECK-NEXT: [[CALC_I_2:%.+]] = sub nsw i32 32000000, [[CALC_I_1]]
|
||||||
|
// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]]
|
||||||
|
|
||||||
|
// ... start of ordered region ...
|
||||||
|
// CHECK-NEXT: call void @__kmpc_ordered([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||||
|
// ... loop body ...
|
||||||
|
// End of body: store into a[i]:
|
||||||
|
// CHECK: store float [[RESULT:%.+]], float* {{%.+}}
|
||||||
|
// CHECK-NEXT: call void @__kmpc_end_ordered([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||||
|
// ... end of ordered region ...
|
||||||
|
#pragma omp ordered
|
||||||
|
a[i] = b[i] * c[i] * d[i];
|
||||||
|
// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]]{{.*}}
|
||||||
|
// CHECK-NEXT: [[ADD1_2:%.+]] = add nsw i32 [[IV1_2]], 1
|
||||||
|
// CHECK-NEXT: store i32 [[ADD1_2]], i32* [[OMP_IV]]
|
||||||
|
// CHECK-NEXT: br label %{{.+}}
|
||||||
|
}
|
||||||
|
// CHECK: [[LOOP1_END]]
|
||||||
|
// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||||
|
// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
|
||||||
|
// CHECK: ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: define {{.*void}} @{{.*}}dynamic1{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
|
||||||
|
void dynamic1(float *a, float *b, float *c, float *d) {
|
||||||
|
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]])
|
||||||
|
#pragma omp for schedule(dynamic) ordered
|
||||||
|
// CHECK: call void @__kmpc_dispatch_init_8u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 35, i64 0, i64 16908287, i64 1, i64 1)
|
||||||
|
//
|
||||||
|
// CHECK: [[HASWORK:%.+]] = call i32 @__kmpc_dispatch_next_8u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32* [[OMP_ISLAST:%[^,]+]], i64* [[OMP_LB:%[^,]+]], i64* [[OMP_UB:%[^,]+]], i64* [[OMP_ST:%[^,]+]])
|
||||||
|
// CHECK-NEXT: [[O_CMP:%.+]] = icmp ne i32 [[HASWORK]], 0
|
||||||
|
// CHECK-NEXT: br i1 [[O_CMP]], label %[[O_LOOP1_BODY:[^,]+]], label %[[O_LOOP1_END:[^,]+]]
|
||||||
|
|
||||||
|
// Loop header
|
||||||
|
// CHECK: [[O_LOOP1_BODY]]
|
||||||
|
// CHECK: [[LB:%.+]] = load i64, i64* [[OMP_LB]]
|
||||||
|
// CHECK-NEXT: store i64 [[LB]], i64* [[OMP_IV:[^,]+]]
|
||||||
|
// CHECK: [[IV:%.+]] = load i64, i64* [[OMP_IV]]
|
||||||
|
|
||||||
|
// CHECK-NEXT: [[UB:%.+]] = load i64, i64* [[OMP_UB]]
|
||||||
|
// CHECK-NEXT: [[CMP:%.+]] = icmp ule i64 [[IV]], [[UB]]
|
||||||
|
// CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1_BODY:[^,]+]], label %[[LOOP1_END:[^,]+]]
|
||||||
|
for (unsigned long long i = 131071; i < 2147483647; i += 127) {
|
||||||
|
// CHECK: [[LOOP1_BODY]]
|
||||||
|
// Start of body: calculate i from IV:
|
||||||
|
// CHECK: [[IV1_1:%.+]] = load i64, i64* [[OMP_IV]]
|
||||||
|
// CHECK-NEXT: [[CALC_I_1:%.+]] = mul i64 [[IV1_1]], 127
|
||||||
|
// CHECK-NEXT: [[CALC_I_2:%.+]] = add i64 131071, [[CALC_I_1]]
|
||||||
|
// CHECK-NEXT: store i64 [[CALC_I_2]], i64* [[LC_I:.+]]
|
||||||
|
|
||||||
|
// ... start of ordered region ...
|
||||||
|
// CHECK-NEXT: call void @__kmpc_ordered([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||||
|
// ... loop body ...
|
||||||
|
// End of body: store into a[i]:
|
||||||
|
// CHECK: store float [[RESULT:%.+]], float* {{%.+}}
|
||||||
|
// CHECK-NEXT: call void @__kmpc_end_ordered([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||||
|
// ... end of ordered region ...
|
||||||
|
#pragma omp ordered
|
||||||
|
a[i] = b[i] * c[i] * d[i];
|
||||||
|
// CHECK: [[IV1_2:%.+]] = load i64, i64* [[OMP_IV]]{{.*}}
|
||||||
|
// CHECK-NEXT: [[ADD1_2:%.+]] = add i64 [[IV1_2]], 1
|
||||||
|
// CHECK-NEXT: store i64 [[ADD1_2]], i64* [[OMP_IV]]
|
||||||
|
|
||||||
|
// ... end iteration for ordered loop ...
|
||||||
|
// CHECK-NEXT: call void @__kmpc_dispatch_fini_8u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||||
|
// CHECK-NEXT: br label %{{.+}}
|
||||||
|
}
|
||||||
|
// CHECK: [[LOOP1_END]]
|
||||||
|
// CHECK: [[O_LOOP1_END]]
|
||||||
|
// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
|
||||||
|
// CHECK: ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: define {{.*void}} @{{.*}}test_auto{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
|
||||||
|
void test_auto(float *a, float *b, float *c, float *d) {
|
||||||
|
unsigned int x = 0;
|
||||||
|
unsigned int y = 0;
|
||||||
|
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]])
|
||||||
|
#pragma omp for schedule(auto) collapse(2) ordered
|
||||||
|
// CHECK: call void @__kmpc_dispatch_init_8([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 38, i64 0, i64 [[LAST_ITER:%[^,]+]], i64 1, i64 1)
|
||||||
|
//
|
||||||
|
// CHECK: [[HASWORK:%.+]] = call i32 @__kmpc_dispatch_next_8([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32* [[OMP_ISLAST:%[^,]+]], i64* [[OMP_LB:%[^,]+]], i64* [[OMP_UB:%[^,]+]], i64* [[OMP_ST:%[^,]+]])
|
||||||
|
// CHECK-NEXT: [[O_CMP:%.+]] = icmp ne i32 [[HASWORK]], 0
|
||||||
|
// CHECK-NEXT: br i1 [[O_CMP]], label %[[O_LOOP1_BODY:[^,]+]], label %[[O_LOOP1_END:[^,]+]]
|
||||||
|
|
||||||
|
// Loop header
|
||||||
|
// CHECK: [[O_LOOP1_BODY]]
|
||||||
|
// CHECK: [[LB:%.+]] = load i64, i64* [[OMP_LB]]
|
||||||
|
// CHECK-NEXT: store i64 [[LB]], i64* [[OMP_IV:[^,]+]]
|
||||||
|
// CHECK: [[IV:%.+]] = load i64, i64* [[OMP_IV]]
|
||||||
|
|
||||||
|
// CHECK-NEXT: [[UB:%.+]] = load i64, i64* [[OMP_UB]]
|
||||||
|
// CHECK-NEXT: [[CMP:%.+]] = icmp sle i64 [[IV]], [[UB]]
|
||||||
|
// CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1_BODY:[^,]+]], label %[[LOOP1_END:[^,]+]]
|
||||||
|
// FIXME: When the iteration count of some nested loop is not a known constant,
|
||||||
|
// we should pre-calculate it, like we do for the total number of iterations!
|
||||||
|
for (char i = static_cast<char>(y); i <= '9'; ++i)
|
||||||
|
for (x = 11; x > 0; --x) {
|
||||||
|
// CHECK: [[LOOP1_BODY]]
|
||||||
|
// Start of body: indices are calculated from IV:
|
||||||
|
// CHECK: store i8 {{%[^,]+}}, i8* {{%[^,]+}}
|
||||||
|
// CHECK: store i32 {{%[^,]+}}, i32* {{%[^,]+}}
|
||||||
|
|
||||||
|
// ... start of ordered region ...
|
||||||
|
// CHECK: call void @__kmpc_ordered([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||||
|
// ... loop body ...
|
||||||
|
// End of body: store into a[i]:
|
||||||
|
// CHECK: store float [[RESULT:%.+]], float* {{%.+}}
|
||||||
|
// CHECK-NEXT: call void @__kmpc_end_ordered([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||||
|
// ... end of ordered region ...
|
||||||
|
#pragma omp ordered
|
||||||
|
a[i] = b[i] * c[i] * d[i];
|
||||||
|
// CHECK: [[IV1_2:%.+]] = load i64, i64* [[OMP_IV]]{{.*}}
|
||||||
|
// CHECK-NEXT: [[ADD1_2:%.+]] = add nsw i64 [[IV1_2]], 1
|
||||||
|
// CHECK-NEXT: store i64 [[ADD1_2]], i64* [[OMP_IV]]
|
||||||
|
|
||||||
|
// ... end iteration for ordered loop ...
|
||||||
|
// CHECK-NEXT: call void @__kmpc_dispatch_fini_8([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||||
|
// CHECK-NEXT: br label %{{.+}}
|
||||||
|
}
|
||||||
|
// CHECK: [[LOOP1_END]]
|
||||||
|
// CHECK: [[O_LOOP1_END]]
|
||||||
|
// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
|
||||||
|
// CHECK: ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: define {{.*void}} @{{.*}}runtime{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
|
||||||
|
void runtime(float *a, float *b, float *c, float *d) {
|
||||||
|
int x = 0;
|
||||||
|
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]])
|
||||||
|
#pragma omp for collapse(2) schedule(runtime) ordered
|
||||||
|
// CHECK: call void @__kmpc_dispatch_init_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 37, i32 0, i32 199, i32 1, i32 1)
|
||||||
|
//
|
||||||
|
// CHECK: [[HASWORK:%.+]] = call i32 @__kmpc_dispatch_next_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32* [[OMP_ISLAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]])
|
||||||
|
// CHECK-NEXT: [[O_CMP:%.+]] = icmp ne i32 [[HASWORK]], 0
|
||||||
|
// CHECK-NEXT: br i1 [[O_CMP]], label %[[O_LOOP1_BODY:[^,]+]], label %[[O_LOOP1_END:[^,]+]]
|
||||||
|
|
||||||
|
// Loop header
|
||||||
|
// CHECK: [[O_LOOP1_BODY]]
|
||||||
|
// CHECK: [[LB:%.+]] = load i32, i32* [[OMP_LB]]
|
||||||
|
// CHECK-NEXT: store i32 [[LB]], i32* [[OMP_IV:[^,]+]]
|
||||||
|
// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]]
|
||||||
|
|
||||||
|
// CHECK-NEXT: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
|
||||||
|
// CHECK-NEXT: [[CMP:%.+]] = icmp sle i32 [[IV]], [[UB]]
|
||||||
|
// CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1_BODY:[^,]+]], label %[[LOOP1_END:[^,]+]]
|
||||||
|
for (unsigned char i = '0' ; i <= '9'; ++i)
|
||||||
|
for (x = -10; x < 10; ++x) {
|
||||||
|
// CHECK: [[LOOP1_BODY]]
|
||||||
|
// Start of body: indices are calculated from IV:
|
||||||
|
// CHECK: store i8 {{%[^,]+}}, i8* {{%[^,]+}}
|
||||||
|
// CHECK: store i32 {{%[^,]+}}, i32* {{%[^,]+}}
|
||||||
|
|
||||||
|
// ... start of ordered region ...
|
||||||
|
// CHECK: call void @__kmpc_ordered([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||||
|
// ... loop body ...
|
||||||
|
// End of body: store into a[i]:
|
||||||
|
// CHECK: store float [[RESULT:%.+]], float* {{%.+}}
|
||||||
|
// CHECK-NEXT: call void @__kmpc_end_ordered([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||||
|
// ... end of ordered region ...
|
||||||
|
#pragma omp ordered
|
||||||
|
a[i] = b[i] * c[i] * d[i];
|
||||||
|
// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]]{{.*}}
|
||||||
|
// CHECK-NEXT: [[ADD1_2:%.+]] = add nsw i32 [[IV1_2]], 1
|
||||||
|
// CHECK-NEXT: store i32 [[ADD1_2]], i32* [[OMP_IV]]
|
||||||
|
|
||||||
|
// ... end iteration for ordered loop ...
|
||||||
|
// CHECK-NEXT: call void @__kmpc_dispatch_fini_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||||
|
// CHECK-NEXT: br label %{{.+}}
|
||||||
|
}
|
||||||
|
// CHECK: [[LOOP1_END]]
|
||||||
|
// CHECK: [[O_LOOP1_END]]
|
||||||
|
// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
|
||||||
|
// CHECK: ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // HEADER
|
||||||
|
|
Loading…
Reference in New Issue