[clang] [OpenACC][NFCI] Split recipe generation into its own class (PR #157160)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 5 11:56:58 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir
Author: Erich Keane (erichkeane)
<details>
<summary>Changes</summary>
The recipe generation was dependent on the clause kind, which meant we had all of the recipe generation duplicated in each of clauses. This patch copy/pastes all of them into their own type to do recipe generation, which should reduce clang's size.
Additionally, we've moved it off into its own file, which should make readability/organization improvements.
---
Patch is 31.73 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/157160.diff
2 Files Affected:
- (modified) clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp (+24-308)
- (added) clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h (+323)
``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
index 0022befa3b562..9959cf6c15792 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
@@ -14,6 +14,7 @@
#include "CIRGenCXXABI.h"
#include "CIRGenFunction.h"
+#include "CIRGenOpenACCRecipe.h"
#include "clang/AST/ExprCXX.h"
@@ -356,299 +357,6 @@ class OpenACCClauseCIREmitter final
}
}
- template <typename RecipeTy>
- std::string getRecipeName(SourceRange loc, QualType baseType,
- OpenACCReductionOperator reductionOp) {
- std::string recipeName;
- {
- llvm::raw_string_ostream stream(recipeName);
-
- if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
- stream << "privatization_";
- } else if constexpr (std::is_same_v<RecipeTy,
- mlir::acc::FirstprivateRecipeOp>) {
- stream << "firstprivatization_";
-
- } else if constexpr (std::is_same_v<RecipeTy,
- mlir::acc::ReductionRecipeOp>) {
- stream << "reduction_";
- // Values here are a little weird (for bitwise and/or is 'i' prefix, and
- // logical ops with 'l'), but are chosen to be the same as the MLIR
- // dialect names as well as to match the Flang versions of these.
- switch (reductionOp) {
- case OpenACCReductionOperator::Addition:
- stream << "add_";
- break;
- case OpenACCReductionOperator::Multiplication:
- stream << "mul_";
- break;
- case OpenACCReductionOperator::Max:
- stream << "max_";
- break;
- case OpenACCReductionOperator::Min:
- stream << "min_";
- break;
- case OpenACCReductionOperator::BitwiseAnd:
- stream << "iand_";
- break;
- case OpenACCReductionOperator::BitwiseOr:
- stream << "ior_";
- break;
- case OpenACCReductionOperator::BitwiseXOr:
- stream << "xor_";
- break;
- case OpenACCReductionOperator::And:
- stream << "land_";
- break;
- case OpenACCReductionOperator::Or:
- stream << "lor_";
- break;
- case OpenACCReductionOperator::Invalid:
- llvm_unreachable("invalid reduction operator");
- }
- } else {
- static_assert(!sizeof(RecipeTy), "Unknown Recipe op kind");
- }
-
- MangleContext &mc = cgf.cgm.getCXXABI().getMangleContext();
- mc.mangleCanonicalTypeName(baseType, stream);
- }
- return recipeName;
- }
-
- void createFirstprivateRecipeCopy(
- mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
- CIRGenFunction::AutoVarEmission tempDeclEmission,
- mlir::acc::FirstprivateRecipeOp recipe, const VarDecl *varRecipe,
- const VarDecl *temporary) {
- mlir::Block *block = builder.createBlock(
- &recipe.getCopyRegion(), recipe.getCopyRegion().end(),
- {mainOp.getType(), mainOp.getType()}, {loc, loc});
- builder.setInsertionPointToEnd(&recipe.getCopyRegion().back());
- CIRGenFunction::LexicalScope ls(cgf, loc, block);
-
- mlir::BlockArgument fromArg = block->getArgument(0);
- mlir::BlockArgument toArg = block->getArgument(1);
-
- mlir::Type elementTy =
- mlir::cast<cir::PointerType>(mainOp.getType()).getPointee();
-
- // Set the address of the emission to be the argument, so that we initialize
- // that instead of the variable in the other block.
- tempDeclEmission.setAllocatedAddress(
- Address{toArg, elementTy, cgf.getContext().getDeclAlign(varRecipe)});
- tempDeclEmission.EmittedAsOffload = true;
-
- CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, temporary};
- cgf.setAddrOfLocalVar(
- temporary,
- Address{fromArg, elementTy, cgf.getContext().getDeclAlign(varRecipe)});
-
- cgf.emitAutoVarInit(tempDeclEmission);
- mlir::acc::YieldOp::create(builder, locEnd);
- }
-
- // Create the 'init' section of the recipe, including the 'copy' section for
- // 'firstprivate'. Note that this function is not 'insertion point' clean, in
- // that it alters the insertion point to be inside of the 'destroy' section of
- // the recipe, but doesn't restore it aftewards.
- template <typename RecipeTy>
- void createRecipeInitCopy(mlir::Location loc, mlir::Location locEnd,
- SourceRange exprRange, mlir::Value mainOp,
- RecipeTy recipe, const VarDecl *varRecipe,
- const VarDecl *temporary) {
- assert(varRecipe && "Required recipe variable not set?");
-
- CIRGenFunction::AutoVarEmission tempDeclEmission{
- CIRGenFunction::AutoVarEmission::invalid()};
- CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, varRecipe};
-
- // Do the 'init' section of the recipe IR, which does an alloca, then the
- // initialization (except for firstprivate).
- mlir::Block *block = builder.createBlock(&recipe.getInitRegion(),
- recipe.getInitRegion().end(),
- {mainOp.getType()}, {loc});
- builder.setInsertionPointToEnd(&recipe.getInitRegion().back());
- CIRGenFunction::LexicalScope ls(cgf, loc, block);
-
- tempDeclEmission =
- cgf.emitAutoVarAlloca(*varRecipe, builder.saveInsertionPoint());
-
- // 'firstprivate' doesn't do its initialization in the 'init' section,
- // instead does it in the 'copy' section. SO only do init here.
- // 'reduction' appears to use it too (rather than a 'copy' section), so
- // we probably have to do it here too, but we can do that when we get to
- // reduction implementation.
- if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
- // We are OK with no init for builtins, arrays of builtins, or pointers,
- // else we should NYI so we know to go look for these.
- if (cgf.getContext().getLangOpts().CPlusPlus &&
- !varRecipe->getType()
- ->getPointeeOrArrayElementType()
- ->isBuiltinType() &&
- !varRecipe->getType()->isPointerType() && !varRecipe->getInit()) {
- // If we don't have any initialization recipe, we failed during Sema to
- // initialize this correctly. If we disable the
- // Sema::TentativeAnalysisScopes in SemaOpenACC::CreateInitRecipe, it'll
- // emit an error to tell us. However, emitting those errors during
- // production is a violation of the standard, so we cannot do them.
- cgf.cgm.errorNYI(exprRange, "private default-init recipe");
- }
- cgf.emitAutoVarInit(tempDeclEmission);
- } else if constexpr (std::is_same_v<RecipeTy,
- mlir::acc::ReductionRecipeOp>) {
- // Unlike Private, the recipe here is always required as it has to do
- // init, not just 'default' init.
- if (!varRecipe->getInit())
- cgf.cgm.errorNYI(exprRange, "reduction init recipe");
- cgf.emitAutoVarInit(tempDeclEmission);
- }
-
- mlir::acc::YieldOp::create(builder, locEnd);
-
- if constexpr (std::is_same_v<RecipeTy, mlir::acc::FirstprivateRecipeOp>) {
- if (!varRecipe->getInit()) {
- // If we don't have any initialization recipe, we failed during Sema to
- // initialize this correctly. If we disable the
- // Sema::TentativeAnalysisScopes in SemaOpenACC::CreateInitRecipe, it'll
- // emit an error to tell us. However, emitting those errors during
- // production is a violation of the standard, so we cannot do them.
- cgf.cgm.errorNYI(
- exprRange, "firstprivate copy-init recipe not properly generated");
- }
-
- createFirstprivateRecipeCopy(loc, locEnd, mainOp, tempDeclEmission,
- recipe, varRecipe, temporary);
- }
- }
-
- // This function generates the 'combiner' section for a reduction recipe. Note
- // that this function is not 'insertion point' clean, in that it alters the
- // insertion point to be inside of the 'combiner' section of the recipe, but
- // doesn't restore it aftewards.
- void createReductionRecipeCombiner(mlir::Location loc, mlir::Location locEnd,
- mlir::Value mainOp,
- mlir::acc::ReductionRecipeOp recipe) {
- mlir::Block *block = builder.createBlock(
- &recipe.getCombinerRegion(), recipe.getCombinerRegion().end(),
- {mainOp.getType(), mainOp.getType()}, {loc, loc});
- builder.setInsertionPointToEnd(&recipe.getCombinerRegion().back());
- CIRGenFunction::LexicalScope ls(cgf, loc, block);
-
- mlir::BlockArgument lhsArg = block->getArgument(0);
-
- mlir::acc::YieldOp::create(builder, locEnd, lhsArg);
- }
-
- // This function generates the 'destroy' section for a recipe. Note
- // that this function is not 'insertion point' clean, in that it alters the
- // insertion point to be inside of the 'destroy' section of the recipe, but
- // doesn't restore it aftewards.
- void createRecipeDestroySection(mlir::Location loc, mlir::Location locEnd,
- mlir::Value mainOp, CharUnits alignment,
- QualType baseType,
- mlir::Region &destroyRegion) {
- mlir::Block *block =
- builder.createBlock(&destroyRegion, destroyRegion.end(),
- {mainOp.getType(), mainOp.getType()}, {loc, loc});
- builder.setInsertionPointToEnd(&destroyRegion.back());
- CIRGenFunction::LexicalScope ls(cgf, loc, block);
-
- mlir::Type elementTy =
- mlir::cast<cir::PointerType>(mainOp.getType()).getPointee();
- // The destroy region has a signature of "original item, privatized item".
- // So the 2nd item is the one that needs destroying, the former is just for
- // reference and we don't really have a need for it at the moment.
- Address addr{block->getArgument(1), elementTy, alignment};
- cgf.emitDestroy(addr, baseType,
- cgf.getDestroyer(QualType::DK_cxx_destructor));
-
- mlir::acc::YieldOp::create(builder, locEnd);
- }
-
- mlir::acc::ReductionOperator convertReductionOp(OpenACCReductionOperator op) {
- switch (op) {
- case OpenACCReductionOperator::Addition:
- return mlir::acc::ReductionOperator::AccAdd;
- case OpenACCReductionOperator::Multiplication:
- return mlir::acc::ReductionOperator::AccMul;
- case OpenACCReductionOperator::Max:
- return mlir::acc::ReductionOperator::AccMax;
- case OpenACCReductionOperator::Min:
- return mlir::acc::ReductionOperator::AccMin;
- case OpenACCReductionOperator::BitwiseAnd:
- return mlir::acc::ReductionOperator::AccIand;
- case OpenACCReductionOperator::BitwiseOr:
- return mlir::acc::ReductionOperator::AccIor;
- case OpenACCReductionOperator::BitwiseXOr:
- return mlir::acc::ReductionOperator::AccXor;
- case OpenACCReductionOperator::And:
- return mlir::acc::ReductionOperator::AccLand;
- case OpenACCReductionOperator::Or:
- return mlir::acc::ReductionOperator::AccLor;
- case OpenACCReductionOperator::Invalid:
- llvm_unreachable("invalid reduction operator");
- }
-
- llvm_unreachable("invalid reduction operator");
- }
-
- template <typename RecipeTy>
- RecipeTy getOrCreateRecipe(ASTContext &astCtx, const Expr *varRef,
- const VarDecl *varRecipe, const VarDecl *temporary,
- OpenACCReductionOperator reductionOp,
- DeclContext *dc, QualType baseType,
- mlir::Value mainOp) {
-
- if (baseType->isPointerType() ||
- (baseType->isArrayType() && !baseType->isConstantArrayType())) {
- // It is clear that the use of pointers/VLAs in a recipe are not properly
- // generated/don't do what they are supposed to do. In the case where we
- // have 'bounds', we can actually figure out what we want to
- // initialize/copy/destroy/compare/etc, but we haven't figured out how
- // that looks yet, both between the IR and generation code. For now, we
- // will do an NYI error no it.
- cgf.cgm.errorNYI(
- varRef->getSourceRange(),
- "OpenACC recipe generation for pointer/non-constant arrays");
- }
-
- mlir::ModuleOp mod = builder.getBlock()
- ->getParent()
- ->template getParentOfType<mlir::ModuleOp>();
-
- std::string recipeName = getRecipeName<RecipeTy>(varRef->getSourceRange(),
- baseType, reductionOp);
- if (auto recipe = mod.lookupSymbol<RecipeTy>(recipeName))
- return recipe;
-
- mlir::Location loc = cgf.cgm.getLoc(varRef->getBeginLoc());
- mlir::Location locEnd = cgf.cgm.getLoc(varRef->getEndLoc());
-
- mlir::OpBuilder modBuilder(mod.getBodyRegion());
- RecipeTy recipe;
-
- if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) {
- recipe = RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType(),
- convertReductionOp(reductionOp));
- } else {
- recipe = RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType());
- }
-
- createRecipeInitCopy(loc, locEnd, varRef->getSourceRange(), mainOp, recipe,
- varRecipe, temporary);
-
- if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) {
- createReductionRecipeCombiner(loc, locEnd, mainOp, recipe);
- }
-
- if (varRecipe && varRecipe->needsDestruction(cgf.getContext()))
- createRecipeDestroySection(loc, locEnd, mainOp,
- cgf.getContext().getDeclAlign(varRecipe),
- baseType, recipe.getDestroyRegion());
- return recipe;
- }
-
public:
OpenACCClauseCIREmitter(OpTy &operation, CIRGen::CIRGenFunction &cgf,
CIRGen::CIRGenBuilderTy &builder,
@@ -1287,11 +995,13 @@ class OpenACCClauseCIREmitter final
allocaDecl->setInit(varRecipe.InitExpr);
allocaDecl->setInitStyle(VarDecl::CallInit);
- auto recipe = getOrCreateRecipe<mlir::acc::PrivateRecipeOp>(
- cgf.getContext(), varExpr, allocaDecl, /*temporary=*/nullptr,
- OpenACCReductionOperator::Invalid,
- Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
- privateOp.getResult());
+ auto recipe =
+ OpenACCRecipeBuilder<mlir::acc::PrivateRecipeOp>(cgf, builder)
+ .getOrCreateRecipe(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
// have these be on a different operation, so when that changes, we
// probably need to change these here.
@@ -1329,11 +1039,15 @@ class OpenACCClauseCIREmitter final
allocaDecl->setInit(varRecipe.InitExpr);
allocaDecl->setInitStyle(VarDecl::CallInit);
- auto recipe = getOrCreateRecipe<mlir::acc::FirstprivateRecipeOp>(
- cgf.getContext(), varExpr, allocaDecl,
- varRecipe.InitFromTemporary, OpenACCReductionOperator::Invalid,
- Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
- firstPrivateOp.getResult());
+ auto recipe =
+ OpenACCRecipeBuilder<mlir::acc::FirstprivateRecipeOp>(cgf,
+ builder)
+ .getOrCreateRecipe(cgf.getContext(), varExpr, allocaDecl,
+ varRecipe.InitFromTemporary,
+ OpenACCReductionOperator::Invalid,
+ Decl::castToDeclContext(cgf.curFuncDecl),
+ opInfo.baseType,
+ firstPrivateOp.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
@@ -1373,11 +1087,13 @@ class OpenACCClauseCIREmitter final
allocaDecl->setInit(varRecipe.InitExpr);
allocaDecl->setInitStyle(VarDecl::CallInit);
- auto recipe = getOrCreateRecipe<mlir::acc::ReductionRecipeOp>(
- cgf.getContext(), varExpr, allocaDecl,
- /*temporary=*/nullptr, clause.getReductionOp(),
- Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
- reductionOp.getResult());
+ auto recipe =
+ OpenACCRecipeBuilder<mlir::acc::ReductionRecipeOp>(cgf, builder)
+ .getOrCreateRecipe(cgf.getContext(), varExpr, allocaDecl,
+ /*temporary=*/nullptr,
+ clause.getReductionOp(),
+ Decl::castToDeclContext(cgf.curFuncDecl),
+ opInfo.baseType, reductionOp.getResult());
operation.addReduction(builder.getContext(), reductionOp, recipe);
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
new file mode 100644
index 0000000000000..102fd890e5579
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
@@ -0,0 +1,323 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Emit OpenACC clause recipes as CIR code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenFunction.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/TypeBase.h"
+#include "clang/Basic/OpenACCKinds.h"
+
+#include "mlir/Dialect/OpenACC/OpenACC.h"
+
+namespace clang::CIRGen {
+template <typename RecipeTy> class OpenACCRecipeBuilder {
+ CIRGen::CIRGenFunction &cgf;
+ CIRGen::CIRGenBuilderTy &builder;
+
+ mlir::acc::ReductionOperator convertReductionOp(OpenACCReductionOperator op) {
+ switch (op) {
+ case OpenACCReductionOperator::Addition:
+ return mlir::acc::ReductionOperator::AccAdd;
+ case OpenACCReductionOperator::Multiplication:
+ return mlir::acc::ReductionOperator::AccMul;
+ case OpenACCReductionOperator::Max:
+ return mlir::acc::ReductionOperator::AccMax;
+ case OpenACCReductionOperator::Min:
+ return mlir::acc::ReductionOperator::AccMin;
+ case OpenACCReductionOperator::BitwiseAnd:
+ return mlir::acc::ReductionOperator::AccIand;
+ case OpenACCReductionOperator::BitwiseOr:
+ return mlir::acc::ReductionOperator::AccIor;
+ case OpenACCReductionOperator::BitwiseXOr:
+ return mlir::acc::ReductionOperator::AccXor;
+ case OpenACCReductionOperator::And:
+ return mlir::acc::ReductionOperator::AccLand;
+ case OpenACCReductionOperator::Or:
+ return mlir::acc::ReductionOperator::AccLor;
+ case OpenACCReductionOperator::Invalid:
+ llvm_unreachable("invalid reduction operator");
+ }
+
+ llvm_unreachable("invalid reduction operator");
+ }
+
+ std::string getRecipeName(SourceRange loc, QualType baseType,
+ OpenACCReductionOperator reductionOp) {
+ std::string recipeName;
+ {
+ llvm::raw_string_ostream stream(recipeName);
+
+ if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
+ stream << "privatization_";
+ } else if constexpr (std::is_same_v<RecipeTy,
+ mlir::acc::FirstprivateRecipeOp>) {
+ s...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/157160
More information about the cfe-commits
mailing list