diff --git a/clang/docs/OpenMPSupport.rst b/clang/docs/OpenMPSupport.rst index f39987caf5c43..ca2a878be0091 100644 --- a/clang/docs/OpenMPSupport.rst +++ b/clang/docs/OpenMPSupport.rst @@ -316,6 +316,8 @@ implementation. +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | misc | dispatch construct and function variant argument adjustment | :part:`worked on` | D99537, D99679 | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ +| misc | dispatch construct | :part:`worked on` | | ++------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | misc | assumes directives | :part:`worked on` | | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | misc | assume directive | :good:`done` | | diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5b702b56038f7..b2d37752266ab 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -616,6 +616,7 @@ Python Binding Changes OpenMP Support -------------- +- Added support for 'omp dispatch' directive. - Added support 'no_openmp_constructs' assumption clause. - Added support for 'self_maps' in map and requirement clause. - Added support for 'omp stripe' directive. diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h index 6ca9f9c550285..f6eb0a02b4227 100644 --- a/clang/include/clang/Basic/OpenMPKinds.h +++ b/clang/include/clang/Basic/OpenMPKinds.h @@ -280,6 +280,12 @@ bool isOpenMPTaskLoopDirective(OpenMPDirectiveKind DKind); /// parallel', otherwise - false. bool isOpenMPParallelDirective(OpenMPDirectiveKind DKind); +/// Checks if the specified directive is a dispatch-kind directive. +/// \param DKind Specified directive. +/// \return true - the directive is a dispatch-like directive like 'omp +/// dispatch', otherwise - false. +bool isOpenMPDispatchDirective(OpenMPDirectiveKind DKind); + /// Checks if the specified directive is a target code offload directive. /// \param DKind Specified directive. /// \return true - the directive is a target code offload directive like diff --git a/clang/include/clang/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h index 6498390fe96f7..50f61a169b7b9 100644 --- a/clang/include/clang/Sema/SemaOpenMP.h +++ b/clang/include/clang/Sema/SemaOpenMP.h @@ -1498,6 +1498,10 @@ class SemaOpenMP : public SemaBase { : OMPDeclareVariantScopes.back().TI; } + void annotateAStmt(const ASTContext &Context, Stmt *StmtP, + SemaOpenMP *SemaPtr, ArrayRef &Clauses, + SourceLocation StartLoc); + /// The current `omp begin/end declare variant` scopes. SmallVector OMPDeclareVariantScopes; diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 09921e3b1edfc..7f98d51622e26 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -623,6 +623,11 @@ bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) { llvm::is_contained(getLeafConstructs(DKind), OMPD_parallel); } +bool clang::isOpenMPDispatchDirective(OpenMPDirectiveKind DKind) { + return DKind == OMPD_dispatch || + llvm::is_contained(getLeafConstructs(DKind), OMPD_dispatch); +} + bool clang::isOpenMPTargetExecutionDirective(OpenMPDirectiveKind DKind) { return DKind == OMPD_target || llvm::is_contained(getLeafConstructs(DKind), OMPD_target); @@ -796,6 +801,10 @@ void clang::getOpenMPCaptureRegions( CaptureRegions.push_back(OMPD_task); CaptureRegions.push_back(OMPD_target); break; + case OMPD_dispatch: + CaptureRegions.push_back(OMPD_task); + CaptureRegions.push_back(OMPD_dispatch); + break; case OMPD_task: case OMPD_target_enter_data: case OMPD_target_exit_data: @@ -819,7 +828,6 @@ void clang::getOpenMPCaptureRegions( else return true; break; - case OMPD_dispatch: case OMPD_distribute: case OMPD_for: case OMPD_ordered: diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 3562b4ea22a24..069a44d73e972 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -424,7 +424,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef Attrs) { EmitOMPInteropDirective(cast(*S)); break; case Stmt::OMPDispatchDirectiveClass: - CGM.ErrorUnsupported(S, "OpenMP dispatch directive"); + EmitOMPDispatchDirective(cast(*S)); break; case Stmt::OMPScopeDirectiveClass: EmitOMPScopeDirective(cast(*S)); diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 156f64bb5f508..d35547049d408 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -4529,6 +4529,189 @@ void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) { emitMaster(*this, S); } +static Expr *replaceWithNewTraitsOrDirectCall(CapturedDecl *CDecl, + Expr *NewExpr) { + Expr *CurrentCallExpr = nullptr; + Stmt *CallExprStmt = CDecl->getBody(); + + if (BinaryOperator *BinaryCopyOpr = dyn_cast(CallExprStmt)) { + CurrentCallExpr = BinaryCopyOpr->getRHS(); + BinaryCopyOpr->setRHS(NewExpr); + } else { + CurrentCallExpr = dyn_cast(CallExprStmt); + CDecl->setBody(NewExpr); + } + + return CurrentCallExpr; +} + +static Expr *transformCallInStmt(Stmt *StmtP, bool NoContext = false) { + Expr *CurrentExpr = nullptr; + if (auto *CptStmt = dyn_cast(StmtP)) { + CapturedDecl *CDecl = CptStmt->getCapturedDecl(); + + CallExpr *NewCallExpr = nullptr; + for (const auto *attr : CDecl->attrs()) { + if (NoContext) { + if (const auto *annotateAttr = + llvm::dyn_cast(attr); + annotateAttr && annotateAttr->getAnnotation() == "NoContextAttr") { + NewCallExpr = llvm::dyn_cast(*annotateAttr->args_begin()); + } + } else { + if (const auto *annotateAttr = + llvm::dyn_cast(attr); + annotateAttr && annotateAttr->getAnnotation() == "NoVariantsAttr") { + NewCallExpr = llvm::dyn_cast(*annotateAttr->args_begin()); + } + } + } + + CurrentExpr = replaceWithNewTraitsOrDirectCall(CDecl, NewCallExpr); + } + return CurrentExpr; +} + +// emitIfElse is used for the following conditions: +// +// NoVariants = 0 && NoContext = 1 +// if (Condition_NoContext) { +// foo_variant2(); // Present in AnnotationAttr +// } else { +// foo_variant(); +// } +// +// NoVariants = 1 && NoContext = 0 +// if (Condition_NoVariants) { +// foo(); +// } else { +// foo_variant(); +// } +// +// NoVariants = 1 && NoContext = 1 +// if (Condition_NoVariants) { // ==> label if.then.NoVariants +// foo(); +// } else { // ==> label else.NoVariants +// if (Condition_NoContext) { // ==> label if.then.NoContext +// foo_variant2(); // Present in AnnotationAttr +// } else { // ==> label else +// foo_variant(); +// } +// } +// +static void emitIfElse(CodeGenFunction *CGF, Stmt *AssociatedStmt, + Expr *Condition_NoVariants, Expr *Condition_NoContext) { + llvm::BasicBlock *ThenBlock = CGF->createBasicBlock("if.then"); + llvm::BasicBlock *ElseBlock = CGF->createBasicBlock("if.else"); + llvm::BasicBlock *MergeBlock = CGF->createBasicBlock("if.end"); + llvm::BasicBlock *ThenNoVariantsBlock = nullptr; + llvm::BasicBlock *ElseNoVariantsBlock = nullptr; + llvm::BasicBlock *ThenNoContextBlock = nullptr; + Expr *ElseCall = nullptr; + + if (Condition_NoVariants && Condition_NoContext) { + ThenNoVariantsBlock = CGF->createBasicBlock("if.then.NoVariants"); + ElseNoVariantsBlock = CGF->createBasicBlock("else.NoVariants"); + ThenNoContextBlock = CGF->createBasicBlock("if.then.NoContext"); + + CGF->EmitBranchOnBoolExpr(Condition_NoVariants, ThenNoVariantsBlock, + ElseNoVariantsBlock, 0); + + } else if (Condition_NoVariants) { + CGF->EmitBranchOnBoolExpr(Condition_NoVariants, ThenBlock, ElseBlock, 0); + } else { + CGF->EmitBranchOnBoolExpr(Condition_NoContext, ThenBlock, ElseBlock, 0); + } + + if (Condition_NoVariants && Condition_NoContext) { + // Emit the NoVariants (if then, for the NoVariants) block. + CGF->EmitBlock(ThenNoVariantsBlock); + Stmt *ThenStmt = AssociatedStmt; + ElseCall = transformCallInStmt(ThenStmt, false); + CGF->EmitStmt(ThenStmt); + CGF->Builder.CreateBr(MergeBlock); + + CGF->EmitBlock(ElseNoVariantsBlock); + CGF->EmitBranchOnBoolExpr(Condition_NoVariants, ThenNoContextBlock, + ElseBlock, 0); + // Emit the NoContext (else if, for the NoContext) block. + CGF->EmitBlock(ThenNoContextBlock); + Stmt *ThenNoContextStmt = AssociatedStmt; + transformCallInStmt(ThenNoContextStmt, true); + CGF->EmitStmt(ThenNoContextStmt); + CGF->Builder.CreateBr(MergeBlock); + + } else { + bool CNoVariantsOrCNoContext = false; + if (Condition_NoContext) { + CNoVariantsOrCNoContext = true; + } + + CGF->EmitBlock(ThenBlock); + Stmt *ThenStmt = AssociatedStmt; + ElseCall = transformCallInStmt(ThenStmt, CNoVariantsOrCNoContext); + CGF->EmitStmt(ThenStmt); + CGF->Builder.CreateBr(MergeBlock); + } + + // Emit the else block. + CGF->EmitBlock(ElseBlock); + Stmt *ElseStmt = AssociatedStmt; + if (auto *CaptStmt = dyn_cast(ElseStmt)) { + CapturedDecl *CDecl = CaptStmt->getCapturedDecl(); + replaceWithNewTraitsOrDirectCall(CDecl, ElseCall); + } + CGF->EmitStmt(ElseStmt); + CGF->Builder.CreateBr(MergeBlock); + + CGF->EmitBlock(MergeBlock); +} + +void CodeGenFunction::EmitOMPDispatchDirective(const OMPDispatchDirective &S) { + ArrayRef Clauses = S.clauses(); + + Stmt *AssociatedStmt = const_cast(S.getAssociatedStmt()); + if (auto *AssocStmt = dyn_cast(AssociatedStmt)) { + if (auto *InnerCapturedStmt = + dyn_cast(AssocStmt->getCapturedStmt())) + AssociatedStmt = InnerCapturedStmt; + } + CodeGenFunction::CGCapturedStmtInfo CapStmtInfo; + if (!CapturedStmtInfo) + CapturedStmtInfo = &CapStmtInfo; + + Expr *NoVariantsCondition = nullptr; + Expr *NoContextCondition = nullptr; + if (!Clauses.empty()) { + if (S.hasClausesOfKind()) + EmitOMPDispatchToTaskwaitDirective(S); + + if (S.hasClausesOfKind() || + S.hasClausesOfKind()) { + if (const OMPNovariantsClause *NoVariantsC = + OMPExecutableDirective::getSingleClause( + Clauses)) { + NoVariantsCondition = NoVariantsC->getCondition(); + if (const OMPNocontextClause *NoContextC = + OMPExecutableDirective::getSingleClause( + Clauses)) { + NoContextCondition = NoContextC->getCondition(); + } + } else { + const OMPNocontextClause *NoContextC = + OMPExecutableDirective::getSingleClause( + Clauses); + NoContextCondition = NoContextC->getCondition(); + } + + OMPLexicalScope Scope(*this, S, OMPD_dispatch); + emitIfElse(this, AssociatedStmt, NoVariantsCondition, NoContextCondition); + } + } else { + EmitStmt(AssociatedStmt); + } +} + static void emitMasked(CodeGenFunction &CGF, const OMPExecutableDirective &S) { auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { Action.Enter(CGF); @@ -5549,6 +5732,15 @@ void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &S) { CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_barrier); } +void CodeGenFunction::EmitOMPDispatchToTaskwaitDirective( + const OMPDispatchDirective &S) { + OMPTaskDataTy Data; + // Build list of dependences + buildDependences(S, Data); + Data.HasNowaitClause = S.hasClausesOfKind(); + CGM.getOpenMPRuntime().emitTaskwaitCall(*this, S.getBeginLoc(), Data); +} + void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S) { OMPTaskDataTy Data; // Build list of dependences diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 2b1062d6d307c..92d43fdeedd66 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3663,6 +3663,8 @@ class CodeGenFunction : public CodeGenTypeCache { void EmitCXXForRangeStmt(const CXXForRangeStmt &S, ArrayRef Attrs = {}); + void EmitOMPDispatchToTaskwaitDirective(const OMPDispatchDirective &S); + /// Controls insertion of cancellation exit blocks in worksharing constructs. class OMPCancelStackRAII { CodeGenFunction &CGF; @@ -3855,6 +3857,7 @@ class CodeGenFunction : public CodeGenTypeCache { void EmitOMPSectionDirective(const OMPSectionDirective &S); void EmitOMPSingleDirective(const OMPSingleDirective &S); void EmitOMPMasterDirective(const OMPMasterDirective &S); + void EmitOMPDispatchDirective(const OMPDispatchDirective &S); void EmitOMPMaskedDirective(const OMPMaskedDirective &S); void EmitOMPCriticalDirective(const OMPCriticalDirective &S); void EmitOMPParallelForDirective(const OMPParallelForDirective &S); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index a382947455aef..f1354b5f8535f 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -4205,6 +4205,8 @@ static void handleDeclareVariantConstructTrait(DSAStackTy *Stack, SmallVector Traits; if (isOpenMPTargetExecutionDirective(DKind)) Traits.emplace_back(llvm::omp::TraitProperty::construct_target_target); + if (isOpenMPDispatchDirective(DKind)) + Traits.emplace_back(llvm::omp::TraitProperty::construct_dispatch_dispatch); if (isOpenMPTeamsDirective(DKind)) Traits.emplace_back(llvm::omp::TraitProperty::construct_teams_teams); if (isOpenMPParallelDirective(DKind)) @@ -4280,6 +4282,14 @@ getTargetRegionParams(Sema &SemaRef) { return Params; } +static SmallVector +getDispatchRegionParams(Sema &SemaRef) { + SmallVector Params; + + Params.emplace_back(StringRef(), QualType()); + return Params; +} + static SmallVector getUnknownRegionParams(Sema &SemaRef) { SmallVector Params{ @@ -4365,6 +4375,10 @@ static void processCapturedRegions(Sema &SemaRef, OpenMPDirectiveKind DKind, SemaRef.ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP, getTargetRegionParams(SemaRef), Level); break; + case OMPD_dispatch: + SemaRef.ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP, + getDispatchRegionParams(SemaRef), Level); + break; case OMPD_unknown: SemaRef.ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP, getUnknownRegionParams(SemaRef)); @@ -5980,6 +5994,99 @@ static bool teamsLoopCanBeParallelFor(Stmt *AStmt, Sema &SemaRef) { return Checker.teamsLoopCanBeParallelFor(); } +/// getNewTraitsOrDirectCall() is for transforming the call traits. +/// Call traits associated with a function call are removed and replaced with +/// a direct call. For clause "nocontext" only, the direct call is then +/// modified to have call traits for a non-dispatch (directive) variant. +static Expr *getNewTraitsOrDirectCall(const ASTContext &Context, + Expr *AssocExpr, SemaOpenMP *SemaPtr, + bool NoContext) { + Expr *PseudoObjExprOrCall = AssocExpr; + if (auto *BinOprExpr = dyn_cast(AssocExpr)) { + PseudoObjExprOrCall = BinOprExpr->getRHS(); + } + + Expr *CallWithoutInvariants = PseudoObjExprOrCall; + // Change PseudoObjectExpr to a direct call + if (auto *PseudoObjExpr = dyn_cast(PseudoObjExprOrCall)) + CallWithoutInvariants = *((PseudoObjExpr->semantics_begin()) - 1); + + Expr *FinalCall = CallWithoutInvariants; // For noinvariants clause + if (NoContext) { + auto *CallExprWithinStmt = cast(CallWithoutInvariants); + int NumArgs = CallExprWithinStmt->getNumArgs(); + clang::Expr **Args = CallExprWithinStmt->getArgs(); + // ActOnOpenMPCall() adds traits to a simple function call + // e.g. invariant function call traits to "foo(i,j)", if they are present. + ExprResult ER = SemaPtr->ActOnOpenMPCall( + CallExprWithinStmt, SemaPtr->SemaRef.getCurScope(), + CallExprWithinStmt->getBeginLoc(), MultiExprArg(Args, NumArgs), + CallExprWithinStmt->getRParenLoc(), static_cast(nullptr)); + FinalCall = ER.get(); + if (auto *PseudoObjExpr = dyn_cast(ER.get())) + FinalCall = *((PseudoObjExpr->semantics_begin())); + } + return FinalCall; +} + +// Add Attribute NoContextAttr or NoVariantsAttr +// to the CapturedDecl. +static void addAttr(const ASTContext &Context, Expr *AssocExpr, + SemaOpenMP *SemaPtr, bool NoContext, CapturedDecl *CDecl) { + llvm::SmallVector Args; + Expr *NewCallExpr = nullptr; + + if (NoContext) { + NewCallExpr = getNewTraitsOrDirectCall(Context, AssocExpr, SemaPtr, true); + Args.push_back(NewCallExpr); + CDecl->addAttr(AnnotateAttr::CreateImplicit( + const_cast(Context), "NoContextAttr", Args.data(), + Args.size())); + } else { + NewCallExpr = getNewTraitsOrDirectCall(Context, AssocExpr, SemaPtr, false); + Args.push_back(NewCallExpr); + CDecl->addAttr(AnnotateAttr::CreateImplicit( + const_cast(Context), "NoVariantsAttr", Args.data(), + Args.size())); + } +} + +/// annotateAStmt() function is used by ActOnOpenMPExecutableDirective() +/// for the dispatch directive (nocontext or invariant clauses). +/// An annotation "NoContextInvariant" is added to the Captured Decl +/// in the Associated Stmt. This annotation contains either a call to the +/// function, not to any of its variants (for invariant clause) or a variant +/// function (for nocontext clause). +void SemaOpenMP::annotateAStmt(const ASTContext &Context, Stmt *StmtP, + SemaOpenMP *SemaPtr, + ArrayRef &Clauses, + SourceLocation StartLoc) { + if (auto *AssocStmt = dyn_cast(StmtP)) { + if (auto *InnerAssocStmt = + dyn_cast(AssocStmt->getCapturedStmt())) { + // Additional CapturedStmt for Virtual taskwait region + AssocStmt = InnerAssocStmt; + } + Stmt *AssocExprStmt = AssocStmt->getCapturedStmt(); + CapturedDecl *CDecl = AssocStmt->getCapturedDecl(); + auto *AssocExpr = dyn_cast(AssocExprStmt); + + if (OMPExecutableDirective::getSingleClause(Clauses)) { + addAttr(const_cast(Context), AssocExpr, SemaPtr, false, + CDecl); + if (OMPExecutableDirective::getSingleClause( + Clauses)) { + addAttr(const_cast(Context), AssocExpr, SemaPtr, true, + CDecl); + } + } else if (OMPExecutableDirective::getSingleClause( + Clauses)) { + addAttr(const_cast(Context), AssocExpr, SemaPtr, true, + CDecl); + } + } +} + StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, OpenMPDirectiveKind CancelRegion, ArrayRef Clauses, @@ -5994,6 +6101,20 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( OMPExecutableDirective::getSingleClause(Clauses)) BindKind = BC->getBindKind(); + if ((Kind == OMPD_dispatch) && (!Clauses.empty())) { + + if (llvm::all_of(Clauses, [](OMPClause *C) { + return llvm::is_contained( + {OMPC_novariants, OMPC_nocontext, OMPC_depend}, + C->getClauseKind()); + })) { + + if (OMPExecutableDirective::getSingleClause( + Clauses) || + OMPExecutableDirective::getSingleClause(Clauses)) + annotateAStmt(getASTContext(), AStmt, this, Clauses, StartLoc); + } + } if (Kind == OMPD_loop && BindKind == OMPC_BIND_unknown) { const OpenMPDirectiveKind ParentDirective = DSAStack->getParentDirective(); @@ -10538,11 +10659,22 @@ StmtResult SemaOpenMP::ActOnOpenMPSectionDirective(Stmt *AStmt, DSAStack->isCancelRegion()); } +/// PseudoObjectExpr is a Trait for dispatch containing the +/// function and its variant. Returning only the function. +static Expr *removePseudoObjectExpr(Expr *PseudoObjExprOrDirectCall) { + Expr *DirectCallExpr = PseudoObjExprOrDirectCall; + if (auto *PseudoObjExpr = + dyn_cast(PseudoObjExprOrDirectCall)) + DirectCallExpr = *((PseudoObjExpr->semantics_begin()) - 1); + return DirectCallExpr; +} + static Expr *getDirectCallExpr(Expr *E) { - E = E->IgnoreParenCasts()->IgnoreImplicit(); - if (auto *CE = dyn_cast(E)) + Expr *PseudoObjExpr = E->IgnoreParenCasts()->IgnoreImplicit(); + Expr *DirectCallExpr = removePseudoObjectExpr(PseudoObjExpr); + if (auto *CE = dyn_cast(DirectCallExpr)) if (CE->getDirectCallee()) - return E; + return DirectCallExpr; return nullptr; } @@ -10554,6 +10686,8 @@ SemaOpenMP::ActOnOpenMPDispatchDirective(ArrayRef Clauses, return StmtError(); Stmt *S = cast(AStmt)->getCapturedStmt(); + if (auto *CS = dyn_cast(S)) + S = CS->getCapturedStmt(); // 5.1 OpenMP // expression-stmt : an expression statement with one of the following forms: diff --git a/clang/test/OpenMP/dispatch_codegen.cpp b/clang/test/OpenMP/dispatch_codegen.cpp new file mode 100644 index 0000000000000..8da387640d988 --- /dev/null +++ b/clang/test/OpenMP/dispatch_codegen.cpp @@ -0,0 +1,364 @@ +// expected-no-diagnostics +// RUN: %clang_cc1 -DCK1 -verify -fopenmp -x c++ %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s + +int foo_variant_dispatch(int x, int y) { + return x+2; +} + +int foo_variant_allCond(int x, int y) { + return x+3; +} + +#pragma omp declare variant(foo_variant_dispatch) match(construct={dispatch}) +#pragma omp declare variant(foo_variant_allCond) match(user={condition(1)}) +int foo(int x, int y) { + // Original implementation of foo + return x+1; +} + +void checkNoVariants(); +void checkNoContext(); +void checkDepend(); + +void declareVariant1() +{ + int cond_false = 0, cond_true = 1; + + int x = 0; + int y = 0; + int output = 0; + + foo(x,y); + + #pragma omp dispatch + output = foo(x,y); + + checkNoVariants(); + checkNoContext(); + checkDepend(); +} + +void checkNoVariants() +{ + int cond_false = 0, cond_true = 1; + + int x = 0; + int y = 0; + int output = 0; + + #pragma omp dispatch novariants(cond_false) + foo(x,y); + + #pragma omp dispatch novariants(cond_true) + output = foo(x,y); +} + +void checkNoContext() +{ + int cond_false = 0, cond_true = 1; + + int x = 0; + int y = 0; + int output = 0; + + #pragma omp dispatch nocontext(cond_false) + foo(x,y); + + #pragma omp dispatch nocontext(cond_true) + output = foo(x,y); + +} + +void checkDepend() +{ + int cond_false = 0, cond_true = 1; + + int x = 0; + int y = 0; + int output = 0; + + #pragma omp dispatch depend(out:x) + output = foo(x,y); + + #pragma omp dispatch depend(out:x) depend(out:y) + output = foo(x,y); + + #pragma omp dispatch depend(out:x) novariants(cond_false) + output = foo(x,y); + + #pragma omp dispatch depend(out:x) nocontext(cond_false) + foo(x,y); + + #pragma omp dispatch depend(out:x) novariants(cond_false) nocontext(cond_true) + output = foo(x,y); +} + +int bar_variant(int x) { + return x+2; +} + +int bar(int x) { + return x+1; +} + +void checkNoContext_withoutVariant(); +void checkNoVariants_withoutVariant(); + +int without_declareVariant() +{ + int cond_false = 0, cond_true = 1; + + int x = 0; + int output = 0; + + bar(x); + + #pragma omp dispatch + bar(x); + + checkNoVariants_withoutVariant(); + checkNoContext_withoutVariant(); + return 1; +} + +void checkNoVariants_withoutVariant() { + int cond_false = 0, cond_true = 1; + + int x = 0; + int output = 0; + + #pragma omp dispatch novariants(cond_true) + output = bar(x); + + #pragma omp dispatch novariants(cond_false) + bar(x); +} + +void checkNoContext_withoutVariant() { + int cond_false = 0, cond_true = 1; + + int x = 0; + int output = 0; + + #pragma omp dispatch nocontext(cond_true) + output = bar(x); + + #pragma omp dispatch nocontext(cond_false) + bar(x); +} + +// CHECK-LABEL: define {{.+}}declareVariant{{.+}} +// CHECK-LABEL: entry: +// +// #pragma omp dispatch +// CHECK: call {{.+}}foo_variant_allCond{{.+}} +// CHECK: call {{.+}}captured_stmt{{.+}} +// CHECK-NEXT: call {{.+}}checkNoVariants{{.+}} +// CHECK-NEXT: call {{.+}}checkNoContext{{.+}} +// CHECK-NEXT: call {{.+}}checkDepend{{.+}} +// CHECK-NEXT: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt{{.+}} +// CHECK: call {{.+}}foo_variant_dispatch{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: {{.+}}checkNoVariants{{.+}} +// CHECK-LABEL: entry: +// #pragma omp dispatch novariants(cond_false) +// CHECK-LABEL: if.then{{.+}} +// CHECK: call {{.+}}captured_stmt.1{{.+}} +// CHECK-LABEL: if.else{{.+}} +// CHECK: call {{.+}}captured_stmt.2{{.+}} +// CHECK-LABEL: if.end{{.+}} +// +// #pragma omp dispatch novariants(cond_true) +// CHECK-LABEL: if.then{{.+}} +// CHECK: call {{.+}}captured_stmt.3{{.+}} +// CHECK-LABEL: if.else{{.+}} +// CHECK: call {{.+}}captured_stmt.4{{.+}} +// CHECK-LABEL: if.end{{.+}} +// +// CHECK-LABEL: {{.+}}checkNoContext{{.+}} +// CHECK-LABEL: entry: +// +// #pragma omp dispatch nocontext(cond_false) +// CHECK-LABEL: if.then{{.+}} +// CHECK: call {{.+}}captured_stmt.5{{.+}} +// CHECK-LABEL: if.else{{.+}} +// CHECK: call {{.+}}captured_stmt.6{{.+}} +// CHECK-LABEL: if.end{{.+}} +// +// #pragma omp dispatch nocontext(cond_true) +// CHECK-LABEL: if.then{{.+}} +// CHECK: call {{.+}}captured_stmt.7{{.+}} +// CHECK-LABEL: if.else{{.+}} +// CHECK: call {{.+}}captured_stmt.8{{.+}} +// CHECK-LABEL: if.end{{.+}} +// +// CHECK-LABEL: {{.+}}checkDepend{{.+}} +// CHECK-LABEL: entry: +// +// #pragma omp dispatch depend(out:x) +// CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}} +// +// #pragma omp dispatch depend(out:x) depend(out:y) +// CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}} +// +// #pragma omp dispatch depend(out:x) novariants(cond_false) +// CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}} +// CHECK-LABEL: if.then{{.+}} +// CHECK: call {{.+}}captured_stmt.9{{.+}} +// CHECK-LABEL: if.else{{.+}} +// CHECK: call {{.+}}captured_stmt.10{{.+}} +// CHECK-LABEL: if.end{{.+}} +// +// #pragma omp dispatch depend(out:x) nocontext(cond_false) +// CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}} +// CHECK-LABEL: if.then{{.+}} +// CHECK: call {{.+}}captured_stmt.11{{.+}} +// CHECK-LABEL: if.else{{.+}} +// CHECK: call {{.+}}captured_stmt.12{{.+}} +// CHECK-LABEL: if.end{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.1{{.+}} +// CHECK: call {{.+}}foo{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.2{{.+}} +// CHECK: call {{.+}}foo_variant_dispatch{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.3{{.+}} +// CHECK: call {{.+}}foo{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.4{{.+}} +// CHECK: call {{.+}}foo_variant_dispatch{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.5{{.+}} +// CHECK: call {{.+}}foo_variant_allCond{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.6{{.+}} +// CHECK: call {{.+}}foo_variant_dispatch{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.7{{.+}} +// CHECK: call {{.+}}foo_variant_allCond{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.8{{.+}} +// CHECK: call {{.+}}foo_variant_dispatch{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.9{{.+}} +// CHECK: call {{.+}}foo{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.10{{.+}} +// CHECK: call {{.+}}foo_variant_dispatch{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.11{{.+}} +// CHECK: call {{.+}}foo_variant_allCond{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.12{{.+}} +// CHECK: call {{.+}}foo_variant_dispatch{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.13{{.+}} +// CHECK: call {{.+}}foo{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.14{{.+}} +// CHECK: call {{.+}}foo_variant_allCond{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.15{{.+}} +// CHECK: call {{.+}}foo_variant_dispatch{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}bar_variant{{.+}} +// CHECK-LABEL: entry: +// CHECK: ret{{.+}} +// +// CHECK-LABEL: define {{.+}}bar{{.+}} +// CHECK-LABEL: entry: +// CHECK: ret{{.+}} + +// CHECK-LABEL: define {{.+}}without_declareVariant{{.+}} +// CHECK-LABEL: entry: +// CHECK: call {{.+}}bar{{.+}} +// CHECK: call {{.+}}captured_stmt.16{{.+}} +// CHECK-NEXT: call {{.+}}checkNoVariants_withoutVariant{{.+}} +// CHECK-NEXT: call {{.+}}checkNoContext_withoutVariant{{.+}} +// CHECK-NEXT: ret{{.+}} +// +// #pragma omp dispatch +// CHECK-LABEL: define {{.+}}__captured_stmt.16{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}checkNoVariants_withoutVariant{{.+}} +// CHECK-LABEL: entry: +// CHECK-LABEL: if.then{{.+}} +// CHECK: call {{.+}}captured_stmt.17{{.+}} +// CHECK-LABEL: if.else{{.+}} +// CHECK: call {{.+}}captured_stmt.18{{.+}} +// CHECK-LABEL: if.end{{.+}} +// CHECK-LABEL: if.then{{.+}} +// CHECK: call {{.+}}captured_stmt.19{{.+}} +// CHECK-LABEL: if.else{{.+}} +// CHECK: call {{.+}}captured_stmt.20{{.+}} +// CHECK-LABEL: if.end{{.+}} +// CHECK: ret{{.+}} +// +// CHECK-LABEL: define {{.+}}checkNoContext_withoutVariant{{.+}} +// CHECK-LABEL: entry: +// CHECK-LABEL: if.then{{.+}} +// CHECK: call {{.+}}captured_stmt.21{{.+}} +// CHECK-LABEL: if.else{{.+}} +// CHECK: call {{.+}}captured_stmt.22{{.+}} +// CHECK-LABEL: if.end{{.+}} +// CHECK-LABEL: if.then{{.+}} +// CHECK: call {{.+}}captured_stmt.23{{.+}} +// CHECK-LABEL: if.else{{.+}} +// CHECK: call {{.+}}captured_stmt.24{{.+}} +// CHECK-LABEL: if.end{{.+}} +// CHECK: ret{{.+}} +// +// #pragma omp dispatch novariants(cond_true) +// CHECK-LABEL: define {{.+}}__captured_stmt.17{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// CHECK-LABEL: define {{.+}}__captured_stmt.18{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// +// #pragma omp dispatch novariants(cond_false) +// CHECK-LABEL: define {{.+}}__captured_stmt.19{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// CHECK-LABEL: define {{.+}}__captured_stmt.20{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// +// #pragma omp dispatch nocontext(cond_true) +// CHECK-LABEL: define {{.+}}__captured_stmt.21{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// CHECK-LABEL: define {{.+}}__captured_stmt.22{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// +// #pragma omp dispatch nocontext(cond_false) +// CHECK-LABEL: define {{.+}}__captured_stmt.23{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// CHECK-LABEL: define {{.+}}__captured_stmt.24{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void diff --git a/clang/test/OpenMP/dispatch_messages.cpp b/clang/test/OpenMP/dispatch_messages.cpp index 27592e18adfa7..5d1fc77f6bdce 100644 --- a/clang/test/OpenMP/dispatch_messages.cpp +++ b/clang/test/OpenMP/dispatch_messages.cpp @@ -64,6 +64,47 @@ void testit_one(int dnum) { // expected-error@+1 {{use of undeclared identifier 'x'}} #pragma omp dispatch nocontext(x) disp_call(); + + bool c1 = false; + bool c2 = true; + int a = 3, b=4; + int output; + + // expected-error@+1 {{expected '(' after 'depend'}} + #pragma omp dispatch depend + disp_call(); + + // expected-error@+4 {{expected ')'}} + // expected-note@+3 {{to match this '('}} + // expected-error@+2 {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset', 'depobj' or 'inoutset' in OpenMP clause 'depend'}} + // expected-warning@+1 {{missing ':' after dependency type}} + #pragma omp dispatch depend( + disp_call(); + + // expected-error@+4 {{expected ')'}} + // expected-note@+3 {{to match this '('}} + // expected-error@+2 {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset', 'depobj' or 'inoutset' in OpenMP clause 'depend'}} + // expected-warning@+1 {{missing ':' after dependency type}} + #pragma omp dispatch depend(a + disp_call(); + + // expected-error@+2 {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset', 'depobj' or 'inoutset' in OpenMP clause 'depend'}} + // expected-warning@+1 {{missing ':' after dependency type}} + #pragma omp dispatch depend(a) + disp_call(); + + // expected-error@+1 {{use of undeclared identifier 'z'}} + #pragma omp dispatch depend(in:z) + disp_call(); + + #pragma omp dispatch depend(in:b) + output = disp_call(); + + #pragma omp dispatch depend(in:b) depend(in:a) + output = disp_call(); + + #pragma omp dispatch nocontext(c1) novariants(c2) depend(inout:a) + disp_call(); } void testit_two() { diff --git a/clang/test/OpenMP/dispatch_unsupported.c b/clang/test/OpenMP/dispatch_unsupported.c deleted file mode 100644 index fe7ccfa90a583..0000000000000 --- a/clang/test/OpenMP/dispatch_unsupported.c +++ /dev/null @@ -1,7 +0,0 @@ -// RUN: %clang_cc1 -emit-llvm -fopenmp -disable-llvm-passes %s -o /dev/null -verify=expected - -// expected-error@+2 {{cannot compile this OpenMP dispatch directive yet}} -void a(){ - #pragma omp dispatch - a(); -}