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

clang 22.0.0git
CIRGenOpenACCRecipe.cpp
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// Helperes to emit OpenACC clause recipes as CIR code.
10//
11//===----------------------------------------------------------------------===//
12
13#include <numeric>
14
15#include "CIRGenOpenACCRecipe.h"
16
17namespace clang::CIRGen {
18mlir::Block *OpenACCRecipeBuilderBase::createRecipeBlock(mlir::Region &region,
19 mlir::Type opTy,
20 mlir::Location loc,
21 size_t numBounds,
22 bool isInit) {
24 types.reserve(numBounds + 2);
25 types.push_back(opTy);
26 // The init section is the only one that doesn't have TWO copies of the
27 // operation-type. Copy has a to/from, and destroy has a
28 // 'reference'/'privatized' copy version.
29 if (!isInit)
30 types.push_back(opTy);
31
32 auto boundsTy = mlir::acc::DataBoundsType::get(&cgf.getMLIRContext());
33 for (size_t i = 0; i < numBounds; ++i)
34 types.push_back(boundsTy);
35
36 llvm::SmallVector<mlir::Location> locs{types.size(), loc};
37 return builder.createBlock(&region, region.end(), types, locs);
38}
39void OpenACCRecipeBuilderBase::makeAllocaCopy(mlir::Location loc,
40 mlir::Type copyType,
41 mlir::Value numEltsToCopy,
42 mlir::Value offsetPerSubarray,
43 mlir::Value destAlloca,
44 mlir::Value srcAlloca) {
45 mlir::OpBuilder::InsertionGuard guardCase(builder);
46
47 mlir::Type itrTy = cgf.cgm.convertType(cgf.getContext().UnsignedLongLongTy);
48 auto itrPtrTy = cir::PointerType::get(itrTy);
49 mlir::IntegerAttr itrAlign =
52
53 auto loopBuilder = [&]() {
54 auto itr =
55 cir::AllocaOp::create(builder, loc, itrPtrTy, itrTy, "itr", itrAlign);
56 cir::ConstantOp constZero = builder.getConstInt(loc, itrTy, 0);
57 builder.CIRBaseBuilderTy::createStore(loc, constZero, itr);
59 loc,
60 /*condBuilder=*/
61 [&](mlir::OpBuilder &b, mlir::Location loc) {
62 // itr < numEltsToCopy
63 // Enforce a trip count of 1 if there wasn't any element count, this
64 // way we can just use this loop with a constant bounds instead of a
65 // separate code path.
66 if (!numEltsToCopy)
67 numEltsToCopy = builder.getConstInt(loc, itrTy, 1);
68
69 auto loadCur = cir::LoadOp::create(builder, loc, {itr});
70 auto cmp = builder.createCompare(loc, cir::CmpOpKind::lt, loadCur,
71 numEltsToCopy);
73 },
74 /*bodyBuilder=*/
75 [&](mlir::OpBuilder &b, mlir::Location loc) {
76 // destAlloca[itr] = srcAlloca[offsetPerSubArray * itr];
77 auto loadCur = cir::LoadOp::create(builder, loc, {itr});
78 auto srcOffset = builder.createMul(loc, offsetPerSubarray, loadCur);
79
80 auto ptrToOffsetIntoSrc = cir::PtrStrideOp::create(
81 builder, loc, copyType, srcAlloca, srcOffset);
82
83 auto offsetIntoDecayDest = cir::PtrStrideOp::create(
84 builder, loc, builder.getPointerTo(copyType), destAlloca,
85 loadCur);
86
87 builder.CIRBaseBuilderTy::createStore(loc, ptrToOffsetIntoSrc,
88 offsetIntoDecayDest);
89 builder.createYield(loc);
90 },
91 /*stepBuilder=*/
92 [&](mlir::OpBuilder &b, mlir::Location loc) {
93 // Simple increment of the iterator.
94 auto load = cir::LoadOp::create(builder, loc, {itr});
95 auto inc = cir::UnaryOp::create(builder, loc, load.getType(),
96 cir::UnaryOpKind::Inc, load);
97 builder.CIRBaseBuilderTy::createStore(loc, inc, itr);
98 builder.createYield(loc);
99 });
100 };
101
102 cir::ScopeOp::create(builder, loc,
103 [&](mlir::OpBuilder &b, mlir::Location loc) {
104 loopBuilder();
105 builder.createYield(loc);
106 });
107}
108
109mlir::Value OpenACCRecipeBuilderBase::makeBoundsAlloca(
110 mlir::Block *block, SourceRange exprRange, mlir::Location loc,
111 std::string_view allocaName, size_t numBounds,
112 llvm::ArrayRef<QualType> boundTypes) {
113 mlir::OpBuilder::InsertionGuard guardCase(builder);
114
115 // Get the range of bounds arguments, which are all but the 1st arg.
116 llvm::ArrayRef<mlir::BlockArgument> boundsRange =
117 block->getArguments().drop_front(1);
118
119 // boundTypes contains the before and after of each bounds, so it ends up
120 // having 1 extra. Assert this is the case to ensure we don't call this in the
121 // wrong 'block'.
122 assert(boundsRange.size() + 1 == boundTypes.size());
123
124 mlir::Type itrTy = cgf.cgm.convertType(cgf.getContext().UnsignedLongLongTy);
125 auto idxType = mlir::IndexType::get(&cgf.getMLIRContext());
126
127 auto getUpperBound = [&](mlir::Value bound) {
128 auto upperBoundVal =
129 mlir::acc::GetUpperboundOp::create(builder, loc, idxType, bound);
130 return mlir::UnrealizedConversionCastOp::create(builder, loc, itrTy,
131 upperBoundVal.getResult())
132 .getResult(0);
133 };
134
135 auto isArrayTy = [&](QualType ty) {
136 if (ty->isArrayType() && !ty->isConstantArrayType())
137 cgf.cgm.errorNYI(exprRange, "OpenACC recipe init for VLAs");
138 return ty->isConstantArrayType();
139 };
140
141 mlir::Type topLevelTy = cgf.convertType(boundTypes.back());
142 cir::PointerType topLevelTyPtr = builder.getPointerTo(topLevelTy);
143 // Do an alloca for the 'top' level type without bounds.
144 mlir::Value initialAlloca = builder.createAlloca(
145 loc, topLevelTyPtr, topLevelTy, allocaName,
146 cgf.getContext().getTypeAlignInChars(boundTypes.back()));
147
148 bool lastBoundWasArray = isArrayTy(boundTypes.back());
149
150 // Make sure we track a moving version of this so we can get our
151 // 'copying' back to correct.
152 mlir::Value lastAlloca = initialAlloca;
153
154 // Since we're iterating the types in reverse, this sets up for each index
155 // corresponding to the boundsRange to be the 'after application of the
156 // bounds.
157 llvm::ArrayRef<QualType> boundResults = boundTypes.drop_back(1);
158
159 // Collect the 'do we have any allocas needed after this type' list.
160 llvm::SmallVector<bool> allocasLeftArr;
161 llvm::ArrayRef<QualType> resultTypes = boundTypes.drop_front();
162 std::transform_inclusive_scan(
163 resultTypes.begin(), resultTypes.end(),
164 std::back_inserter(allocasLeftArr), std::plus<bool>{},
165 [](QualType ty) { return !ty->isConstantArrayType(); }, false);
166
167 // Keep track of the number of 'elements' that we're allocating. Individual
168 // allocas should multiply this by the size of its current allocation.
169 mlir::Value cumulativeElts;
170 for (auto [bound, resultType, allocasLeft] : llvm::reverse(
171 llvm::zip_equal(boundsRange, boundResults, allocasLeftArr))) {
172
173 // if there is no further 'alloca' operation we need to do, we can skip
174 // creating the UB/multiplications/etc.
175 if (!allocasLeft)
176 break;
177
178 // First: figure out the number of elements in the current 'bound' list.
179 mlir::Value eltsPerSubArray = getUpperBound(bound);
180 mlir::Value eltsToAlloca;
181
182 // IF we are in a sub-bounds, the total number of elements to alloca is
183 // the product of that one and the current 'bounds' size. That is,
184 // arr[5][5], we would need 25 elements, not just 5. Else it is just the
185 // current number of elements.
186 if (cumulativeElts)
187 eltsToAlloca = builder.createMul(loc, eltsPerSubArray, cumulativeElts);
188 else
189 eltsToAlloca = eltsPerSubArray;
190
191 if (!lastBoundWasArray) {
192 // If we have to do an allocation, figure out the size of the
193 // allocation. alloca takes the number of bytes, not elements.
194 TypeInfoChars eltInfo = cgf.getContext().getTypeInfoInChars(resultType);
195 cir::ConstantOp eltSize = builder.getConstInt(
196 loc, itrTy, eltInfo.Width.alignTo(eltInfo.Align).getQuantity());
197 mlir::Value curSize = builder.createMul(loc, eltsToAlloca, eltSize);
198
199 mlir::Type eltTy = cgf.convertType(resultType);
200 cir::PointerType ptrTy = builder.getPointerTo(eltTy);
201 mlir::Value curAlloca = builder.createAlloca(
202 loc, ptrTy, eltTy, "openacc.init.bounds",
203 cgf.getContext().getTypeAlignInChars(resultType), curSize);
204
205 makeAllocaCopy(loc, ptrTy, cumulativeElts, eltsPerSubArray, lastAlloca,
206 curAlloca);
207 lastAlloca = curAlloca;
208 } else {
209 // In the case of an array, we just need to decay the pointer, so just do
210 // a zero-offset stride on the last alloca to decay it down an array
211 // level.
212 cir::ConstantOp constZero = builder.getConstInt(loc, itrTy, 0);
213 lastAlloca = builder.getArrayElement(loc, loc, lastAlloca,
214 cgf.convertType(resultType),
215 constZero, /*shouldDecay=*/true);
216 }
217
218 cumulativeElts = eltsToAlloca;
219 lastBoundWasArray = isArrayTy(resultType);
220 }
221 return initialAlloca;
222}
223
224mlir::Value
226 mlir::Value bound,
227 mlir::Location loc, bool inverse) {
228 mlir::Operation *bodyInsertLoc;
229
230 mlir::Type itrTy = cgf.cgm.convertType(cgf.getContext().UnsignedLongLongTy);
231 auto itrPtrTy = cir::PointerType::get(itrTy);
232 mlir::IntegerAttr itrAlign =
233 cgf.cgm.getSize(cgf.getContext().getTypeAlignInChars(
234 cgf.getContext().UnsignedLongLongTy));
235 auto idxType = mlir::IndexType::get(&cgf.getMLIRContext());
236
237 auto doSubscriptOp = [&](mlir::Value subVal,
238 cir::LoadOp idxLoad) -> mlir::Value {
239 auto eltTy = cast<cir::PointerType>(subVal.getType()).getPointee();
240
241 if (auto arrayTy = dyn_cast<cir::ArrayType>(eltTy))
242 return builder.getArrayElement(loc, loc, subVal, arrayTy.getElementType(),
243 idxLoad,
244 /*shouldDecay=*/true);
245
246 assert(isa<cir::PointerType>(eltTy));
247
248 auto eltLoad = cir::LoadOp::create(builder, loc, {subVal});
249
250 return cir::PtrStrideOp::create(builder, loc, eltLoad.getType(), eltLoad,
251 idxLoad);
252
253 };
254
255 auto forStmtBuilder = [&]() {
256 // get the lower and upper bound for iterating over.
257 auto lowerBoundVal =
258 mlir::acc::GetLowerboundOp::create(builder, loc, idxType, bound);
259 auto lbConversion = mlir::UnrealizedConversionCastOp::create(
260 builder, loc, itrTy, lowerBoundVal.getResult());
261 auto upperBoundVal =
262 mlir::acc::GetUpperboundOp::create(builder, loc, idxType, bound);
263 auto ubConversion = mlir::UnrealizedConversionCastOp::create(
264 builder, loc, itrTy, upperBoundVal.getResult());
265
266 // Create a memory location for the iterator.
267 auto itr =
268 cir::AllocaOp::create(builder, loc, itrPtrTy, itrTy, "iter", itrAlign);
269 // Store to the iterator: either lower bound, or if inverse loop, upper
270 // bound.
271 if (inverse) {
272 cir::ConstantOp constOne = builder.getConstInt(loc, itrTy, 1);
273
274 auto sub = cir::BinOp::create(builder, loc, itrTy, cir::BinOpKind::Sub,
275 ubConversion.getResult(0), constOne);
276
277 // Upperbound is exclusive, so subtract 1.
278 builder.CIRBaseBuilderTy::createStore(loc, sub, itr);
279 } else {
280 // Lowerbound is inclusive, so we can include it.
281 builder.CIRBaseBuilderTy::createStore(loc, lbConversion.getResult(0),
282 itr);
283 }
284 // Save the 'end' iterator based on whether we are inverted or not. This
285 // end iterator never changes, so we can just get it and convert it, so no
286 // need to store/load/etc.
287 auto endItr = inverse ? lbConversion : ubConversion;
288
289 builder.createFor(
290 loc,
291 /*condBuilder=*/
292 [&](mlir::OpBuilder &b, mlir::Location loc) {
293 auto loadCur = cir::LoadOp::create(builder, loc, {itr});
294 // Use 'not equal' since we are just doing an increment/decrement.
295 auto cmp = builder.createCompare(
296 loc, inverse ? cir::CmpOpKind::ge : cir::CmpOpKind::lt, loadCur,
297 endItr.getResult(0));
298 builder.createCondition(cmp);
299 },
300 /*bodyBuilder=*/
301 [&](mlir::OpBuilder &b, mlir::Location loc) {
302 auto load = cir::LoadOp::create(builder, loc, {itr});
303
304 if (subscriptedValue)
305 subscriptedValue = doSubscriptOp(subscriptedValue, load);
306 bodyInsertLoc = builder.createYield(loc);
307 },
308 /*stepBuilder=*/
309 [&](mlir::OpBuilder &b, mlir::Location loc) {
310 auto load = cir::LoadOp::create(builder, loc, {itr});
311 auto unary = cir::UnaryOp::create(
312 builder, loc, load.getType(),
313 inverse ? cir::UnaryOpKind::Dec : cir::UnaryOpKind::Inc, load);
314 builder.CIRBaseBuilderTy::createStore(loc, unary, itr);
315 builder.createYield(loc);
316 });
317 };
318
319 cir::ScopeOp::create(builder, loc,
320 [&](mlir::OpBuilder &b, mlir::Location loc) {
321 forStmtBuilder();
322 builder.createYield(loc);
323 });
324
325 // Leave the insertion point to be inside the body, so we can loop over
326 // these things.
327 builder.setInsertionPoint(bodyInsertLoc);
328 return subscriptedValue;
329}
330
331mlir::acc::ReductionOperator
333 switch (op) {
335 return mlir::acc::ReductionOperator::AccAdd;
337 return mlir::acc::ReductionOperator::AccMul;
339 return mlir::acc::ReductionOperator::AccMax;
341 return mlir::acc::ReductionOperator::AccMin;
343 return mlir::acc::ReductionOperator::AccIand;
345 return mlir::acc::ReductionOperator::AccIor;
347 return mlir::acc::ReductionOperator::AccXor;
349 return mlir::acc::ReductionOperator::AccLand;
351 return mlir::acc::ReductionOperator::AccLor;
353 llvm_unreachable("invalid reduction operator");
354 }
355
356 llvm_unreachable("invalid reduction operator");
357}
358
359// This function generates the 'destroy' section for a recipe. Note
360// that this function is not 'insertion point' clean, in that it alters the
361// insertion point to be inside of the 'destroy' section of the recipe, but
362// doesn't restore it aftewards.
364 mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
365 CharUnits alignment, QualType origType, size_t numBounds, QualType baseType,
366 mlir::Region &destroyRegion) {
367 mlir::Block *block = createRecipeBlock(destroyRegion, mainOp.getType(), loc,
368 numBounds, /*isInit=*/false);
369 builder.setInsertionPointToEnd(&destroyRegion.back());
370 CIRGenFunction::LexicalScope ls(cgf, loc, block);
371
372 mlir::Type elementTy =
373 mlir::cast<cir::PointerType>(mainOp.getType()).getPointee();
374 auto emitDestroy = [&](mlir::Value var, mlir::Type ty) {
375 Address addr{var, ty, alignment};
376 cgf.emitDestroy(addr, origType,
377 cgf.getDestroyer(QualType::DK_cxx_destructor));
378 };
379
380 if (numBounds) {
381 mlir::OpBuilder::InsertionGuard guardCase(builder);
382 // Get the range of bounds arguments, which are all but the 1st 2. 1st is
383 // a 'reference', 2nd is the 'private' variant we need to destroy from.
385 block->getArguments().drop_front(2);
386
387 mlir::Value subscriptedValue = block->getArgument(1);
388 for (mlir::BlockArgument boundArg : llvm::reverse(boundsRange))
389 subscriptedValue = createBoundsLoop(subscriptedValue, boundArg, loc,
390 /*inverse=*/true);
391
392 emitDestroy(subscriptedValue, cgf.cgm.convertType(origType));
393 } else {
394 // If we don't have any bounds, we can just destroy the variable directly.
395 // The destroy region has a signature of "original item, privatized item".
396 // So the 2nd item is the one that needs destroying, the former is just
397 // for reference and we don't really have a need for it at the moment.
398 emitDestroy(block->getArgument(1), elementTy);
399 }
400
401 mlir::acc::YieldOp::create(builder, locEnd);
402}
403
404// TODO: OpenACC: When we get this implemented for the reduction/firstprivate,
405// this might end up re-merging with createRecipeInitCopy. For now, keep it
406// separate until we're sure what everything looks like to keep this as clean
407// as possible.
409 mlir::Location loc, mlir::Location locEnd, SourceRange exprRange,
410 mlir::Value mainOp, mlir::acc::PrivateRecipeOp recipe, size_t numBounds,
411 llvm::ArrayRef<QualType> boundTypes, const VarDecl *allocaDecl,
412 QualType origType, const Expr *initExpr) {
413 assert(allocaDecl && "Required recipe variable not set?");
414 CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, allocaDecl};
415
416 mlir::Block *block =
417 createRecipeBlock(recipe.getInitRegion(), mainOp.getType(), loc,
418 numBounds, /*isInit=*/true);
419 builder.setInsertionPointToEnd(&recipe.getInitRegion().back());
420 CIRGenFunction::LexicalScope ls(cgf, loc, block);
421
422 const Type *allocaPointeeType =
423 allocaDecl->getType()->getPointeeOrArrayElementType();
424 // We are OK with no init for builtins, arrays of builtins, or pointers,
425 // else we should NYI so we know to go look for these.
426 if (cgf.getContext().getLangOpts().CPlusPlus && !allocaDecl->getInit() &&
427 !allocaDecl->getType()->isPointerType() &&
428 !allocaPointeeType->isBuiltinType() &&
429 !allocaPointeeType->isPointerType()) {
430 // If we don't have any initialization recipe, we failed during Sema to
431 // initialize this correctly. If we disable the
432 // Sema::TentativeAnalysisScopes in SemaOpenACC::CreateInitRecipe, it'll
433 // emit an error to tell us. However, emitting those errors during
434 // production is a violation of the standard, so we cannot do them.
435 cgf.cgm.errorNYI(exprRange, "private default-init recipe");
436 }
437
438 if (!numBounds) {
439 // This is an 'easy' case, we just have to use the builtin init stuff to
440 // initialize this variable correctly.
441 CIRGenFunction::AutoVarEmission tempDeclEmission =
442 cgf.emitAutoVarAlloca(*allocaDecl, builder.saveInsertionPoint());
443 cgf.emitAutoVarInit(tempDeclEmission);
444 } else {
445 makeBoundsAlloca(block, exprRange, loc, "openacc.private.init", numBounds,
446 boundTypes);
447
448 if (initExpr)
449 cgf.cgm.errorNYI(exprRange, "private-init with bounds initialization");
450 }
451
452 mlir::acc::YieldOp::create(builder, locEnd);
453}
454
456 mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
457 CIRGenFunction::AutoVarEmission tempDeclEmission,
458 mlir::acc::FirstprivateRecipeOp recipe, const VarDecl *varRecipe,
459 const VarDecl *temporary) {
460 mlir::Block *block =
461 createRecipeBlock(recipe.getCopyRegion(), mainOp.getType(), loc,
462 /*numBounds=*/0, /*isInit=*/false);
463 builder.setInsertionPointToEnd(&recipe.getCopyRegion().back());
464 CIRGenFunction::LexicalScope ls(cgf, loc, block);
465
466 mlir::BlockArgument fromArg = block->getArgument(0);
467 mlir::BlockArgument toArg = block->getArgument(1);
468
469 mlir::Type elementTy =
470 mlir::cast<cir::PointerType>(mainOp.getType()).getPointee();
471
472 // Set the address of the emission to be the argument, so that we initialize
473 // that instead of the variable in the other block.
474 tempDeclEmission.setAllocatedAddress(
475 Address{toArg, elementTy, cgf.getContext().getDeclAlign(varRecipe)});
476 tempDeclEmission.EmittedAsOffload = true;
477
478 CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, temporary};
479 cgf.setAddrOfLocalVar(
480 temporary,
481 Address{fromArg, elementTy, cgf.getContext().getDeclAlign(varRecipe)});
482
483 cgf.emitAutoVarInit(tempDeclEmission);
484 mlir::acc::YieldOp::create(builder, locEnd);
485}
486// This function generates the 'combiner' section for a reduction recipe. Note
487// that this function is not 'insertion point' clean, in that it alters the
488// insertion point to be inside of the 'combiner' section of the recipe, but
489// doesn't restore it aftewards.
491 mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
492 mlir::acc::ReductionRecipeOp recipe) {
493 mlir::Block *block = builder.createBlock(
494 &recipe.getCombinerRegion(), recipe.getCombinerRegion().end(),
495 {mainOp.getType(), mainOp.getType()}, {loc, loc});
496 builder.setInsertionPointToEnd(&recipe.getCombinerRegion().back());
497 CIRGenFunction::LexicalScope ls(cgf, loc, block);
498
499 mlir::BlockArgument lhsArg = block->getArgument(0);
500
501 mlir::acc::YieldOp::create(builder, locEnd, lhsArg);
502}
503
504} // namespace clang::CIRGen
__device__ __2f16 b
cir::ConditionOp createCondition(mlir::Value condition)
Create a loop condition.
cir::ForOp createFor(mlir::Location loc, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> condBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> bodyBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> stepBuilder)
Create a for operation.
cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs)
CharUnits getTypeAlignInChars(QualType T) const
Return the ABI-specified alignment of a (complete) type T, in characters.
CanQualType UnsignedLongLongTy
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal)
clang::ASTContext & getContext() const
mlir::Type convertType(clang::QualType type)
mlir::IntegerAttr getSize(CharUnits size)
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)
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)
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
This represents one expression.
Definition Expr.h:112
A (possibly-)qualified type.
Definition TypeBase.h:937
A trivial tuple used to represent a source range.
const Type * getPointeeOrArrayElementType() const
If this is a pointer type, return the pointee type.
Definition TypeBase.h:9060
bool isPointerType() const
Definition TypeBase.h:8524
bool isBuiltinType() const
Helper methods to distinguish type categories.
Definition TypeBase.h:8647
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
@ Type
The l-value was considered opaque, so the alignment was determined from a type.
OpenACCReductionOperator
@ Invalid
Invalid Reduction Clause Kind.
bool isa(CodeGen::Address addr)
Definition Address.h:330
U cast(CodeGen::Address addr)
Definition Address.h:327
bool EmittedAsOffload
True if the variable was emitted as an offload recipe, and thus doesn't have the same sort of alloca ...
Represents a scope, including function bodies, compound statements, and the substatements of if/while...