https://github.com/SunilKuravinakop updated https://github.com/llvm/llvm-project/pull/117904
>From f466152e17c8057b98fbc88ebf413de82ca3ecb7 Mon Sep 17 00:00:00 2001 From: Sunil Kuravinakop <kurav...@pe28vega.hpc.amslabs.hpecorp.net> Date: Fri, 20 Sep 2024 01:41:29 -0500 Subject: [PATCH] Support for dispatch construct (Sema & Codegen) support. Support for clauses depend, novariants & nocontext. --- .../clang/Basic/DiagnosticSemaKinds.td | 3 + clang/include/clang/Basic/OpenMPKinds.h | 6 + clang/include/clang/Sema/SemaOpenMP.h | 7 + clang/lib/Basic/OpenMPKinds.cpp | 5 + clang/lib/CodeGen/CGStmt.cpp | 2 +- clang/lib/CodeGen/CGStmtOpenMP.cpp | 4 + clang/lib/CodeGen/CodeGenFunction.h | 1 + clang/lib/Sema/SemaOpenMP.cpp | 294 +++++++++++++- clang/test/OpenMP/dispatch_codegen.cpp | 359 ++++++++++++++++++ clang/test/OpenMP/dispatch_unsupported.c | 7 - .../include/llvm/Frontend/OpenMP/OMPContext.h | 6 + 11 files changed, 683 insertions(+), 11 deletions(-) create mode 100644 clang/test/OpenMP/dispatch_codegen.cpp delete mode 100644 clang/test/OpenMP/dispatch_unsupported.c diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 8495884dcd058f..81b876f9fd85c5 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11774,6 +11774,9 @@ def err_omp_clause_requires_dispatch_construct : Error< "'%0' clause requires 'dispatch' context selector">; def err_omp_append_args_with_varargs : Error< "'append_args' is not allowed with varargs functions">; +def warn_omp_dispatch_clause_novariants_nocontext : Warning< + "only 'novariants' clause is supported when 'novariants' & 'nocontext' clauses occur on the same dispatch construct">, + InGroup<SourceUsesOpenMP>; def err_openmp_vla_in_task_untied : Error< "variable length arrays are not supported in OpenMP tasking regions with 'untied' clause">; def warn_omp_unterminated_declare_target : Warning< diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h index 900ad6ca6d66f6..7579fab43dbb19 100644 --- a/clang/include/clang/Basic/OpenMPKinds.h +++ b/clang/include/clang/Basic/OpenMPKinds.h @@ -269,6 +269,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 3d1cc4fab1c10f..80cee9e7583051 100644 --- a/clang/include/clang/Sema/SemaOpenMP.h +++ b/clang/include/clang/Sema/SemaOpenMP.h @@ -1462,6 +1462,13 @@ class SemaOpenMP : public SemaBase { : OMPDeclareVariantScopes.back().TI; } + StmtResult transformDispatchDirective(OpenMPDirectiveKind Kind, + const DeclarationNameInfo &DirName, + OpenMPDirectiveKind CancelRegion, + ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// The current `omp begin/end declare variant` scopes. SmallVector<OMPDeclareVariantScope, 4> OMPDeclareVariantScopes; diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 62a13f01481b28..44ee63df46adb5 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -621,6 +621,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_target); +} + bool clang::isOpenMPTargetExecutionDirective(OpenMPDirectiveKind DKind) { return DKind == OMPD_target || llvm::is_contained(getLeafConstructs(DKind), OMPD_target); diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 698baf853507f4..f3eedb79844378 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -417,7 +417,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) { EmitOMPInteropDirective(cast<OMPInteropDirective>(*S)); break; case Stmt::OMPDispatchDirectiveClass: - CGM.ErrorUnsupported(S, "OpenMP dispatch directive"); + EmitOMPDispatchDirective(cast<OMPDispatchDirective>(*S)); break; case Stmt::OMPScopeDirectiveClass: EmitOMPScopeDirective(cast<OMPScopeDirective>(*S)); diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 6cb37b20b7aeee..f3f2f54b068263 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -4452,6 +4452,10 @@ void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) { emitMaster(*this, S); } +void CodeGenFunction::EmitOMPDispatchDirective(const OMPDispatchDirective &S) { + EmitStmt(S.getAssociatedStmt()); +} + static void emitMasked(CodeGenFunction &CGF, const OMPExecutableDirective &S) { auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { Action.Enter(CGF); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index eaea0d8a08ac06..2e342bc00a94a8 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3830,6 +3830,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 66ff92f554fc42..3e3efe2b3edd0c 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -4205,6 +4205,8 @@ static void handleDeclareVariantConstructTrait(DSAStackTy *Stack, SmallVector<llvm::omp::TraitProperty, 8> 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)) @@ -5965,6 +5967,263 @@ static bool teamsLoopCanBeParallelFor(Stmt *AStmt, Sema &SemaRef) { return Checker.teamsLoopCanBeParallelFor(); } +static Expr *getInitialExprFromCapturedExpr(Expr *Cond) { + + Expr *SubExpr = Cond->IgnoreParenImpCasts(); + + if (auto *DeclRef = dyn_cast<DeclRefExpr>(SubExpr)) { + if (auto *CapturedExprDecl = + dyn_cast<OMPCapturedExprDecl>(DeclRef->getDecl())) { + + // Retrieve the initial expression from the captured expression + return CapturedExprDecl->getInit(); + } + } + return nullptr; +} + +// Next two functions, CloneAssociatedStmt() & +// replaceWithNewTraitsOrDirectCall(), are for transforming the call traits. +// e.g. +// #pragma omp declare variant(foo_variant_dispatch) match(construct={dispatch}) +// #pragma omp declare variant(foo_variant_allCond) match(user={condition(1)}) +// .. +// #pragma omp dispatch nocontext(cond_true) +// foo(i, j); +// is changed to: +// if (cond_true) { +// foo(i,j) // with traits: CodeGen call to foo_variant_allCond(i,j) +// } else { +// #pragma omp dispatch +// foo(i,j) // with traits: CodeGen call to foo_variant_dispatch(i,j) +// } +// +// The next 2 functions, are for: +// if (cond_true) { +// foo(i,j) // with traits: runtime call to foo_variant_allCond(i,j) +// } +// +static Expr *ReplaceWithNewTraitsOrDirectCall(const ASTContext &Context, Expr *, + SemaOpenMP *, bool); + +static StmtResult CloneAssociatedStmt(const ASTContext &Context, Stmt *StmtP, + SemaOpenMP *SemaPtr, bool NoContext) { + if (CapturedStmt *AssocStmt = dyn_cast<CapturedStmt>(StmtP)) { + CapturedDecl *CDecl = AssocStmt->getCapturedDecl(); + Stmt *AssocExprStmt = AssocStmt->getCapturedStmt(); + Expr *AssocExpr = dyn_cast<Expr>(AssocExprStmt); + Expr *NewCallOrPseudoObjOrBinExpr = ReplaceWithNewTraitsOrDirectCall( + Context, AssocExpr, SemaPtr, NoContext); + + // Copy Current Captured Decl to a New Captured Decl for noting the + // Annotation + CapturedDecl *NewDecl = + CapturedDecl::Create(const_cast<ASTContext &>(Context), + CDecl->getDeclContext(), CDecl->getNumParams()); + NewDecl->setBody(static_cast<Stmt *>(NewCallOrPseudoObjOrBinExpr)); + for (unsigned i = 0; i < CDecl->getNumParams(); ++i) { + if (i != CDecl->getContextParamPosition()) + NewDecl->setParam(i, CDecl->getParam(i)); + else + NewDecl->setContextParam(i, CDecl->getContextParam()); + } + + // Create a New Captured Stmt containing the New Captured Decl + SmallVector<CapturedStmt::Capture, 4> Captures; + SmallVector<Expr *, 4> CaptureInits; + for (auto capture : AssocStmt->captures()) + Captures.push_back(capture); + for (auto capture_init : AssocStmt->capture_inits()) + CaptureInits.push_back(capture_init); + CapturedStmt *NewStmt = CapturedStmt::Create( + Context, AssocStmt->getCapturedStmt(), + AssocStmt->getCapturedRegionKind(), Captures, CaptureInits, NewDecl, + const_cast<RecordDecl *>(AssocStmt->getCapturedRecordDecl())); + + return NewStmt; + } + return static_cast<Stmt *>(nullptr); +} + +static Expr *ReplaceWithNewTraitsOrDirectCall(const ASTContext &Context, + Expr *AssocExpr, + SemaOpenMP *SemaPtr, + bool NoContext) { + BinaryOperator *BinaryCopyOpr = nullptr; + bool IsBinaryOp = false; + Expr *PseudoObjExprOrCall = AssocExpr; + if (BinaryOperator *BinOprExpr = dyn_cast<BinaryOperator>(AssocExpr)) { + IsBinaryOp = true; + BinaryCopyOpr = BinaryOperator::Create( + Context, BinOprExpr->getLHS(), BinOprExpr->getRHS(), + BinOprExpr->getOpcode(), BinOprExpr->getType(), + BinOprExpr->getValueKind(), BinOprExpr->getObjectKind(), + BinOprExpr->getOperatorLoc(), FPOptionsOverride()); + PseudoObjExprOrCall = BinaryCopyOpr->getRHS(); + } + + Expr *CallWithoutInvariants = PseudoObjExprOrCall; + // Change PseudoObjectExpr to a direct call + if (PseudoObjectExpr *PseudoObjExpr = + dyn_cast<PseudoObjectExpr>(PseudoObjExprOrCall)) + CallWithoutInvariants = *((PseudoObjExpr->semantics_begin()) - 1); + + Expr *FinalCall = CallWithoutInvariants; // For noinvariants clause + if (NoContext) { + // Convert StmtResult to a CallExpr before calling ActOnOpenMPCall() + CallExpr *CallExprWithinStmt = dyn_cast<CallExpr>(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<Expr *>(nullptr)); + FinalCall = ER.get(); + } + + if (IsBinaryOp) { + BinaryCopyOpr->setRHS(FinalCall); + return BinaryCopyOpr; + } + + return FinalCall; +} + +static StmtResult combine2Stmts(ASTContext &Context, Stmt *FirstStmt, + Stmt *SecondStmt) { + + llvm::SmallVector<Stmt *, 2> NewCombinedStmtVector; + NewCombinedStmtVector.push_back(FirstStmt); + NewCombinedStmtVector.push_back(SecondStmt); + CompoundStmt *CombinedStmt = CompoundStmt::Create( + Context, llvm::ArrayRef<Stmt *>(NewCombinedStmtVector), + FPOptionsOverride(), SourceLocation(), SourceLocation()); + StmtResult FinalStmts(CombinedStmt); + return FinalStmts; +} + +template <typename SpecificClause> +static bool hasClausesOfKind(ArrayRef<OMPClause *> Clauses) { + auto ClausesOfKind = + OMPExecutableDirective::getClausesOfKind<SpecificClause>(Clauses); + return ClausesOfKind.begin() != ClausesOfKind.end(); +} + +StmtResult SemaOpenMP::transformDispatchDirective( + OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, + OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { + + StmtResult RetValue; + llvm::SmallVector<OMPClause *, 8> DependVector; + for (const OMPDependClause *ConstDependClause : + OMPExecutableDirective::getClausesOfKind<OMPDependClause>(Clauses)) { + OMPDependClause *DependClause = + const_cast<OMPDependClause *>(ConstDependClause); + DependVector.push_back(DependClause); + } + llvm::ArrayRef<OMPClause *> DependCArray(DependVector); + + // #pragma omp dispatch depend() is changed to #pragma omp taskwait depend() + // This is done by calling ActOnOpenMPExecutableDirective() for the + // new taskwait directive. + StmtResult DispatchDepend2taskwait = + ActOnOpenMPExecutableDirective(OMPD_taskwait, DirName, CancelRegion, + DependCArray, NULL, StartLoc, EndLoc); + + if (OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(Clauses)) { + + if (OMPExecutableDirective::getSingleClause<OMPNocontextClause>(Clauses)) { + Diag(StartLoc, diag::warn_omp_dispatch_clause_novariants_nocontext); + } + + const OMPNovariantsClause *NoVariantsC = + OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(Clauses); + // #pragma omp dispatch novariants(c2) depend(out: x) + // foo(); + // becomes: + // #pragma omp taskwait depend(out: x) + // if (c2) { + // foo(); + // } else { + // #pragma omp dispatch + // foo(); <--- foo() is replaced with foo_variant() in CodeGen + // } + Expr *Cond = getInitialExprFromCapturedExpr(NoVariantsC->getCondition()); + StmtResult ThenStmt = + CloneAssociatedStmt(getASTContext(), AStmt, this, false); + SmallVector<OMPClause *, 5> DependClauses; + StmtResult ElseStmt = ActOnOpenMPExecutableDirective( + Kind, DirName, CancelRegion, DependClauses, AStmt, StartLoc, EndLoc); + IfStmt *IfElseStmt = + IfStmt::Create(getASTContext(), StartLoc, IfStatementKind::Ordinary, + nullptr, // Init + nullptr, // Condition Var Declaration + Cond, + StartLoc, // Source Location Left Paranthesis + StartLoc, // Source Location Right Paranthesis + ThenStmt.get(), StartLoc, ElseStmt.get()); + if (hasClausesOfKind<OMPDependClause>(Clauses)) { + StmtResult FinalStmts = combine2Stmts( + getASTContext(), DispatchDepend2taskwait.get(), IfElseStmt); + RetValue = FinalStmts; + } else { + RetValue = IfElseStmt; + } + } else if (OMPExecutableDirective::getSingleClause<OMPNocontextClause>( + Clauses)) { + + const OMPNocontextClause *NoContextC = + OMPExecutableDirective::getSingleClause<OMPNocontextClause>(Clauses); + Expr *Cond = getInitialExprFromCapturedExpr(NoContextC->getCondition()); + // #pragma omp dispatch depend(out: x) nocontext(c2) + // foo(); + // becomes: + // #pragma omp taskwait depend(out: x) + // if (c2) { + // foo(); + // } else { + // #pragma omp dispatch + // foo(); + // } + + StmtResult ThenStmt = + CloneAssociatedStmt(getASTContext(), AStmt, this, true); + + SmallVector<OMPClause *, 5> DependClauses; + StmtResult ElseStmt = ActOnOpenMPExecutableDirective( + Kind, DirName, CancelRegion, DependClauses, AStmt, StartLoc, EndLoc); + IfStmt *IfElseStmt = + IfStmt::Create(getASTContext(), StartLoc, IfStatementKind::Ordinary, + nullptr, // Init + nullptr, // Condition Var Declaration + Cond, + StartLoc, // Source Location Left Paranthesis + StartLoc, // Source Location Right Paranthesis + ThenStmt.get(), StartLoc, ElseStmt.get()); + if (hasClausesOfKind<OMPDependClause>(Clauses)) { + StmtResult FinalStmts = combine2Stmts( + getASTContext(), DispatchDepend2taskwait.get(), IfElseStmt); + RetValue = FinalStmts; + } else { + RetValue = IfElseStmt; + } + } else if (hasClausesOfKind<OMPDependClause>(Clauses)) { + // Only: + // #pragma omp dispatch depend(out: x) + // foo(); + // to + // #pragma omp taskwait depend(out: x) + // foo(); + StmtResult FinalStmts = + combine2Stmts(getASTContext(), DispatchDepend2taskwait.get(), AStmt); + RetValue = FinalStmts; + } + return RetValue; +} + StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses, @@ -5979,6 +6238,20 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( OMPExecutableDirective::getSingleClause<OMPBindClause>(Clauses)) BindKind = BC->getBindKind(); + if ((Kind == OMPD_dispatch) && (Clauses.size() > 0)) { + + bool UnSupportedClause = false; + for (OMPClause *C : Clauses) { + if (!((C->getClauseKind() == OMPC_novariants) || + (C->getClauseKind() == OMPC_nocontext) || + (C->getClauseKind() == OMPC_depend))) + UnSupportedClause = true; + } + if (!UnSupportedClause) + return transformDispatchDirective(Kind, DirName, CancelRegion, Clauses, + AStmt, StartLoc, EndLoc); + } + if (Kind == OMPD_loop && BindKind == OMPC_BIND_unknown) { const OpenMPDirectiveKind ParentDirective = DSAStack->getParentDirective(); @@ -7209,8 +7482,10 @@ ExprResult SemaOpenMP::ActOnOpenMPCall(ExprResult Call, Scope *Scope, Exprs.erase(Exprs.begin() + BestIdx); } while (!VMIs.empty()); - if (!NewCall.isUsable()) + if (!NewCall.isUsable()) { + fprintf(stdout, "Returning Call, NewCall is not usable\n"); return Call; + } return PseudoObjectExpr::Create(getASTContext(), CE, {NewCall.get()}, 0); } @@ -10520,8 +10795,17 @@ StmtResult SemaOpenMP::ActOnOpenMPSectionDirective(Stmt *AStmt, DSAStack->isCancelRegion()); } +static Expr *removePseudoObjectExpr(Expr *E) { + // PseudoObjectExpr is a Trait for dispatch containing the + // function name and its variant. Returning the function name. + if (auto *PO = dyn_cast<PseudoObjectExpr>(E)) + E = *((PO->semantics_begin()) - 1); + return E; +} + static Expr *getDirectCallExpr(Expr *E) { E = E->IgnoreParenCasts()->IgnoreImplicit(); + E = removePseudoObjectExpr(E); if (auto *CE = dyn_cast<CallExpr>(E)) if (CE->getDirectCallee()) return E; @@ -10556,15 +10840,19 @@ SemaOpenMP::ActOnOpenMPDispatchDirective(ArrayRef<OMPClause *> Clauses, E = E->IgnoreParenCasts()->IgnoreImplicit(); if (auto *BO = dyn_cast<BinaryOperator>(E)) { - if (BO->getOpcode() == BO_Assign) + if (BO->getOpcode() == BO_Assign) { TargetCall = getDirectCallExpr(BO->getRHS()); + } } else { if (auto *COCE = dyn_cast<CXXOperatorCallExpr>(E)) if (COCE->getOperator() == OO_Equal) TargetCall = getDirectCallExpr(COCE->getArg(1)); - if (!TargetCall) + if (!TargetCall) { + E = removePseudoObjectExpr(E); TargetCall = getDirectCallExpr(E); + } } + if (!TargetCall) { Diag(E->getBeginLoc(), diag::err_omp_dispatch_statement_call); return StmtError(); diff --git a/clang/test/OpenMP/dispatch_codegen.cpp b/clang/test/OpenMP/dispatch_codegen.cpp new file mode 100644 index 00000000000000..3a50ccbb99873a --- /dev/null +++ b/clang/test/OpenMP/dispatch_codegen.cpp @@ -0,0 +1,359 @@ +// 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); +} + +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{{.+}} +// CHECK: call {{.+}}captured_stmt.9{{.+}} +// +// #pragma omp dispatch depend(out:x) depend(out:y) +// CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}} +// CHECK: call {{.+}}captured_stmt.10{{.+}} +// +// #pragma omp dispatch depend(out:x) novariants(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{{.+}} +// +// #pragma omp dispatch depend(out:x) nocontext(cond_false) +// CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}} +// CHECK-LABEL: if.then{{.+}} +// CHECK: call {{.+}}captured_stmt.13{{.+}} +// CHECK-LABEL: if.else{{.+}} +// CHECK: call {{.+}}captured_stmt.14{{.+}} +// 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_variant_dispatch{{.+}} +// 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{{.+}} +// 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_variant_allCond{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}__captured_stmt.14{{.+}} +// 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.15{{.+}} +// CHECK-NEXT: call {{.+}}checkNoVariants_withoutVariant{{.+}} +// CHECK-NEXT: call {{.+}}checkNoContext_withoutVariant{{.+}} +// CHECK-NEXT: ret{{.+}} +// +// #pragma omp dispatch +// CHECK-LABEL: define {{.+}}__captured_stmt.15{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// +// CHECK-LABEL: define {{.+}}checkNoVariants_withoutVariant{{.+}} +// CHECK-LABEL: entry: +// CHECK-LABEL: if.then{{.+}} +// CHECK: call {{.+}}captured_stmt.16{{.+}} +// CHECK-LABEL: if.else{{.+}} +// CHECK: call {{.+}}captured_stmt.17{{.+}} +// CHECK-LABEL: if.end{{.+}} +// CHECK-LABEL: if.then{{.+}} +// CHECK: call {{.+}}captured_stmt.18{{.+}} +// CHECK-LABEL: if.else{{.+}} +// CHECK: call {{.+}}captured_stmt.19{{.+}} +// CHECK-LABEL: if.end{{.+}} +// CHECK: ret{{.+}} +// +// CHECK-LABEL: define {{.+}}checkNoContext_withoutVariant{{.+}} +// CHECK-LABEL: entry: +// CHECK-LABEL: if.then{{.+}} +// CHECK: call {{.+}}captured_stmt.20{{.+}} +// CHECK-LABEL: if.else{{.+}} +// CHECK: call {{.+}}captured_stmt.21{{.+}} +// CHECK-LABEL: if.end{{.+}} +// CHECK-LABEL: if.then{{.+}} +// CHECK: call {{.+}}captured_stmt.22{{.+}} +// CHECK-LABEL: if.else{{.+}} +// CHECK: call {{.+}}captured_stmt.23{{.+}} +// CHECK-LABEL: if.end{{.+}} +// CHECK: ret{{.+}} +// +// #pragma omp dispatch novariants(cond_true) +// CHECK-LABEL: define {{.+}}__captured_stmt.16{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// CHECK-LABEL: define {{.+}}__captured_stmt.17{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// +// #pragma omp dispatch novariants(cond_false) +// CHECK-LABEL: define {{.+}}__captured_stmt.18{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// CHECK-LABEL: define {{.+}}__captured_stmt.19{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// +// #pragma omp dispatch nocontext(cond_true) +// CHECK-LABEL: define {{.+}}__captured_stmt.20{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// CHECK-LABEL: define {{.+}}__captured_stmt.21{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// +// #pragma omp dispatch nocontext(cond_false) +// CHECK-LABEL: define {{.+}}__captured_stmt.22{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void +// CHECK-LABEL: define {{.+}}__captured_stmt.23{{.+}} +// CHECK: call {{.+}}bar{{.+}} +// CHECK: ret void diff --git a/clang/test/OpenMP/dispatch_unsupported.c b/clang/test/OpenMP/dispatch_unsupported.c deleted file mode 100644 index fe7ccfa90a5831..00000000000000 --- 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(); -} diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h index b13b74ceab8651..9ca7bf332f9519 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h @@ -141,6 +141,12 @@ struct VariantMatchInfo { ISATraits.push_back(RawString); RequiredTraits.set(unsigned(Property)); +#if 0 + unsigned int i = 0; + for (unsigned Bit : RequiredTraits.set_bits()) { + i++; + } +#endif if (Set == TraitSet::construct) ConstructTraits.push_back(Property); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits