llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: None (SunilKuravinakop) <details> <summary>Changes</summary> Support for dispatch construct (Sema & Codegen) support. Support for clauses: depend, novariants & nocontext. --- Patch is 30.07 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/117904.diff 12 Files Affected: - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2) - (modified) clang/include/clang/Basic/OpenMPKinds.h (+6) - (modified) clang/include/clang/Sema/SemaOpenMP.h (+7) - (modified) clang/lib/Basic/OpenMPKinds.cpp (+5) - (modified) clang/lib/CodeGen/CGStmt.cpp (+2-1) - (modified) clang/lib/CodeGen/CGStmtOpenMP.cpp (+5) - (modified) clang/lib/CodeGen/CodeGenFunction.h (+1) - (modified) clang/lib/Sema/SemaOpenMP.cpp (+272-3) - (modified) clang/test/Misc/warning-flags.c (+2-1) - (added) clang/test/OpenMP/dispatch_codegen.cpp (+359) - (removed) clang/test/OpenMP/dispatch_unsupported.c (-7) - (modified) llvm/include/llvm/Frontend/OpenMP/OMPContext.h (+6) ``````````diff diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c1cdd811db446d..61d684461d785f 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11769,6 +11769,8 @@ 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">; 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..2cd2a650151c87 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -417,7 +417,8 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) { EmitOMPInteropDirective(cast<OMPInteropDirective>(*S)); break; case Stmt::OMPDispatchDirectiveClass: - CGM.ErrorUnsupported(S, "OpenMP dispatch directive"); + // 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 390516fea38498..7d77db0ba2bb12 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -4452,6 +4452,11 @@ 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 5c4d76c2267a77..0adf51f53aceaf 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 976d48e1249136..943e47e2d96b25 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,244 @@ 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; +} + +static Expr *copy_removePseudoObjectExpr(const ASTContext &Context, Expr *E, + SemaOpenMP *SemaPtr, bool NoContext) { + + BinaryOperator *BinaryCopyOpr = NULL; + bool BinaryOp = false; + if (E->getStmtClass() == Stmt::BinaryOperatorClass) { + BinaryOp = true; + BinaryOperator *E_BinOpr = static_cast<BinaryOperator *>(E); + BinaryCopyOpr = BinaryOperator::Create( + Context, E_BinOpr->getLHS(), E_BinOpr->getRHS(), E_BinOpr->getOpcode(), + E_BinOpr->getType(), E_BinOpr->getValueKind(), + E_BinOpr->getObjectKind(), E_BinOpr->getOperatorLoc(), + FPOptionsOverride()); + E = BinaryCopyOpr->getRHS(); + } + + // Change PseudoObjectExpr to a direct call + if (PseudoObjectExpr *PO = dyn_cast<PseudoObjectExpr>(E)) + E = *((PO->semantics_begin()) - 1); + + // Add new Traits to direct call to convert it to new PseudoObjectExpr + // This converts Traits for the function call from under "dispatch" to traits + // of direct function call not under "dispatch". + if (NoContext) { + // Convert StmtResult to a CallExpr before calling ActOnOpenMPCall() + CallExpr *CallExprWithinStmt = dyn_cast<CallExpr>(E); + int NumArgs = CallExprWithinStmt->getNumArgs(); + clang::Expr **Args = CallExprWithinStmt->getArgs(); + ExprResult er = SemaPtr->ActOnOpenMPCall( + CallExprWithinStmt, SemaPtr->SemaRef.getCurScope(), + CallExprWithinStmt->getBeginLoc(), MultiExprArg(Args, NumArgs), + CallExprWithinStmt->getRParenLoc(), static_cast<Expr *>(nullptr)); + E = er.get(); + } + + if (BinaryOp) { + BinaryCopyOpr->setRHS(E); + return BinaryCopyOpr; + } + + return E; +} + +static StmtResult combine2Stmts(ASTContext &context, Stmt *first, + Stmt *second) { + + llvm::SmallVector<Stmt *, 2> newCombinedStmts; + newCombinedStmts.push_back(first); + newCombinedStmts.push_back(second); // Adding foo(); + llvm::ArrayRef<Stmt *> ar(newCombinedStmts); + CompoundStmt *CombinedStmt = CompoundStmt::Create( + context, ar, 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(); +} + +// Get a CapturedStmt with direct call to function. +// If there is a PseudoObjectExpr under the CapturedDecl +// choose the first call under it for the direct call to function +static StmtResult CloneNewCapturedStmtForDirectCall(const ASTContext &Context, + Stmt *StmtP, + SemaOpenMP *SemaPtr, + bool NoContext) { + if (StmtP->getStmtClass() == Stmt::CapturedStmtClass) { + CapturedStmt *AStmt = static_cast<CapturedStmt *>(StmtP); + CapturedDecl *CDecl = AStmt->getCapturedDecl(); + Stmt *S = cast<CapturedStmt>(AStmt)->getCapturedStmt(); + auto *E = dyn_cast<Expr>(S); + E = copy_removePseudoObjectExpr(Context, E, 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 *>(E)); + 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 : AStmt->captures()) + Captures.push_back(capture); + for (auto capture_init : AStmt->capture_inits()) + CaptureInits.push_back(capture_init); + CapturedStmt *NewStmt = CapturedStmt::Create( + Context, AStmt->getCapturedStmt(), AStmt->getCapturedRegionKind(), + Captures, CaptureInits, NewDecl, + const_cast<RecordDecl *>(AStmt->getCapturedRecordDecl())); + + return NewStmt; + } + return static_cast<Stmt *>(NULL); +} + +StmtResult SemaOpenMP::transformDispatchDirective( + OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, + OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { + + StmtResult RetValue; + std::vector<OMPClause *> DependVector; + for (auto C : + OMPExecutableDirective::getClausesOfKind<OMPDependClause>(Clauses)) { + auto C1 = const_cast<OMPDependClause *>(C); + if (OMPDependClause *DependClause = dyn_cast<OMPDependClause>(C1)) { + 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 = + CloneNewCapturedStmtForDirectCall(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 = + CloneNewCapturedStmtForDirectCall(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 NewAStmt = + // CloneNewCapturedStmtForDirectCall(getASTContext(), AStmt, false); + 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 +6219,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 +7463,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 +10776,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 +10821,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/Misc/warning-flags.c b/clang/test/Misc/warning-flags.c index 1fd02440833359..5f3b54d7be8e29 100644 --- a/clang/test/Misc/warning-flags.c +++ b/clang/test/Misc/warning-flags.c @@ -18,7 +18,7 @@ This test serves two purposes: The list of warnings below should NEVER grow. It should gradually shrink to 0. -CHECK: Warnings without flags (61): +CHECK: Warnings without flags (62): CHECK-NEXT: ext_expected_semi_decl_list CHECK-NEXT: ext_missing_whitespace_after_macro_name @@ -65,6 +65,7 @@ CHECK-NEXT: warn_no_constructor_for_refconst CHECK-NEXT: warn_not_compound_assign CHECK-NEXT: warn_objc_property_copy_missing_on_block CHECK-NEXT: warn_objc_protocol_qualifier_missing_id +CHECK-NEXT: warn_omp_dispatch_clause_novariants_nocontext CHECK-NEXT: warn_on_superclass_use CHECK-NEXT: warn_pp_convert_to_positive CHECK-NEXT: warn_pp_expr_overflow 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_v... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/117904 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits