Thanks to visit codestin.com
Credit goes to clang.llvm.org

clang 22.0.0git
CIRGenOpenACCRecipe.h
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Emit OpenACC clause recipes as CIR code.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenCXXABI.h"
14#include "CIRGenFunction.h"
15
17#include "clang/AST/DeclBase.h"
18#include "clang/AST/Expr.h"
19#include "clang/AST/ExprCXX.h"
20#include "clang/AST/TypeBase.h"
22
23#include "mlir/Dialect/OpenACC/OpenACC.h"
24
25namespace clang::CIRGen {
27 // makes the copy of the addresses of an alloca to the previous allocation.
28 void makeAllocaCopy(mlir::Location loc, mlir::Type copyType,
29 mlir::Value numEltsToCopy, mlir::Value offsetPerSubarray,
30 mlir::Value destAlloca, mlir::Value srcAlloca);
31 // This function generates the required alloca, similar to
32 // 'emitAutoVarAlloca', except for the OpenACC array/pointer types.
33 mlir::Value makeBoundsAlloca(mlir::Block *block, SourceRange exprRange,
34 mlir::Location loc, std::string_view allocaName,
35 size_t numBounds,
36 llvm::ArrayRef<QualType> boundTypes);
37
38protected:
41
42 mlir::Block *createRecipeBlock(mlir::Region &region, mlir::Type opTy,
43 mlir::Location loc, size_t numBounds,
44 bool isInit);
45 // Creates a loop through an 'acc.bounds', leaving the 'insertion' point to be
46 // the inside of the loop body. Traverses LB->UB UNLESS `inverse` is set.
47 // Returns the 'subscriptedValue' changed with the new bounds subscript.
48 mlir::Value createBoundsLoop(mlir::Value subscriptedValue, mlir::Value bound,
49 mlir::Location loc, bool inverse);
50 mlir::acc::ReductionOperator convertReductionOp(OpenACCReductionOperator op);
52 mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
53 CIRGenFunction::AutoVarEmission tempDeclEmission,
54 mlir::acc::FirstprivateRecipeOp recipe, const VarDecl *varRecipe,
55 const VarDecl *temporary);
56
57 // This function generates the 'combiner' section for a reduction recipe. Note
58 // that this function is not 'insertion point' clean, in that it alters the
59 // insertion point to be inside of the 'combiner' section of the recipe, but
60 // doesn't restore it aftewards.
61 void createReductionRecipeCombiner(mlir::Location loc, mlir::Location locEnd,
62 mlir::Value mainOp,
63 mlir::acc::ReductionRecipeOp recipe);
64 void createPrivateInitRecipe(mlir::Location loc, mlir::Location locEnd,
65 SourceRange exprRange, mlir::Value mainOp,
66 mlir::acc::PrivateRecipeOp recipe,
67 size_t numBounds,
68 llvm::ArrayRef<QualType> boundTypes,
69 const VarDecl *allocaDecl, QualType origType,
70 const Expr *initExpr);
71
72 void createRecipeDestroySection(mlir::Location loc, mlir::Location locEnd,
73 mlir::Value mainOp, CharUnits alignment,
74 QualType origType, size_t numBounds,
75 QualType baseType,
76 mlir::Region &destroyRegion);
77
81};
82
83template <typename RecipeTy>
85 std::string getRecipeName(SourceRange loc, QualType baseType,
86 unsigned numBounds,
87 OpenACCReductionOperator reductionOp) {
88 std::string recipeName;
89 {
90 llvm::raw_string_ostream stream(recipeName);
91
92 if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
93 stream << "privatization_";
94 } else if constexpr (std::is_same_v<RecipeTy,
95 mlir::acc::FirstprivateRecipeOp>) {
96 stream << "firstprivatization_";
97
98 } else if constexpr (std::is_same_v<RecipeTy,
99 mlir::acc::ReductionRecipeOp>) {
100 stream << "reduction_";
101 // Values here are a little weird (for bitwise and/or is 'i' prefix, and
102 // logical ops with 'l'), but are chosen to be the same as the MLIR
103 // dialect names as well as to match the Flang versions of these.
104 switch (reductionOp) {
106 stream << "add_";
107 break;
109 stream << "mul_";
110 break;
112 stream << "max_";
113 break;
115 stream << "min_";
116 break;
118 stream << "iand_";
119 break;
121 stream << "ior_";
122 break;
124 stream << "xor_";
125 break;
127 stream << "land_";
128 break;
130 stream << "lor_";
131 break;
133 llvm_unreachable("invalid reduction operator");
134 }
135 } else {
136 static_assert(!sizeof(RecipeTy), "Unknown Recipe op kind");
137 }
138
139 // The naming convention from Flang with bounds doesn't map to C++ types
140 // very well, so we're just going to choose our own here.
141 if (numBounds)
142 stream << "_Bcnt" << numBounds << '_';
143
144 MangleContext &mc = cgf.cgm.getCXXABI().getMangleContext();
145 mc.mangleCanonicalTypeName(baseType, stream);
146 }
147 return recipeName;
148 }
149
150 // Create the 'init' section of the recipe, including the 'copy' section for
151 // 'firstprivate'. Note that this function is not 'insertion point' clean, in
152 // that it alters the insertion point to be inside of the 'destroy' section of
153 // the recipe, but doesn't restore it aftewards.
154 void createRecipeInitCopy(mlir::Location loc, mlir::Location locEnd,
155 SourceRange exprRange, mlir::Value mainOp,
156 RecipeTy recipe, const VarDecl *varRecipe,
157 const VarDecl *temporary) {
158 // TODO: OpenACC: when we get the 'pointer' variants for
159 // firstprivate/reduction, this probably should be removed/split into
160 // functions for the BuilderBase.
161 assert(varRecipe && "Required recipe variable not set?");
162
163 CIRGenFunction::AutoVarEmission tempDeclEmission{
165 CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, varRecipe};
166
167 // Do the 'init' section of the recipe IR, which does an alloca, then the
168 // initialization (except for firstprivate).
169 mlir::Block *block =
170 createRecipeBlock(recipe.getInitRegion(), mainOp.getType(), loc,
171 /*numBounds=*/0, /*isInit=*/true);
172 builder.setInsertionPointToEnd(&recipe.getInitRegion().back());
173 CIRGenFunction::LexicalScope ls(cgf, loc, block);
174
175 tempDeclEmission =
176 cgf.emitAutoVarAlloca(*varRecipe, builder.saveInsertionPoint());
177
178 // 'firstprivate' doesn't do its initialization in the 'init' section,
179 // instead it does it in the 'copy' section. SO, only do 'init' here for
180 // reduction.
181 if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) {
182 // Unlike Private, the recipe here is always required as it has to do
183 // init, not just 'default' init.
184 if (!varRecipe->getInit())
185 cgf.cgm.errorNYI(exprRange, "reduction init recipe");
186 cgf.emitAutoVarInit(tempDeclEmission);
187 }
188
189 mlir::acc::YieldOp::create(builder, locEnd);
190
191 if constexpr (std::is_same_v<RecipeTy, mlir::acc::FirstprivateRecipeOp>) {
192 if (!varRecipe->getInit()) {
193 // If we don't have any initialization recipe, we failed during Sema to
194 // initialize this correctly. If we disable the
195 // Sema::TentativeAnalysisScopes in SemaOpenACC::CreateInitRecipe, it'll
196 // emit an error to tell us. However, emitting those errors during
197 // production is a violation of the standard, so we cannot do them.
198 cgf.cgm.errorNYI(
199 exprRange, "firstprivate copy-init recipe not properly generated");
200 }
201
202 createFirstprivateRecipeCopy(loc, locEnd, mainOp, tempDeclEmission,
203 recipe, varRecipe, temporary);
204 }
205 }
206
207public:
212 mlir::OpBuilder::InsertPoint &insertLocation,
213 const Expr *varRef, const VarDecl *varRecipe,
214 const Expr *initExpr, const VarDecl *temporary,
215 OpenACCReductionOperator reductionOp,
216 DeclContext *dc, QualType origType,
217 size_t numBounds,
218 llvm::ArrayRef<QualType> boundTypes,
219 QualType baseType, mlir::Value mainOp) {
220 assert(!varRecipe->getType()->isSpecificBuiltinType(
221 BuiltinType::ArraySection) &&
222 "array section shouldn't make it to recipe creation");
223
224 // TODO: OpenACC: This is a bit of a hackery to get this to not change for
225 // the non-private recipes. This will be removed soon, when we get this
226 // 'right' for firstprivate and reduction.
227 if constexpr (!std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
228 if (numBounds) {
229 cgf.cgm.errorNYI(varRef->getSourceRange(),
230 "firstprivate/reduction-init with bounds");
231 }
232 boundTypes = {};
233 numBounds = 0;
234 origType = baseType;
235 }
236
237 mlir::ModuleOp mod = builder.getBlock()
238 ->getParent()
239 ->template getParentOfType<mlir::ModuleOp>();
240
241 std::string recipeName = getRecipeName(varRef->getSourceRange(), baseType,
242 numBounds, reductionOp);
243 if (auto recipe = mod.lookupSymbol<RecipeTy>(recipeName))
244 return recipe;
245
246 mlir::Location loc = cgf.cgm.getLoc(varRef->getBeginLoc());
247 mlir::Location locEnd = cgf.cgm.getLoc(varRef->getEndLoc());
248
249 mlir::OpBuilder modBuilder(mod.getBodyRegion());
250 if (insertLocation.isSet())
251 modBuilder.restoreInsertionPoint(insertLocation);
252 RecipeTy recipe;
253
254 if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) {
255 recipe = RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType(),
256 convertReductionOp(reductionOp));
257 } else {
258 recipe = RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType());
259 }
260 insertLocation = modBuilder.saveInsertionPoint();
261
262 if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
263 createPrivateInitRecipe(loc, locEnd, varRef->getSourceRange(), mainOp,
264 recipe, numBounds, boundTypes, varRecipe,
265 origType, initExpr);
266 } else {
267 createRecipeInitCopy(loc, locEnd, varRef->getSourceRange(), mainOp,
268 recipe, varRecipe, temporary);
269 }
270
271 if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) {
272 createReductionRecipeCombiner(loc, locEnd, mainOp, recipe);
273 }
274
275 if (origType.isDestructedType())
277 loc, locEnd, mainOp, cgf.getContext().getDeclAlign(varRecipe),
278 origType, numBounds, baseType, recipe.getDestroyRegion());
279 return recipe;
280 }
281};
282} // namespace clang::CIRGen
Defines the clang::ASTContext interface.
Defines the clang::Expr interface and subclasses for C++ expressions.
Defines some OpenACC-specific enums and functions.
C Language Family Type Representation.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:220
void createFirstprivateRecipeCopy(mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp, CIRGenFunction::AutoVarEmission tempDeclEmission, mlir::acc::FirstprivateRecipeOp recipe, const VarDecl *varRecipe, const VarDecl *temporary)
void createPrivateInitRecipe(mlir::Location loc, mlir::Location locEnd, SourceRange exprRange, mlir::Value mainOp, mlir::acc::PrivateRecipeOp recipe, size_t numBounds, llvm::ArrayRef< QualType > boundTypes, const VarDecl *allocaDecl, QualType origType, const Expr *initExpr)
OpenACCRecipeBuilderBase(CIRGen::CIRGenFunction &cgf, CIRGen::CIRGenBuilderTy &builder)
mlir::Value createBoundsLoop(mlir::Value subscriptedValue, mlir::Value bound, mlir::Location loc, bool inverse)
mlir::acc::ReductionOperator convertReductionOp(OpenACCReductionOperator op)
void createReductionRecipeCombiner(mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp, mlir::acc::ReductionRecipeOp recipe)
void createRecipeDestroySection(mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp, CharUnits alignment, QualType origType, size_t numBounds, QualType baseType, mlir::Region &destroyRegion)
mlir::Block * createRecipeBlock(mlir::Region &region, mlir::Type opTy, mlir::Location loc, size_t numBounds, bool isInit)
OpenACCRecipeBuilder(CIRGen::CIRGenFunction &cgf, CIRGen::CIRGenBuilderTy &builder)
RecipeTy getOrCreateRecipe(ASTContext &astCtx, mlir::OpBuilder::InsertPoint &insertLocation, const Expr *varRef, const VarDecl *varRecipe, const Expr *initExpr, const VarDecl *temporary, OpenACCReductionOperator reductionOp, DeclContext *dc, QualType origType, size_t numBounds, llvm::ArrayRef< QualType > boundTypes, QualType baseType, mlir::Value mainOp)
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1449
This represents one expression.
Definition Expr.h:112
MangleContext - Context for tracking state which persists across multiple calls to the C++ name mangl...
Definition Mangle.h:52
virtual void mangleCanonicalTypeName(QualType T, raw_ostream &, bool NormalizeIntegers=false)=0
Generates a unique string for an externally visible type for use with TBAA or type uniquing.
A (possibly-)qualified type.
Definition TypeBase.h:937
DestructionKind isDestructedType() const
Returns a nonzero value if objects of this type require non-trivial work to clean up after.
Definition TypeBase.h:1545
A trivial tuple used to represent a source range.
SourceLocation getEndLoc() const LLVM_READONLY
Definition Stmt.cpp:358
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:334
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:346
bool isSpecificBuiltinType(unsigned K) const
Test for a particular builtin type.
Definition TypeBase.h:8849
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:926
const Expr * getInit() const
Definition Decl.h:1368
OpenACCReductionOperator
@ Invalid
Invalid Reduction Clause Kind.
Represents a scope, including function bodies, compound statements, and the substatements of if/while...