diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h index 2f4aba1cdcd90..081244fe0efb6 100644 --- a/clang/include/clang/AST/OpenACCClause.h +++ b/clang/include/clang/AST/OpenACCClause.h @@ -835,19 +835,40 @@ class OpenACCClauseWithVarList : public OpenACCClauseWithExprs { ArrayRef getVarList() const { return getExprs(); } }; +// Represents all the data needed for recipe generation. The declaration and +// init are stored separately, because in the case of subscripts, we do the +// alloca at the level of the base, and the init at the element level. +struct OpenACCPrivateRecipe { + VarDecl *AllocaDecl; + Expr *InitExpr; + + OpenACCPrivateRecipe(VarDecl *A, Expr *I) : AllocaDecl(A), InitExpr(I) { + assert(!AllocaDecl || AllocaDecl->getInit() == nullptr); + } + + bool isSet() const { return AllocaDecl; } + + static OpenACCPrivateRecipe Empty() { + return OpenACCPrivateRecipe(nullptr, nullptr); + } +}; + class OpenACCPrivateClause final : public OpenACCClauseWithVarList, - private llvm::TrailingObjects { + private llvm::TrailingObjects { friend TrailingObjects; OpenACCPrivateClause(SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef VarList, - ArrayRef InitRecipes, SourceLocation EndLoc) + ArrayRef InitRecipes, + SourceLocation EndLoc) : OpenACCClauseWithVarList(OpenACCClauseKind::Private, BeginLoc, LParenLoc, EndLoc) { assert(VarList.size() == InitRecipes.size()); setExprs(getTrailingObjects(VarList.size()), VarList); - llvm::uninitialized_copy(InitRecipes, getTrailingObjects()); + llvm::uninitialized_copy(InitRecipes, + getTrailingObjects()); } public: @@ -856,19 +877,19 @@ class OpenACCPrivateClause final } // 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() { + return ArrayRef{ + getTrailingObjects(), getExprs().size()}; } - ArrayRef getInitRecipes() const { - 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, ArrayRef InitRecipes, + ArrayRef VarList, ArrayRef InitRecipes, SourceLocation EndLoc); size_t numTrailingObjects(OverloadToken) const { @@ -879,11 +900,20 @@ class OpenACCPrivateClause final // A 'pair' to stand in for the recipe. RecipeDecl is the main declaration, and // InitFromTemporary is the 'temp' declaration we put in to be 'copied from'. struct OpenACCFirstPrivateRecipe { - VarDecl *RecipeDecl, *InitFromTemporary; - OpenACCFirstPrivateRecipe(VarDecl *R, VarDecl *T) - : RecipeDecl(R), InitFromTemporary(T) {} - OpenACCFirstPrivateRecipe(std::pair p) - : RecipeDecl(p.first), InitFromTemporary(p.second) {} + VarDecl *AllocaDecl; + Expr *InitExpr; + VarDecl *InitFromTemporary; + OpenACCFirstPrivateRecipe(VarDecl *A, Expr *I, VarDecl *T) + : AllocaDecl(A), InitExpr(I), InitFromTemporary(T) { + assert(!AllocaDecl || AllocaDecl->getInit() == nullptr); + assert(!InitFromTemporary || InitFromTemporary->getInit() == nullptr); + } + + bool isSet() const { return AllocaDecl; } + + static OpenACCFirstPrivateRecipe Empty() { + return OpenACCFirstPrivateRecipe(nullptr, nullptr, nullptr); + } }; class OpenACCFirstPrivateClause final @@ -1253,8 +1283,18 @@ class OpenACCCreateClause final // A structure to stand in for the recipe on a reduction. RecipeDecl is the // 'main' declaration used for initializaiton, which is fixed. struct OpenACCReductionRecipe { - VarDecl *RecipeDecl; + VarDecl *AllocaDecl; + Expr *InitExpr; // TODO: OpenACC: this should eventually have the operations here too. + + OpenACCReductionRecipe(VarDecl *A, Expr *I) : AllocaDecl(A), InitExpr(I) { + assert(!AllocaDecl || AllocaDecl->getInit() == nullptr); + } + + bool isSet() const { return AllocaDecl; } + static OpenACCReductionRecipe Empty() { + return OpenACCReductionRecipe(nullptr, nullptr); + } }; class OpenACCReductionClause final diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index 42e86582c3b06..09fdf75fbbd09 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_SEMA_SEMAOPENACC_H #include "clang/AST/DeclGroup.h" +#include "clang/AST/OpenACCClause.h" #include "clang/AST/StmtOpenACC.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/OpenACCKinds.h" @@ -237,21 +238,11 @@ class SemaOpenACC : public SemaBase { SourceLocation ClauseLoc, ArrayRef Clauses); - // Creates a VarDecl with a proper default init for the purposes of a - // `private`/'firstprivate'/'reduction' clause, so it can be used to generate - // a recipe later. - // The first entry is the recipe itself, the second is any required - // 'temporary' created for the init (in the case of a copy), such as with - // firstprivate. - std::pair CreateInitRecipe(OpenACCClauseKind CK, - const Expr *VarExpr) { - assert(CK != OpenACCClauseKind::Reduction); - return CreateInitRecipe(CK, OpenACCReductionOperator::Invalid, VarExpr); - } - std::pair - CreateInitRecipe(OpenACCClauseKind CK, - OpenACCReductionOperator ReductionOperator, - const Expr *VarExpr); + OpenACCPrivateRecipe CreatePrivateInitRecipe(const Expr *VarExpr); + OpenACCFirstPrivateRecipe CreateFirstPrivateInitRecipe(const Expr *VarExpr); + OpenACCReductionRecipe + CreateReductionInitRecipe(OpenACCReductionOperator ReductionOperator, + const Expr *VarExpr); public: ComputeConstructInfo &getActiveComputeConstructInfo() { diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp index 9a9ede467331e..6c4bc7c274eaa 100644 --- a/clang/lib/AST/OpenACCClause.cpp +++ b/clang/lib/AST/OpenACCClause.cpp @@ -317,11 +317,11 @@ OpenACCTileClause *OpenACCTileClause::Create(const ASTContext &C, OpenACCPrivateClause * OpenACCPrivateClause::Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef VarList, - ArrayRef InitRecipes, + ArrayRef InitRecipes, SourceLocation EndLoc) { assert(VarList.size() == InitRecipes.size()); - void *Mem = - C.Allocate(OpenACCPrivateClause::totalSizeToAlloc( + void *Mem = C.Allocate( + OpenACCPrivateClause::totalSizeToAlloc( VarList.size(), InitRecipes.size())); return new (Mem) OpenACCPrivateClause(BeginLoc, LParenLoc, VarList, InitRecipes, EndLoc); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 2035fa7635f2a..1bc21062203cb 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2636,8 +2636,11 @@ void OpenACCClauseProfiler::VisitPrivateClause( const OpenACCPrivateClause &Clause) { VisitClauseWithVarList(Clause); - for (auto *VD : Clause.getInitRecipes()) - Profiler.VisitDecl(VD); + for (auto &Recipe : Clause.getInitRecipes()) { + Profiler.VisitDecl(Recipe.AllocaDecl); + if (Recipe.InitExpr) + Profiler.VisitExpr(Recipe.InitExpr); + } } void OpenACCClauseProfiler::VisitFirstPrivateClause( @@ -2645,7 +2648,9 @@ void OpenACCClauseProfiler::VisitFirstPrivateClause( VisitClauseWithVarList(Clause); for (auto &Recipe : Clause.getInitRecipes()) { - Profiler.VisitDecl(Recipe.RecipeDecl); + Profiler.VisitDecl(Recipe.AllocaDecl); + if (Recipe.InitExpr) + Profiler.VisitExpr(Recipe.InitExpr); Profiler.VisitDecl(Recipe.InitFromTemporary); } } @@ -2750,11 +2755,13 @@ void OpenACCClauseProfiler::VisitReductionClause( VisitClauseWithVarList(Clause); for (auto &Recipe : Clause.getRecipes()) { - Profiler.VisitDecl(Recipe.RecipeDecl); + Profiler.VisitDecl(Recipe.AllocaDecl); + if (Recipe.InitExpr) + Profiler.VisitExpr(Recipe.InitExpr); // TODO: OpenACC: Make sure we remember to update this when we figure out // what we're adding for the operation recipe, in the meantime, a static // assert will make sure we don't add something. - static_assert(sizeof(OpenACCReductionRecipe) == sizeof(int *)); + static_assert(sizeof(OpenACCReductionRecipe) == 2 * sizeof(int *)); } } diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp index 41834da8a86c3..0022befa3b562 100644 --- a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp @@ -1280,10 +1280,16 @@ class OpenACCClauseCIREmitter final { mlir::OpBuilder::InsertionGuard guardCase(builder); + // TODO: OpenACC: At the moment this is a bit of a hacky way of doing + // this, and won't work when we get to bounds/etc. Do this for now to + // limit the scope of this refactor. + VarDecl *allocaDecl = varRecipe.AllocaDecl; + allocaDecl->setInit(varRecipe.InitExpr); + allocaDecl->setInitStyle(VarDecl::CallInit); + auto recipe = getOrCreateRecipe( - cgf.getContext(), varExpr, varRecipe, /*temporary=*/nullptr, + cgf.getContext(), varExpr, allocaDecl, /*temporary=*/nullptr, OpenACCReductionOperator::Invalid, - Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType, privateOp.getResult()); // TODO: OpenACC: The dialect is going to change in the near future to @@ -1316,8 +1322,15 @@ class OpenACCClauseCIREmitter final { mlir::OpBuilder::InsertionGuard guardCase(builder); + // TODO: OpenACC: At the moment this is a bit of a hacky way of doing + // this, and won't work when we get to bounds/etc. Do this for now to + // limit the scope of this refactor. + VarDecl *allocaDecl = varRecipe.AllocaDecl; + allocaDecl->setInit(varRecipe.InitExpr); + allocaDecl->setInitStyle(VarDecl::CallInit); + auto recipe = getOrCreateRecipe( - cgf.getContext(), varExpr, varRecipe.RecipeDecl, + cgf.getContext(), varExpr, allocaDecl, varRecipe.InitFromTemporary, OpenACCReductionOperator::Invalid, Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType, firstPrivateOp.getResult()); @@ -1353,9 +1366,15 @@ class OpenACCClauseCIREmitter final { mlir::OpBuilder::InsertionGuard guardCase(builder); + // TODO: OpenACC: At the moment this is a bit of a hacky way of doing + // this, and won't work when we get to bounds/etc. Do this for now to + // limit the scope of this refactor. + VarDecl *allocaDecl = varRecipe.AllocaDecl; + allocaDecl->setInit(varRecipe.InitExpr); + allocaDecl->setInitStyle(VarDecl::CallInit); auto recipe = getOrCreateRecipe( - cgf.getContext(), varExpr, varRecipe.RecipeDecl, + cgf.getContext(), varExpr, allocaDecl, /*temporary=*/nullptr, clause.getReductionOp(), Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType, reductionOp.getResult()); diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index 5082e2c272ebd..fbd8022cd68ba 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -2590,9 +2590,11 @@ SemaOpenACC::ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) { } namespace { -enum class InitKind { Zero, One, AllOnes, Least, Largest }; +enum class InitKind { Invalid, Zero, One, AllOnes, Least, Largest }; llvm::APFloat getInitFloatValue(ASTContext &Context, InitKind IK, QualType Ty) { switch (IK) { + case InitKind::Invalid: + llvm_unreachable("invalid init kind"); case InitKind::Zero: return llvm::APFloat::getZero(Context.getFloatTypeSemantics(Ty)); case InitKind::One: @@ -2604,13 +2606,14 @@ llvm::APFloat getInitFloatValue(ASTContext &Context, InitKind IK, QualType Ty) { /*Negative=*/true); case InitKind::Largest: return llvm::APFloat::getLargest(Context.getFloatTypeSemantics(Ty)); - break; } llvm_unreachable("unknown init kind"); } llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) { switch (IK) { + case InitKind::Invalid: + llvm_unreachable("invalid init kind"); case InitKind::Zero: return llvm::APInt(Context.getIntWidth(Ty), 0); case InitKind::One: @@ -2625,7 +2628,6 @@ llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) { if (Ty->isSignedIntegerOrEnumerationType()) return llvm::APInt::getSignedMaxValue(Context.getIntWidth(Ty)); return llvm::APInt::getMaxValue(Context.getIntWidth(Ty)); - break; } llvm_unreachable("unknown init kind"); } @@ -2635,6 +2637,16 @@ llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) { Expr *GenerateReductionInitRecipeExpr(ASTContext &Context, SourceRange ExprRange, QualType Ty, InitKind IK) { + if (IK == InitKind::Invalid) + return nullptr; + + if (IK == InitKind::Zero) { + Expr *InitExpr = new (Context) + InitListExpr(Context, ExprRange.getBegin(), {}, ExprRange.getEnd()); + InitExpr->setType(Context.VoidTy); + return InitExpr; + } + Ty = Ty.getCanonicalType(); llvm::SmallVector Exprs; @@ -2712,219 +2724,202 @@ Expr *GenerateReductionInitRecipeExpr(ASTContext &Context, return InitExpr; } -} // namespace - -std::pair -SemaOpenACC::CreateInitRecipe(OpenACCClauseKind CK, - OpenACCReductionOperator ReductionOperator, - const Expr *VarExpr) { - // Strip off any array subscripts/array section exprs to get to the type of - // the variable. +const Expr *StripOffBounds(const Expr *VarExpr) { 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(); } + return VarExpr; +} + +VarDecl *CreateAllocaDecl(ASTContext &Ctx, DeclContext *DC, + SourceLocation BeginLoc, IdentifierInfo *VarName, + QualType VarTy) { + return VarDecl::Create(Ctx, DC, BeginLoc, BeginLoc, VarName, VarTy, + Ctx.getTrivialTypeSourceInfo(VarTy), SC_Auto); +} + +ExprResult FinishValueInit(Sema &S, InitializedEntity &Entity, + SourceLocation Loc, QualType VarTy, Expr *InitExpr) { + if (!InitExpr) + return ExprEmpty(); + + InitializationKind Kind = + InitializationKind::CreateForInit(Loc, /*DirectInit=*/true, InitExpr); + InitializationSequence InitSeq(S, Entity, Kind, InitExpr, + /*TopLevelOfInitList=*/false, + /*TreatUnavailableAsInvalid=*/false); + + return InitSeq.Perform(S, Entity, Kind, InitExpr, &VarTy); +} + +} // namespace + +OpenACCPrivateRecipe SemaOpenACC::CreatePrivateInitRecipe(const Expr *VarExpr) { + VarExpr = StripOffBounds(VarExpr); - // 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, nullptr}; + return OpenACCPrivateRecipe::Empty(); QualType VarTy = VarExpr->getType().getNonReferenceType().getUnqualifiedType(); - IdentifierInfo *VarName = [&]() { - switch (CK) { - case OpenACCClauseKind::Private: - return &getASTContext().Idents.get("openacc.private.init"); - case OpenACCClauseKind::FirstPrivate: - return &getASTContext().Idents.get("openacc.firstprivate.init"); - case OpenACCClauseKind::Reduction: - return &getASTContext().Idents.get("openacc.reduction.init"); - default: - llvm_unreachable("Unknown clause kind?"); - } - }(); + // TODO: OpenACC: for arrays/bounds versions, we're going to have to do a + // different initializer, but for now we can go ahead with this. - VarDecl *Recipe = VarDecl::Create( + VarDecl *AllocaDecl = CreateAllocaDecl( getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(), - VarExpr->getBeginLoc(), VarName, VarTy, - getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto); - - ExprResult Init; - VarDecl *Temporary = nullptr; - { - // 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); - - auto FinishValueInit = [&](Expr *InitExpr) { - if (InitExpr) { - InitializationKind Kind = InitializationKind::CreateForInit( - Recipe->getLocation(), /*DirectInit=*/true, InitExpr); - InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, InitExpr, - /*TopLevelOfInitList=*/false, - /*TreatUnavailableAsInvalid=*/false); - return InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, InitExpr, &VarTy); - } - return ExprEmpty(); - }; + &getASTContext().Idents.get("openacc.private.init"), VarTy); - if (CK == OpenACCClauseKind::Private) { - InitializationKind Kind = - InitializationKind::CreateDefault(Recipe->getLocation()); - - InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, {}); - Init = InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, {}); - } else if (CK == OpenACCClauseKind::FirstPrivate) { - // Create a VarDecl to be the 'copied-from' for the copy section of the - // recipe. This allows us to make the association so that we can use the - // standard 'generation' ability of the init. - Temporary = VarDecl::Create( - getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(), - VarExpr->getBeginLoc(), &getASTContext().Idents.get("openacc.temp"), - VarTy, getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto); - auto *TemporaryDRE = DeclRefExpr::Create( - getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{}, - Temporary, - /*ReferstoEnclosingVariableOrCapture=*/false, - DeclarationNameInfo{DeclarationName{Temporary->getDeclName()}, - VarExpr->getBeginLoc()}, - VarTy, clang::VK_LValue, Temporary, nullptr, NOUR_None); - - Expr *InitExpr = nullptr; - - if (const auto *ArrTy = getASTContext().getAsConstantArrayType(VarTy)) { - // Arrays need to have each individual element initialized as there - // isn't a normal 'equals' feature in C/C++. This section sets these up - // as an init list after 'initializing' each individual element. - llvm::SmallVector Args; - - // Decay to pointer for the array subscript expression. - auto *CastToPtr = ImplicitCastExpr::Create( - getASTContext(), - getASTContext().getPointerType(ArrTy->getElementType()), - CK_ArrayToPointerDecay, TemporaryDRE, /*BasePath=*/nullptr, - clang::VK_LValue, FPOptionsOverride{}); - - for (std::size_t I = 0; I < ArrTy->getLimitedSize(); ++I) { - // Each element needs to be some sort of copy initialization from an - // array-index of the original temporary (referenced via a - // DeclRefExpr). - - auto *Idx = IntegerLiteral::Create( - getASTContext(), - llvm::APInt( - getASTContext().getTypeSize(getASTContext().getSizeType()), - I), - getASTContext().getSizeType(), VarExpr->getBeginLoc()); - - Expr *Subscript = new (getASTContext()) ArraySubscriptExpr( - CastToPtr, Idx, ArrTy->getElementType(), clang::VK_LValue, - OK_Ordinary, VarExpr->getBeginLoc()); - - // Generate a simple copy from the result of the subscript. This will - // do a bitwise copy or a copy-constructor, as necessary. - InitializedEntity CopyEntity = - InitializedEntity::InitializeElement(getASTContext(), I, Entity); - InitializationKind CopyKind = - InitializationKind::CreateCopy(VarExpr->getBeginLoc(), {}); - InitializationSequence CopySeq(SemaRef.SemaRef, CopyEntity, CopyKind, - Subscript, - /*TopLevelOfInitList=*/true); - - ExprResult ElemRes = - CopySeq.Perform(SemaRef.SemaRef, CopyEntity, CopyKind, Subscript); - Args.push_back(ElemRes.get()); - } + Sema::TentativeAnalysisScope Trap{SemaRef}; + InitializedEntity Entity = InitializedEntity::InitializeVariable(AllocaDecl); + InitializationKind Kind = + InitializationKind::CreateDefault(AllocaDecl->getLocation()); + InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, {}); + ExprResult Init = InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, {}); - InitExpr = new (getASTContext()) - InitListExpr(getASTContext(), VarExpr->getBeginLoc(), Args, - VarExpr->getEndLoc()); - InitExpr->setType(VarTy); + return OpenACCPrivateRecipe(AllocaDecl, Init.get()); +} - } else { - // If this isn't an array, we can just do normal copy init from a simple - // variable reference, so set that up. - InitExpr = TemporaryDRE; - } +OpenACCFirstPrivateRecipe +SemaOpenACC::CreateFirstPrivateInitRecipe(const Expr *VarExpr) { + VarExpr = StripOffBounds(VarExpr); - Init = FinishValueInit(InitExpr); - } else if (CK == OpenACCClauseKind::Reduction) { - // How we initialize the reduction variable depends on the operator used, - // according to the chart in OpenACC 3.3 section 2.6.15. - - switch (ReductionOperator) { - case OpenACCReductionOperator::Invalid: - // This can only happen when there is an error, and since these inits - // are used for code generation, we can just ignore/not bother doing any - // initialization here. - break; - case OpenACCReductionOperator::Max: { - Expr *InitExpr = GenerateReductionInitRecipeExpr( - getASTContext(), VarExpr->getSourceRange(), VarTy, InitKind::Least); - - Init = FinishValueInit(InitExpr); - break; - } - case OpenACCReductionOperator::Min: { - Expr *InitExpr = GenerateReductionInitRecipeExpr( - getASTContext(), VarExpr->getSourceRange(), VarTy, - InitKind::Largest); + if (!VarExpr || VarExpr->getType()->isDependentType()) + return OpenACCFirstPrivateRecipe::Empty(); - Init = FinishValueInit(InitExpr); - break; - } - case OpenACCReductionOperator::BitwiseAnd: { - Expr *InitExpr = GenerateReductionInitRecipeExpr( - getASTContext(), VarExpr->getSourceRange(), VarTy, - InitKind::AllOnes); + QualType VarTy = + VarExpr->getType().getNonReferenceType().getUnqualifiedType(); - Init = FinishValueInit(InitExpr); - break; - } - case OpenACCReductionOperator::Multiplication: - case OpenACCReductionOperator::And: { - // '&&' initializes every field to 1. However, we need to loop through - // every field/element and generate an initializer for each of the - // elements. + // TODO: OpenACC: for arrays/bounds versions, we're going to have to do a + // different initializer, but for now we can go ahead with this. - Expr *InitExpr = GenerateReductionInitRecipeExpr( - getASTContext(), VarExpr->getSourceRange(), VarTy, InitKind::One); + VarDecl *AllocaDecl = CreateAllocaDecl( + getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(), + &getASTContext().Idents.get("openacc.firstprivate.init"), VarTy); - Init = FinishValueInit(InitExpr); - break; - } - case OpenACCReductionOperator::Addition: - case OpenACCReductionOperator::BitwiseOr: - case OpenACCReductionOperator::BitwiseXOr: - case OpenACCReductionOperator::Or: { - // +, |, ^, and || all use 0 for their initializers, so we can just - // use 'zero init' here and not bother with the rest of the - // array/compound type/etc contents. - Expr *InitExpr = new (getASTContext()) InitListExpr( - getASTContext(), VarExpr->getBeginLoc(), {}, VarExpr->getEndLoc()); - // we set this to void so that the initialization sequence generation - // will get this type correct/etc. - InitExpr->setType(getASTContext().VoidTy); - - Init = FinishValueInit(InitExpr); - break; - } - } - } else { - llvm_unreachable("Unknown clause kind in CreateInitRecipe"); - } - } + VarDecl *Temporary = CreateAllocaDecl( + getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(), + &getASTContext().Idents.get("openacc.temp"), VarTy); + + auto *TemporaryDRE = DeclRefExpr::Create( + getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{}, Temporary, + /*ReferstoEnclosingVariableOrCapture=*/false, + DeclarationNameInfo{DeclarationName{Temporary->getDeclName()}, + VarExpr->getBeginLoc()}, + VarTy, clang::VK_LValue, Temporary, nullptr, NOUR_None); + + Sema::TentativeAnalysisScope Trap{SemaRef}; + InitializedEntity Entity = InitializedEntity::InitializeVariable(AllocaDecl); + + const auto *ArrTy = getASTContext().getAsConstantArrayType(VarTy); + if (!ArrTy) { + ExprResult Init = FinishValueInit( + SemaRef.SemaRef, Entity, VarExpr->getBeginLoc(), VarTy, TemporaryDRE); + return OpenACCFirstPrivateRecipe(AllocaDecl, Init.get(), Temporary); + } + + // Arrays need to have each individual element initialized as there + // isn't a normal 'equals' feature in C/C++. This section sets these up + // as an init list after 'initializing' each individual element. + llvm::SmallVector Args; + // Decay to pointer for the array subscript expression. + auto *CastToPtr = ImplicitCastExpr::Create( + getASTContext(), getASTContext().getPointerType(ArrTy->getElementType()), + CK_ArrayToPointerDecay, TemporaryDRE, /*BasePath=*/nullptr, + clang::VK_LValue, FPOptionsOverride{}); + + for (std::size_t I = 0; I < ArrTy->getLimitedSize(); ++I) { + // Each element needs to be some sort of copy initialization from an + // array-index of the original temporary (referenced via a + // DeclRefExpr). + auto *Idx = IntegerLiteral::Create( + getASTContext(), + llvm::APInt(getASTContext().getTypeSize(getASTContext().getSizeType()), + I), + getASTContext().getSizeType(), VarExpr->getBeginLoc()); + + Expr *Subscript = new (getASTContext()) ArraySubscriptExpr( + CastToPtr, Idx, ArrTy->getElementType(), clang::VK_LValue, OK_Ordinary, + VarExpr->getBeginLoc()); + // Generate a simple copy from the result of the subscript. This will + // do a bitwise copy or a copy-constructor, as necessary. + InitializedEntity CopyEntity = + InitializedEntity::InitializeElement(getASTContext(), I, Entity); + InitializationKind CopyKind = + InitializationKind::CreateCopy(VarExpr->getBeginLoc(), {}); + InitializationSequence CopySeq(SemaRef.SemaRef, CopyEntity, CopyKind, + Subscript, + /*TopLevelOfInitList=*/true); + ExprResult ElemRes = + CopySeq.Perform(SemaRef.SemaRef, CopyEntity, CopyKind, Subscript); + Args.push_back(ElemRes.get()); + } + + Expr *InitExpr = new (getASTContext()) InitListExpr( + getASTContext(), VarExpr->getBeginLoc(), Args, VarExpr->getEndLoc()); + InitExpr->setType(VarTy); + + ExprResult Init = FinishValueInit(SemaRef.SemaRef, Entity, + VarExpr->getBeginLoc(), VarTy, InitExpr); + + return OpenACCFirstPrivateRecipe(AllocaDecl, Init.get(), Temporary); +} +OpenACCReductionRecipe SemaOpenACC::CreateReductionInitRecipe( + OpenACCReductionOperator ReductionOperator, const Expr *VarExpr) { + VarExpr = StripOffBounds(VarExpr); - if (Init.get()) { - Recipe->setInit(Init.get()); - Recipe->setInitStyle(VarDecl::CallInit); + if (!VarExpr || VarExpr->getType()->isDependentType()) + return OpenACCReductionRecipe::Empty(); + + QualType VarTy = + VarExpr->getType().getNonReferenceType().getUnqualifiedType(); + + // TODO: OpenACC: for arrays/bounds versions, we're going to have to do a + // different initializer, but for now we can go ahead with this. + + VarDecl *AllocaDecl = CreateAllocaDecl( + getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(), + &getASTContext().Idents.get("openacc.reduction.init"), VarTy); + + Sema::TentativeAnalysisScope Trap{SemaRef}; + InitializedEntity Entity = InitializedEntity::InitializeVariable(AllocaDecl); + + InitKind IK = InitKind::Invalid; + switch (ReductionOperator) { + case OpenACCReductionOperator::Invalid: + // This can only happen when there is an error, and since these inits + // are used for code generation, we can just ignore/not bother doing any + // initialization here. + IK = InitKind::Invalid; + break; + case OpenACCReductionOperator::Max: + IK = InitKind::Least; + break; + case OpenACCReductionOperator::Min: + IK = InitKind::Largest; + break; + case OpenACCReductionOperator::BitwiseAnd: + IK = InitKind::AllOnes; + break; + case OpenACCReductionOperator::Multiplication: + case OpenACCReductionOperator::And: + IK = InitKind::One; + break; + case OpenACCReductionOperator::Addition: + case OpenACCReductionOperator::BitwiseOr: + case OpenACCReductionOperator::BitwiseXOr: + case OpenACCReductionOperator::Or: + IK = InitKind::Zero; + break; } - return {Recipe, Temporary}; + Expr *InitExpr = GenerateReductionInitRecipeExpr( + getASTContext(), VarExpr->getSourceRange(), VarTy, IK); + + ExprResult Init = FinishValueInit(SemaRef.SemaRef, Entity, + VarExpr->getBeginLoc(), VarTy, InitExpr); + return OpenACCReductionRecipe(AllocaDecl, Init.get()); } diff --git a/clang/lib/Sema/SemaOpenACCClause.cpp b/clang/lib/Sema/SemaOpenACCClause.cpp index 36f79ba46caf3..b0869293c1664 100644 --- a/clang/lib/Sema/SemaOpenACCClause.cpp +++ b/clang/lib/Sema/SemaOpenACCClause.cpp @@ -795,12 +795,11 @@ 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. - llvm::SmallVector InitRecipes; + llvm::SmallVector InitRecipes; // Assemble the recipes list. for (const Expr *VarExpr : Clause.getVarList()) - InitRecipes.push_back( - SemaRef.CreateInitRecipe(OpenACCClauseKind::Private, VarExpr).first); + InitRecipes.push_back(SemaRef.CreatePrivateInitRecipe(VarExpr)); return OpenACCPrivateClause::Create( Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(), @@ -817,8 +816,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitFirstPrivateClause( // Assemble the recipes list. for (const Expr *VarExpr : Clause.getVarList()) - InitRecipes.push_back( - SemaRef.CreateInitRecipe(OpenACCClauseKind::FirstPrivate, VarExpr)); + InitRecipes.push_back(SemaRef.CreateFirstPrivateInitRecipe(VarExpr)); return OpenACCFirstPrivateClause::Create( Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(), @@ -1783,12 +1781,8 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitReductionClause( if (Res.isUsable()) { ValidVars.push_back(Res.get()); - VarDecl *InitRecipe = - SemaRef - .CreateInitRecipe(OpenACCClauseKind::Reduction, - Clause.getReductionOp(), Res.get()) - .first; - Recipes.push_back({InitRecipe}); + Recipes.push_back(SemaRef.CreateReductionInitRecipe( + Clause.getReductionOp(), Res.get())); } } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index fbadb8d6881a5..0587a7decbd8d 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -11903,7 +11903,7 @@ template void OpenACCClauseTransform::VisitPrivateClause( const OpenACCPrivateClause &C) { llvm::SmallVector InstantiatedVarList; - llvm::SmallVector InitRecipes; + llvm::SmallVector InitRecipes; for (const auto [RefExpr, InitRecipe] : llvm::zip(C.getVarList(), C.getInitRecipes())) { @@ -11914,14 +11914,11 @@ void OpenACCClauseTransform::VisitPrivateClause( // 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) + if (InitRecipe.isSet()) InitRecipes.push_back(InitRecipe); else InitRecipes.push_back( - Self.getSema() - .OpenACC() - .CreateInitRecipe(OpenACCClauseKind::Private, VarRef.get()) - .first); + Self.getSema().OpenACC().CreatePrivateInitRecipe(VarRef.get())); } } ParsedClause.setVarListDetails(InstantiatedVarList, @@ -11972,11 +11969,12 @@ void OpenACCClauseTransform::VisitFirstPrivateClause( // 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.RecipeDecl) + if (InitRecipe.isSet()) InitRecipes.push_back(InitRecipe); else - InitRecipes.push_back(Self.getSema().OpenACC().CreateInitRecipe( - OpenACCClauseKind::FirstPrivate, VarRef.get())); + InitRecipes.push_back( + Self.getSema().OpenACC().CreateFirstPrivateInitRecipe( + VarRef.get())); } } ParsedClause.setVarListDetails(InstantiatedVarList, @@ -12434,27 +12432,18 @@ void OpenACCClauseTransform::VisitReductionClause( SmallVector ValidVars; llvm::SmallVector Recipes; - for (const auto [Var, OrigRecipes] : + for (const auto [Var, OrigRecipe] : llvm::zip(TransformedVars, C.getRecipes())) { ExprResult Res = Self.getSema().OpenACC().CheckReductionVar( ParsedClause.getDirectiveKind(), C.getReductionOp(), Var); if (Res.isUsable()) { ValidVars.push_back(Res.get()); - // TODO OpenACC: When the recipe changes, make sure we get these right - // too. We probably need something similar for the operation. - static_assert(sizeof(OpenACCReductionRecipe) == sizeof(int*)); - VarDecl *InitRecipe = nullptr; - if (OrigRecipes.RecipeDecl) - InitRecipe = OrigRecipes.RecipeDecl; - else - InitRecipe = Self.getSema() - .OpenACC() - .CreateInitRecipe(OpenACCClauseKind::Reduction, - C.getReductionOp(), Res.get()) - .first; - - Recipes.push_back({InitRecipe}); + if (OrigRecipe.isSet()) + Recipes.push_back(OrigRecipe); + else + Recipes.push_back(Self.getSema().OpenACC().CreateReductionInitRecipe( + C.getReductionOp(), Res.get())); } } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 7268af698cfb4..9b0e699b1a829 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -12858,9 +12858,13 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { SourceLocation LParenLoc = readSourceLocation(); llvm::SmallVector VarList = readOpenACCVarList(); - llvm::SmallVector RecipeList; - for (unsigned I = 0; I < VarList.size(); ++I) - RecipeList.push_back(readDeclAs()); + llvm::SmallVector RecipeList; + for (unsigned I = 0; I < VarList.size(); ++I) { + static_assert(sizeof(OpenACCPrivateRecipe) == 2 * sizeof(int *)); + VarDecl *Alloca = readDeclAs(); + Expr *InitExpr = readSubExpr(); + RecipeList.push_back({Alloca, InitExpr}); + } return OpenACCPrivateClause::Create(getContext(), BeginLoc, LParenLoc, VarList, RecipeList, EndLoc); @@ -12882,9 +12886,11 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { llvm::SmallVector VarList = readOpenACCVarList(); llvm::SmallVector RecipeList; for (unsigned I = 0; I < VarList.size(); ++I) { + static_assert(sizeof(OpenACCFirstPrivateRecipe) == 3 * sizeof(int *)); VarDecl *Recipe = readDeclAs(); + Expr *InitExpr = readSubExpr(); VarDecl *RecipeTemp = readDeclAs(); - RecipeList.push_back({Recipe, RecipeTemp}); + RecipeList.push_back({Recipe, InitExpr, RecipeTemp}); } return OpenACCFirstPrivateClause::Create(getContext(), BeginLoc, LParenLoc, @@ -13005,9 +13011,10 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { llvm::SmallVector RecipeList; for (unsigned I = 0; I < VarList.size(); ++I) { + static_assert(sizeof(OpenACCReductionRecipe) == 2 * sizeof(int *)); VarDecl *Recipe = readDeclAs(); - static_assert(sizeof(OpenACCReductionRecipe) == sizeof(int *)); - RecipeList.push_back({Recipe}); + Expr *InitExpr = readSubExpr(); + RecipeList.push_back({Recipe, InitExpr}); } return OpenACCReductionClause::Create(getContext(), BeginLoc, LParenLoc, Op, diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 293b67aac0219..8e219e54bf251 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -8751,8 +8751,11 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { writeSourceLocation(PC->getLParenLoc()); writeOpenACCVarList(PC); - for (VarDecl *VD : PC->getInitRecipes()) - AddDeclRef(VD); + for (const OpenACCPrivateRecipe &R : PC->getInitRecipes()) { + static_assert(sizeof(R) == 2 * sizeof(int *)); + AddDeclRef(R.AllocaDecl); + AddStmt(const_cast(R.InitExpr)); + } return; } case OpenACCClauseKind::Host: { @@ -8773,7 +8776,9 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { writeOpenACCVarList(FPC); for (const OpenACCFirstPrivateRecipe &R : FPC->getInitRecipes()) { - AddDeclRef(R.RecipeDecl); + static_assert(sizeof(R) == 3 * sizeof(int *)); + AddDeclRef(R.AllocaDecl); + AddStmt(const_cast(R.InitExpr)); AddDeclRef(R.InitFromTemporary); } return; @@ -8895,8 +8900,9 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { writeOpenACCVarList(RC); for (const OpenACCReductionRecipe &R : RC->getRecipes()) { - static_assert(sizeof(OpenACCReductionRecipe) == sizeof(int *)); - AddDeclRef(R.RecipeDecl); + static_assert(sizeof(OpenACCReductionRecipe) == 2 * sizeof(int *)); + AddDeclRef(R.AllocaDecl); + AddStmt(const_cast(R.InitExpr)); } return; } diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 858423a06576a..f255d751362ee 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2837,8 +2837,10 @@ void OpenACCClauseEnqueue::VisitTileClause(const OpenACCTileClause &C) { void OpenACCClauseEnqueue::VisitPrivateClause(const OpenACCPrivateClause &C) { VisitVarList(C); - for (VarDecl *V : C.getInitRecipes()) - Visitor.AddDecl(V); + for (const OpenACCPrivateRecipe &R : C.getInitRecipes()) { + Visitor.AddDecl(R.AllocaDecl); + Visitor.AddStmt(R.InitExpr); + } } void OpenACCClauseEnqueue::VisitHostClause(const OpenACCHostClause &C) { @@ -2853,7 +2855,8 @@ void OpenACCClauseEnqueue::VisitFirstPrivateClause( const OpenACCFirstPrivateClause &C) { VisitVarList(C); for (const OpenACCFirstPrivateRecipe &R : C.getInitRecipes()) { - Visitor.AddDecl(R.RecipeDecl); + Visitor.AddDecl(R.AllocaDecl); + Visitor.AddStmt(R.InitExpr); Visitor.AddDecl(R.InitFromTemporary); } } @@ -2930,8 +2933,8 @@ void OpenACCClauseEnqueue::VisitReductionClause( const OpenACCReductionClause &C) { VisitVarList(C); for (const OpenACCReductionRecipe &R : C.getRecipes()) { - static_assert(sizeof(OpenACCReductionRecipe) == sizeof(int *)); - Visitor.AddDecl(R.RecipeDecl); + Visitor.AddDecl(R.AllocaDecl); + Visitor.AddStmt(R.InitExpr); } } void OpenACCClauseEnqueue::VisitAutoClause(const OpenACCAutoClause &C) {}