diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h index 71ad24a427105..32a06bc84ad20 100644 --- a/clang/include/clang/AST/OpenACCClause.h +++ b/clang/include/clang/AST/OpenACCClause.h @@ -837,23 +837,43 @@ class OpenACCClauseWithVarList : public OpenACCClauseWithExprs { class OpenACCPrivateClause final : public OpenACCClauseWithVarList, - private llvm::TrailingObjects { + private llvm::TrailingObjects { friend TrailingObjects; OpenACCPrivateClause(SourceLocation BeginLoc, SourceLocation LParenLoc, - ArrayRef VarList, SourceLocation EndLoc) + ArrayRef VarList, + ArrayRef InitRecipes, SourceLocation EndLoc) : OpenACCClauseWithVarList(OpenACCClauseKind::Private, BeginLoc, LParenLoc, EndLoc) { - setExprs(getTrailingObjects(VarList.size()), VarList); + assert(VarList.size() == InitRecipes.size()); + setExprs(getTrailingObjects(VarList.size()), VarList); + llvm::uninitialized_copy(InitRecipes, getTrailingObjects()); } public: static bool classof(const OpenACCClause *C) { return C->getClauseKind() == OpenACCClauseKind::Private; } + // Gets a list of 'made up' `VarDecl` objects that can be used by codegen to + // ensure that we properly initialize each of these variables. + ArrayRef getInitRecipes() { + return ArrayRef{getTrailingObjects(), + getExprs().size()}; + } + + ArrayRef getInitRecipes() const { + return ArrayRef{getTrailingObjects(), + getExprs().size()}; + } + static OpenACCPrivateClause * Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, - ArrayRef VarList, SourceLocation EndLoc); + ArrayRef VarList, ArrayRef InitRecipes, + SourceLocation EndLoc); + + size_t numTrailingObjects(OverloadToken) const { + return getExprs().size(); + } }; class OpenACCFirstPrivateClause final diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index b7e7f5d97bcef..f51045d26e23b 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -241,6 +241,10 @@ class SemaOpenACC : public SemaBase { SourceLocation ClauseLoc, ArrayRef Clauses); + // Creates a VarDecl with a proper default init for the purposes of a + // `private` clause, so it can be used to generate a recipe later. + VarDecl *CreateInitRecipe(const Expr *VarExpr); + public: ComputeConstructInfo &getActiveComputeConstructInfo() { return ActiveComputeConstructInfo; diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp index 60ec10a986e5e..f21e645697656 100644 --- a/clang/lib/AST/OpenACCClause.cpp +++ b/clang/lib/AST/OpenACCClause.cpp @@ -314,14 +314,17 @@ OpenACCTileClause *OpenACCTileClause::Create(const ASTContext &C, return new (Mem) OpenACCTileClause(BeginLoc, LParenLoc, SizeExprs, EndLoc); } -OpenACCPrivateClause *OpenACCPrivateClause::Create(const ASTContext &C, - SourceLocation BeginLoc, - SourceLocation LParenLoc, - ArrayRef VarList, - SourceLocation EndLoc) { - void *Mem = C.Allocate( - OpenACCPrivateClause::totalSizeToAlloc(VarList.size())); - return new (Mem) OpenACCPrivateClause(BeginLoc, LParenLoc, VarList, EndLoc); +OpenACCPrivateClause * +OpenACCPrivateClause::Create(const ASTContext &C, SourceLocation BeginLoc, + SourceLocation LParenLoc, ArrayRef VarList, + ArrayRef InitRecipes, + SourceLocation EndLoc) { + assert(VarList.size() == InitRecipes.size()); + void *Mem = + C.Allocate(OpenACCPrivateClause::totalSizeToAlloc( + VarList.size(), InitRecipes.size())); + return new (Mem) + OpenACCPrivateClause(BeginLoc, LParenLoc, VarList, InitRecipes, EndLoc); } OpenACCFirstPrivateClause *OpenACCFirstPrivateClause::Create( diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index c61450e19f1b6..57834ca4a89ca 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2636,6 +2636,9 @@ void OpenACCClauseProfiler::VisitCollapseClause( void OpenACCClauseProfiler::VisitPrivateClause( const OpenACCPrivateClause &Clause) { VisitClauseWithVarList(Clause); + + for (auto *VD : Clause.getInitRecipes()) + Profiler.VisitDecl(VD); } void OpenACCClauseProfiler::VisitFirstPrivateClause( diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp index 32095cb687e88..907cb5fa11401 100644 --- a/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp @@ -119,7 +119,8 @@ CIRGenFunction::getOpenACCDataOperandInfo(const Expr *e) { if (const auto *memExpr = dyn_cast(curVarExpr)) return {exprLoc, emitMemberExpr(memExpr).getPointer(), exprString, - curVarExpr->getType(), std::move(bounds)}; + curVarExpr->getType().getNonReferenceType().getUnqualifiedType(), + std::move(bounds)}; // Sema has made sure that only 4 types of things can get here, array // subscript, array section, member expr, or DRE to a var decl (or the @@ -127,5 +128,6 @@ CIRGenFunction::getOpenACCDataOperandInfo(const Expr *e) { // right. const auto *dre = cast(curVarExpr); return {exprLoc, emitDeclRefLValue(dre).getPointer(), exprString, - curVarExpr->getType(), std::move(bounds)}; + curVarExpr->getType().getNonReferenceType().getUnqualifiedType(), + std::move(bounds)}; } diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp index 5a6e66550c0bd..bb9054a68b5c7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp @@ -358,8 +358,8 @@ class OpenACCClauseCIREmitter final template RecipeTy getOrCreateRecipe(ASTContext &astCtx, const Expr *varRef, - DeclContext *dc, QualType baseType, - mlir::Value mainOp) { + const VarDecl *varRecipe, DeclContext *dc, + QualType baseType, mlir::Value mainOp) { mlir::ModuleOp mod = builder.getBlock()->getParent()->getParentOfType(); @@ -398,12 +398,6 @@ class OpenACCClauseCIREmitter final auto recipe = RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType()); - // Magic-up a var-decl so we can use normal init/destruction operations for - // a variable declaration. - VarDecl &tempDecl = *VarDecl::Create( - astCtx, dc, varRef->getBeginLoc(), varRef->getBeginLoc(), - &astCtx.Idents.get("openacc.private.init"), baseType, - astCtx.getTrivialTypeSourceInfo(baseType), SC_Auto); CIRGenFunction::AutoVarEmission tempDeclEmission{ CIRGenFunction::AutoVarEmission::invalid()}; @@ -422,9 +416,11 @@ class OpenACCClauseCIREmitter final "OpenACC non-private recipe init"); } - tempDeclEmission = - cgf.emitAutoVarAlloca(tempDecl, builder.saveInsertionPoint()); - cgf.emitAutoVarInit(tempDeclEmission); + if (varRecipe) { + tempDeclEmission = + cgf.emitAutoVarAlloca(*varRecipe, builder.saveInsertionPoint()); + cgf.emitAutoVarInit(tempDeclEmission); + } mlir::acc::YieldOp::create(builder, locEnd); } @@ -439,7 +435,7 @@ class OpenACCClauseCIREmitter final } // Destroy section (doesn't currently exist). - if (tempDecl.needsDestruction(cgf.getContext())) { + if (varRecipe && varRecipe->needsDestruction(cgf.getContext())) { llvm::SmallVector argsTys{mainOp.getType()}; llvm::SmallVector argsLocs{loc}; mlir::Block *block = builder.createBlock(&recipe.getDestroyRegion(), @@ -450,7 +446,7 @@ class OpenACCClauseCIREmitter final mlir::Type elementTy = mlir::cast(mainOp.getType()).getPointee(); Address addr{block->getArgument(0), elementTy, - cgf.getContext().getDeclAlign(&tempDecl)}; + cgf.getContext().getDeclAlign(varRecipe)}; cgf.emitDestroy(addr, baseType, cgf.getDestroyer(QualType::DK_cxx_destructor)); @@ -1080,9 +1076,10 @@ class OpenACCClauseCIREmitter final void VisitPrivateClause(const OpenACCPrivateClause &clause) { if constexpr (isOneOfTypes) { - for (const Expr *var : clause.getVarList()) { + for (const auto [varExpr, varRecipe] : + llvm::zip_equal(clause.getVarList(), clause.getInitRecipes())) { CIRGenFunction::OpenACCDataOperandInfo opInfo = - cgf.getOpenACCDataOperandInfo(var); + cgf.getOpenACCDataOperandInfo(varExpr); auto privateOp = mlir::acc::PrivateOp::create( builder, opInfo.beginLoc, opInfo.varValue, /*structured=*/true, /*implicit=*/false, opInfo.name, opInfo.bounds); @@ -1091,8 +1088,9 @@ class OpenACCClauseCIREmitter final { mlir::OpBuilder::InsertionGuard guardCase(builder); auto recipe = getOrCreateRecipe( - cgf.getContext(), var, Decl::castToDeclContext(cgf.curFuncDecl), - opInfo.baseType, privateOp.getResult()); + cgf.getContext(), varExpr, varRecipe, + Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType, + privateOp.getResult()); // TODO: OpenACC: The dialect is going to change in the near future to // have these be on a different operation, so when that changes, we // probably need to change these here. diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index 8bfea623103e4..8f32817aec48f 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -17,6 +17,7 @@ #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/OpenACCKinds.h" #include "clang/Basic/SourceManager.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/Scope.h" #include "clang/Sema/Sema.h" #include "llvm/ADT/StringExtras.h" @@ -2552,3 +2553,50 @@ ExprResult SemaOpenACC::ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) { return BuildOpenACCAsteriskSizeExpr(AsteriskLoc); } + +VarDecl *SemaOpenACC::CreateInitRecipe(const Expr *VarExpr) { + // Strip off any array subscripts/array section exprs to get to the type of + // the variable. + while (isa_and_present(VarExpr)) { + if (const auto *AS = dyn_cast(VarExpr)) + VarExpr = AS->getBase()->IgnoreParenImpCasts(); + else if (const auto *Sub = dyn_cast(VarExpr)) + VarExpr = Sub->getBase()->IgnoreParenImpCasts(); + } + + // If for some reason the expression is invalid, or this is dependent, just + // fill in with nullptr. We'll count on TreeTransform to make this if + // necessary. + if (!VarExpr || VarExpr->getType()->isDependentType()) + return nullptr; + + QualType VarTy = + VarExpr->getType().getNonReferenceType().getUnqualifiedType(); + + VarDecl *Recipe = VarDecl::Create( + getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(), + VarExpr->getBeginLoc(), + &getASTContext().Idents.get("openacc.private.init"), VarTy, + getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto); + + ExprResult Init; + + { + // Trap errors so we don't get weird ones here. If we can't init, we'll just + // swallow the errors. + Sema::TentativeAnalysisScope Trap{SemaRef}; + InitializedEntity Entity = InitializedEntity::InitializeVariable(Recipe); + InitializationKind Kind = + InitializationKind::CreateDefault(Recipe->getLocation()); + + InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, {}); + Init = InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, {}); + } + + if (Init.get()) { + Recipe->setInit(Init.get()); + Recipe->setInitStyle(VarDecl::CallInit); + } + + return Recipe; +} diff --git a/clang/lib/Sema/SemaOpenACCClause.cpp b/clang/lib/Sema/SemaOpenACCClause.cpp index b54a0124e9495..9f1a6177b945c 100644 --- a/clang/lib/Sema/SemaOpenACCClause.cpp +++ b/clang/lib/Sema/SemaOpenACCClause.cpp @@ -795,9 +795,15 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitPrivateClause( // really isn't anything to do here. GCC does some duplicate-finding, though // it isn't apparent in the standard where this is justified. - return OpenACCPrivateClause::Create(Ctx, Clause.getBeginLoc(), - Clause.getLParenLoc(), - Clause.getVarList(), Clause.getEndLoc()); + llvm::SmallVector InitRecipes; + + // Assemble the recipes list. + for (const Expr *VarExpr : Clause.getVarList()) + InitRecipes.push_back(SemaRef.CreateInitRecipe(VarExpr)); + + return OpenACCPrivateClause::Create( + Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(), + InitRecipes, Clause.getEndLoc()); } OpenACCClause *SemaOpenACCClauseVisitor::VisitFirstPrivateClause( diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index c7428d1a02345..7c9755f301552 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -11730,20 +11730,26 @@ class OpenACCClauseTransform final SemaOpenACC::OpenACCParsedClause &ParsedClause; OpenACCClause *NewClause = nullptr; + ExprResult VisitVar(Expr *VarRef) { + ExprResult Res = Self.TransformExpr(VarRef); + + if (!Res.isUsable()) + return Res; + + Res = Self.getSema().OpenACC().ActOnVar(ParsedClause.getDirectiveKind(), + ParsedClause.getClauseKind(), + Res.get()); + + return Res; + } + llvm::SmallVector VisitVarList(ArrayRef VarList) { llvm::SmallVector InstantiatedVarList; for (Expr *CurVar : VarList) { - ExprResult Res = Self.TransformExpr(CurVar); - - if (!Res.isUsable()) - continue; + ExprResult VarRef = VisitVar(CurVar); - Res = Self.getSema().OpenACC().ActOnVar(ParsedClause.getDirectiveKind(), - ParsedClause.getClauseKind(), - Res.get()); - - if (Res.isUsable()) - InstantiatedVarList.push_back(Res.get()); + if (VarRef.isUsable()) + InstantiatedVarList.push_back(VarRef.get()); } return InstantiatedVarList; @@ -11870,12 +11876,31 @@ void OpenACCClauseTransform::VisitNumGangsClause( template void OpenACCClauseTransform::VisitPrivateClause( const OpenACCPrivateClause &C) { - ParsedClause.setVarListDetails(VisitVarList(C.getVarList()), + llvm::SmallVector InstantiatedVarList; + llvm::SmallVector InitRecipes; + + for (const auto [RefExpr, InitRecipe] : + llvm::zip(C.getVarList(), C.getInitRecipes())) { + ExprResult VarRef = VisitVar(RefExpr); + + if (VarRef.isUsable()) { + InstantiatedVarList.push_back(VarRef.get()); + + // We only have to create a new one if it is dependent, and Sema won't + // make one of these unless the type is non-dependent. + if (InitRecipe) + InitRecipes.push_back(InitRecipe); + else + InitRecipes.push_back( + Self.getSema().OpenACC().CreateInitRecipe(VarRef.get())); + } + } + ParsedClause.setVarListDetails(InstantiatedVarList, OpenACCModifierKind::Invalid); NewClause = OpenACCPrivateClause::Create( Self.getSema().getASTContext(), ParsedClause.getBeginLoc(), - ParsedClause.getLParenLoc(), ParsedClause.getVarList(), + ParsedClause.getLParenLoc(), ParsedClause.getVarList(), InitRecipes, ParsedClause.getEndLoc()); } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 682d26394c0d5..753b25fb7dade 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -12851,8 +12851,13 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { case OpenACCClauseKind::Private: { SourceLocation LParenLoc = readSourceLocation(); llvm::SmallVector VarList = readOpenACCVarList(); + + llvm::SmallVector RecipeList; + for (unsigned I = 0; I < VarList.size(); ++I) + RecipeList.push_back(readDeclAs()); + return OpenACCPrivateClause::Create(getContext(), BeginLoc, LParenLoc, - VarList, EndLoc); + VarList, RecipeList, EndLoc); } case OpenACCClauseKind::Host: { SourceLocation LParenLoc = readSourceLocation(); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index a6957e54b66f1..7c637c0d00369 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -8738,6 +8738,9 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { const auto *PC = cast(C); writeSourceLocation(PC->getLParenLoc()); writeOpenACCVarList(PC); + + for (VarDecl *VD : PC->getInitRecipes()) + AddDeclRef(VD); return; } case OpenACCClauseKind::Host: { diff --git a/clang/test/CIR/CodeGenOpenACC/combined-private-clause.cpp b/clang/test/CIR/CodeGenOpenACC/combined-private-clause.cpp index 3306c55b4a8e7..0b58bae9239b2 100644 --- a/clang/test/CIR/CodeGenOpenACC/combined-private-clause.cpp +++ b/clang/test/CIR/CodeGenOpenACC/combined-private-clause.cpp @@ -43,7 +43,24 @@ struct HasDtor { // // CHECK-NEXT: acc.private.recipe @privatization__ZTSA5_14NonDefaultCtor : !cir.ptr> init { // CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr> {{.*}}): -// CHECK-NEXT: cir.alloca !cir.array, !cir.ptr>, ["openacc.private.init"] +// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array, !cir.ptr>, ["openacc.private.init", init] +// CHECK-NEXT: %[[LAST_IDX:.*]] = cir.const #cir.int<5> : !u64i +// CHECK-NEXT: %[[ARRPTR:.*]] = cir.cast(array_to_ptrdecay, %[[ALLOCA]] : !cir.ptr>), !cir.ptr +// CHECK-NEXT: %[[LAST_ELEM:.*]] = cir.ptr_stride(%[[ARRPTR]] : !cir.ptr, %[[LAST_IDX]] : !u64i), !cir.ptr +// CHECK-NEXT: %[[ITR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["__array_idx"] +// CHECK-NEXT: cir.store %[[ARRPTR]], %[[ITR]] : !cir.ptr, !cir.ptr> +// CHECK-NEXT: cir.do { +// CHECK-NEXT: %[[ELEM_LOAD:.*]] = cir.load %[[ITR]] : !cir.ptr>, !cir.ptr +// CHECK-NEXT: cir.call @_ZN14NonDefaultCtorC1Ev(%[[ELEM_LOAD]]) : (!cir.ptr) -> () +// CHECK-NEXT: %[[ONE_CONST:.*]] = cir.const #cir.int<1> : !u64i +// CHECK-NEXT: %[[ELEM:.*]] = cir.ptr_stride(%[[ELEM_LOAD]] : !cir.ptr, %[[ONE_CONST]] : !u64i), !cir.ptr +// CHECK-NEXT: cir.store %[[ELEM]], %[[ITR]] : !cir.ptr, !cir.ptr> +// CHECK-NEXT: cir.yield +// CHECK-NEXT: } while { +// CHECK-NEXT: %[[ELEM_LOAD:.*]] = cir.load %[[ITR]] : !cir.ptr>, !cir.ptr +// CHECK-NEXT: %[[CMP:.*]] = cir.cmp(ne, %[[ELEM_LOAD]], %[[LAST_ELEM]]) : !cir.ptr, !cir.bool +// CHECK-NEXT: cir.condition(%[[CMP]]) +// CHECK-NEXT: } // CHECK-NEXT: acc.yield // CHECK-NEXT: } // @@ -83,7 +100,8 @@ struct HasDtor { // // CHECK-NEXT: acc.private.recipe @privatization__ZTS14NonDefaultCtor : !cir.ptr init { // CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr {{.*}}): -// CHECK-NEXT: cir.alloca !rec_NonDefaultCtor, !cir.ptr, ["openacc.private.init"] +// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !rec_NonDefaultCtor, !cir.ptr, ["openacc.private.init", init] +// CHECK-NEXT: cir.call @_ZN14NonDefaultCtorC1Ev(%[[ALLOCA]]) : (!cir.ptr) -> () // CHECK-NEXT: acc.yield // CHECK-NEXT: } // diff --git a/clang/test/CIR/CodeGenOpenACC/compute-private-clause-templates.cpp b/clang/test/CIR/CodeGenOpenACC/compute-private-clause-templates.cpp new file mode 100644 index 0000000000000..659e84bc892b6 --- /dev/null +++ b/clang/test/CIR/CodeGenOpenACC/compute-private-clause-templates.cpp @@ -0,0 +1,79 @@ +// RUN: %clang_cc1 -fopenacc -triple x86_64-linux-gnu -Wno-openacc-self-if-potential-conflict -emit-cir -fclangir -triple x86_64-linux-pc %s -o - | FileCheck %s + +struct CopyConstruct { + CopyConstruct() = default; + CopyConstruct(const CopyConstruct&); +}; + +struct NonDefaultCtor { + NonDefaultCtor(); +}; + +struct HasDtor { + ~HasDtor(); +}; + +// CHECK: acc.private.recipe @privatization__ZTSi : !cir.ptr init { +// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr {{.*}}): +// CHECK-NEXT: cir.alloca !s32i, !cir.ptr, ["openacc.private.init"] +// CHECK-NEXT: acc.yield +// CHECK-NEXT: } +// +// CHECK-NEXT: acc.private.recipe @privatization__ZTS7HasDtor : !cir.ptr init { +// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr {{.*}}): +// CHECK-NEXT: cir.alloca !rec_HasDtor, !cir.ptr, ["openacc.private.init"] +// CHECK-NEXT: acc.yield +// CHECK-NEXT: } destroy { +// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr {{.*}}): +// CHECK-NEXT: cir.call @_ZN7HasDtorD1Ev(%[[ARG]]) nothrow : (!cir.ptr) -> () +// CHECK-NEXT: acc.yield +// CHECK-NEXT: } +// +// CHECK-NEXT: acc.private.recipe @privatization__ZTS14NonDefaultCtor : !cir.ptr init { +// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr {{.*}}): +// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !rec_NonDefaultCtor, !cir.ptr, ["openacc.private.init", init] +// CHECK-NEXT: cir.call @_ZN14NonDefaultCtorC1Ev(%[[ALLOCA]]) : (!cir.ptr) -> () +// CHECK-NEXT: acc.yield +// CHECK-NEXT: } +// +// CHECK-NEXT: acc.private.recipe @privatization__ZTS13CopyConstruct : !cir.ptr init { +// CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr {{.*}}): +// CHECK-NEXT: cir.alloca !rec_CopyConstruct, !cir.ptr, ["openacc.private.init"] +// CHECK-NEXT: acc.yield +// CHECK-NEXT: } + +template +void dependent_version(const T &cc, const U &ndc, const V &dtor, const W &someInt) { + // CHECK: cir.func {{.*}}@_Z17dependent_versionI13CopyConstruct14NonDefaultCtor7HasDtoriEvRKT_RKT0_RKT1_RKT2_(%[[ARG0:.*]]: !cir.ptr {{.*}}, %[[ARG1:.*]]: !cir.ptr {{.*}}, %[[ARG2:.*]]: !cir.ptr {{.*}}, %[[ARG3:.*]]: !cir.ptr {{.*}}) { + // CHECK-NEXT: %[[CC:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["cc", init, const] + // CHECK-NEXT: %[[NDC:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["ndc", init, const] + // CHECK-NEXT: %[[DTOR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["dtor", init, const] + // CHECK-NEXT: %[[SOMEINT:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["someInt", init, const] + // % 3 = cir.alloca !cir.ptr, !cir.ptr>, ["someInt", init, const] + +#pragma acc parallel private(cc, ndc, dtor, someInt) + ; + // CHECK: %[[PRIV_LOAD:.*]] = cir.load %[[CC]] : !cir.ptr>, !cir.ptr + // CHECK-NEXT: %[[PRIVATE1:.*]] = acc.private varPtr(%[[PRIV_LOAD]] : !cir.ptr) -> !cir.ptr {name = "cc"} + // CHECK-NEXT: %[[PRIV_LOAD:.*]] = cir.load %[[NDC]] : !cir.ptr>, !cir.ptr + // CHECK-NEXT: %[[PRIVATE2:.*]] = acc.private varPtr(%[[PRIV_LOAD]] : !cir.ptr) -> !cir.ptr {name = "ndc"} + // CHECK-NEXT: %[[PRIV_LOAD:.*]] = cir.load %[[DTOR]] : !cir.ptr>, !cir.ptr + // CHECK-NEXT: %[[PRIVATE3:.*]] = acc.private varPtr(%[[PRIV_LOAD]] : !cir.ptr) -> !cir.ptr {name = "dtor"} + // CHECK-NEXT: %[[PRIV_LOAD:.*]] = cir.load %[[SOMEINT]] : !cir.ptr>, !cir.ptr + // CHECK-NEXT: %[[PRIVATE4:.*]] = acc.private varPtr(%[[PRIV_LOAD]] : !cir.ptr) -> !cir.ptr {name = "someInt"} + + // CHECK-NEXT: acc.parallel private(@privatization__ZTS13CopyConstruct -> %[[PRIVATE1]] : !cir.ptr, + // CHECK-SAME: @privatization__ZTS14NonDefaultCtor -> %[[PRIVATE2]] : !cir.ptr, + // CHECK-SAME: @privatization__ZTS7HasDtor -> %[[PRIVATE3]] : !cir.ptr, + // CHECK-SAME: @privatization__ZTSi -> %[[PRIVATE4]] : !cir.ptr) { + // CHECK-NEXT: acc.yield + // CHECK-NEXT: } loc +} + +void use() { + CopyConstruct cc; + NonDefaultCtor ndc; + HasDtor dtor; + int i; + dependent_version(cc, ndc, dtor, i); +} diff --git a/clang/test/CIR/CodeGenOpenACC/compute-private-clause.cpp b/clang/test/CIR/CodeGenOpenACC/compute-private-clause.cpp index a204f41ef7dbe..940bf53e7ece4 100644 --- a/clang/test/CIR/CodeGenOpenACC/compute-private-clause.cpp +++ b/clang/test/CIR/CodeGenOpenACC/compute-private-clause.cpp @@ -43,7 +43,24 @@ struct HasDtor { // // CHECK-NEXT: acc.private.recipe @privatization__ZTSA5_14NonDefaultCtor : !cir.ptr> init { // CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr> {{.*}}): -// CHECK-NEXT: cir.alloca !cir.array, !cir.ptr>, ["openacc.private.init"] +// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array, !cir.ptr>, ["openacc.private.init", init] +// CHECK-NEXT: %[[LAST_IDX:.*]] = cir.const #cir.int<5> : !u64i +// CHECK-NEXT: %[[ARRPTR:.*]] = cir.cast(array_to_ptrdecay, %[[ALLOCA]] : !cir.ptr>), !cir.ptr +// CHECK-NEXT: %[[LAST_ELEM:.*]] = cir.ptr_stride(%[[ARRPTR]] : !cir.ptr, %[[LAST_IDX]] : !u64i), !cir.ptr +// CHECK-NEXT: %[[ITR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["__array_idx"] +// CHECK-NEXT: cir.store %[[ARRPTR]], %[[ITR]] : !cir.ptr, !cir.ptr> +// CHECK-NEXT: cir.do { +// CHECK-NEXT: %[[ELEM_LOAD:.*]] = cir.load %[[ITR]] : !cir.ptr>, !cir.ptr +// CHECK-NEXT: cir.call @_ZN14NonDefaultCtorC1Ev(%[[ELEM_LOAD]]) : (!cir.ptr) -> () +// CHECK-NEXT: %[[ONE_CONST:.*]] = cir.const #cir.int<1> : !u64i +// CHECK-NEXT: %[[ELEM:.*]] = cir.ptr_stride(%[[ELEM_LOAD]] : !cir.ptr, %[[ONE_CONST]] : !u64i), !cir.ptr +// CHECK-NEXT: cir.store %[[ELEM]], %[[ITR]] : !cir.ptr, !cir.ptr> +// CHECK-NEXT: cir.yield +// CHECK-NEXT: } while { +// CHECK-NEXT: %[[ELEM_LOAD:.*]] = cir.load %[[ITR]] : !cir.ptr>, !cir.ptr +// CHECK-NEXT: %[[CMP:.*]] = cir.cmp(ne, %[[ELEM_LOAD]], %[[LAST_ELEM]]) : !cir.ptr, !cir.bool +// CHECK-NEXT: cir.condition(%[[CMP]]) +// CHECK-NEXT: } // CHECK-NEXT: acc.yield // CHECK-NEXT: } // @@ -83,7 +100,8 @@ struct HasDtor { // // CHECK-NEXT: acc.private.recipe @privatization__ZTS14NonDefaultCtor : !cir.ptr init { // CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr {{.*}}): -// CHECK-NEXT: cir.alloca !rec_NonDefaultCtor, !cir.ptr, ["openacc.private.init"] +// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !rec_NonDefaultCtor, !cir.ptr, ["openacc.private.init", init] +// CHECK-NEXT: cir.call @_ZN14NonDefaultCtorC1Ev(%[[ALLOCA]]) : (!cir.ptr) -> () // CHECK-NEXT: acc.yield // CHECK-NEXT: } // diff --git a/clang/test/CIR/CodeGenOpenACC/loop-private-clause.cpp b/clang/test/CIR/CodeGenOpenACC/loop-private-clause.cpp index 384496bf87945..435a0c9157603 100644 --- a/clang/test/CIR/CodeGenOpenACC/loop-private-clause.cpp +++ b/clang/test/CIR/CodeGenOpenACC/loop-private-clause.cpp @@ -43,7 +43,24 @@ struct HasDtor { // // CHECK-NEXT: acc.private.recipe @privatization__ZTSA5_14NonDefaultCtor : !cir.ptr> init { // CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr> {{.*}}): -// CHECK-NEXT: cir.alloca !cir.array, !cir.ptr>, ["openacc.private.init"] +// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !cir.array, !cir.ptr>, ["openacc.private.init", init] +// CHECK-NEXT: %[[LAST_IDX:.*]] = cir.const #cir.int<5> : !u64i +// CHECK-NEXT: %[[ARRPTR:.*]] = cir.cast(array_to_ptrdecay, %[[ALLOCA]] : !cir.ptr>), !cir.ptr +// CHECK-NEXT: %[[LAST_ELEM:.*]] = cir.ptr_stride(%[[ARRPTR]] : !cir.ptr, %[[LAST_IDX]] : !u64i), !cir.ptr +// CHECK-NEXT: %[[ITR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["__array_idx"] +// CHECK-NEXT: cir.store %[[ARRPTR]], %[[ITR]] : !cir.ptr, !cir.ptr> +// CHECK-NEXT: cir.do { +// CHECK-NEXT: %[[ELEM_LOAD:.*]] = cir.load %[[ITR]] : !cir.ptr>, !cir.ptr +// CHECK-NEXT: cir.call @_ZN14NonDefaultCtorC1Ev(%[[ELEM_LOAD]]) : (!cir.ptr) -> () +// CHECK-NEXT: %[[ONE_CONST:.*]] = cir.const #cir.int<1> : !u64i +// CHECK-NEXT: %[[ELEM:.*]] = cir.ptr_stride(%[[ELEM_LOAD]] : !cir.ptr, %[[ONE_CONST]] : !u64i), !cir.ptr +// CHECK-NEXT: cir.store %[[ELEM]], %[[ITR]] : !cir.ptr, !cir.ptr> +// CHECK-NEXT: cir.yield +// CHECK-NEXT: } while { +// CHECK-NEXT: %[[ELEM_LOAD:.*]] = cir.load %[[ITR]] : !cir.ptr>, !cir.ptr +// CHECK-NEXT: %[[CMP:.*]] = cir.cmp(ne, %[[ELEM_LOAD]], %[[LAST_ELEM]]) : !cir.ptr, !cir.bool +// CHECK-NEXT: cir.condition(%[[CMP]]) +// CHECK-NEXT: } // CHECK-NEXT: acc.yield // CHECK-NEXT: } // @@ -83,7 +100,8 @@ struct HasDtor { // // CHECK-NEXT: acc.private.recipe @privatization__ZTS14NonDefaultCtor : !cir.ptr init { // CHECK-NEXT: ^bb0(%[[ARG:.*]]: !cir.ptr {{.*}}): -// CHECK-NEXT: cir.alloca !rec_NonDefaultCtor, !cir.ptr, ["openacc.private.init"] +// CHECK-NEXT: %[[ALLOCA:.*]] = cir.alloca !rec_NonDefaultCtor, !cir.ptr, ["openacc.private.init", init] +// CHECK-NEXT: cir.call @_ZN14NonDefaultCtorC1Ev(%[[ALLOCA]]) : (!cir.ptr) -> () // CHECK-NEXT: acc.yield // CHECK-NEXT: } // diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 9412d9735ef82..9c2724f17cf8b 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2880,6 +2880,8 @@ void OpenACCClauseEnqueue::VisitTileClause(const OpenACCTileClause &C) { void OpenACCClauseEnqueue::VisitPrivateClause(const OpenACCPrivateClause &C) { VisitVarList(C); + for (VarDecl *V : C.getInitRecipes()) + Visitor.AddDecl(V); } void OpenACCClauseEnqueue::VisitHostClause(const OpenACCHostClause &C) {