24 types.reserve(numBounds + 2);
25 types.push_back(opTy);
30 types.push_back(opTy);
32 auto boundsTy = mlir::acc::DataBoundsType::get(&
cgf.getMLIRContext());
33 for (
size_t i = 0; i < numBounds; ++i)
34 types.push_back(boundsTy);
37 return builder.createBlock(®ion, region.end(), types, locs);
39void OpenACCRecipeBuilderBase::makeAllocaCopy(mlir::Location loc,
41 mlir::Value numEltsToCopy,
42 mlir::Value offsetPerSubarray,
43 mlir::Value destAlloca,
44 mlir::Value srcAlloca) {
45 mlir::OpBuilder::InsertionGuard guardCase(
builder);
48 auto itrPtrTy = cir::PointerType::get(itrTy);
49 mlir::IntegerAttr itrAlign =
53 auto loopBuilder = [&]() {
55 cir::AllocaOp::create(
builder, loc, itrPtrTy, itrTy,
"itr", itrAlign);
57 builder.CIRBaseBuilderTy::createStore(loc, constZero, itr);
61 [&](mlir::OpBuilder &
b, mlir::Location loc) {
69 auto loadCur = cir::LoadOp::create(
builder, loc, {itr});
75 [&](mlir::OpBuilder &
b, mlir::Location loc) {
77 auto loadCur = cir::LoadOp::create(
builder, loc, {itr});
78 auto srcOffset =
builder.createMul(loc, offsetPerSubarray, loadCur);
80 auto ptrToOffsetIntoSrc = cir::PtrStrideOp::create(
81 builder, loc, copyType, srcAlloca, srcOffset);
83 auto offsetIntoDecayDest = cir::PtrStrideOp::create(
87 builder.CIRBaseBuilderTy::createStore(loc, ptrToOffsetIntoSrc,
92 [&](mlir::OpBuilder &
b, mlir::Location loc) {
94 auto load = cir::LoadOp::create(
builder, loc, {itr});
95 auto inc =
builder.createInc(loc, load);
96 builder.CIRBaseBuilderTy::createStore(loc, inc, itr);
101 cir::ScopeOp::create(
builder, loc,
102 [&](mlir::OpBuilder &
b, mlir::Location loc) {
108mlir::Value OpenACCRecipeBuilderBase::makeBoundsAlloca(
109 mlir::Block *block, SourceRange exprRange, mlir::Location loc,
110 std::string_view allocaName,
size_t numBounds,
111 llvm::ArrayRef<QualType> boundTypes) {
112 mlir::OpBuilder::InsertionGuard guardCase(
builder);
115 llvm::ArrayRef<mlir::BlockArgument> boundsRange =
116 block->getArguments().drop_front(1);
121 assert(boundsRange.size() + 1 == boundTypes.size());
123 mlir::Type itrTy =
cgf.cgm.convertType(
cgf.getContext().UnsignedLongLongTy);
124 auto idxType = mlir::IndexType::get(&
cgf.getMLIRContext());
126 auto getUpperBound = [&](mlir::Value bound) {
128 mlir::acc::GetUpperboundOp::create(
builder, loc, idxType, bound);
129 return mlir::UnrealizedConversionCastOp::create(
builder, loc, itrTy,
130 upperBoundVal.getResult())
134 auto isArrayTy = [&](QualType ty) {
135 if (ty->isArrayType() && !ty->isConstantArrayType())
136 cgf.cgm.errorNYI(exprRange,
"OpenACC recipe init for VLAs");
137 return ty->isConstantArrayType();
140 mlir::Type topLevelTy =
cgf.convertType(boundTypes.back());
141 cir::PointerType topLevelTyPtr =
builder.getPointerTo(topLevelTy);
143 mlir::Value initialAlloca =
builder.createAlloca(
144 loc, topLevelTyPtr, topLevelTy, allocaName,
145 cgf.getContext().getTypeAlignInChars(boundTypes.back()));
147 bool lastBoundWasArray = isArrayTy(boundTypes.back());
151 mlir::Value lastAlloca = initialAlloca;
156 llvm::ArrayRef<QualType> boundResults = boundTypes.drop_back(1);
159 llvm::SmallVector<bool> allocasLeftArr;
160 llvm::ArrayRef<QualType> resultTypes = boundTypes.drop_front();
161 std::transform_inclusive_scan(
162 resultTypes.begin(), resultTypes.end(),
163 std::back_inserter(allocasLeftArr), std::plus<bool>{},
164 [](QualType ty) { return !ty->isConstantArrayType(); },
false);
168 mlir::Value cumulativeElts;
169 for (
auto [bound, resultType, allocasLeft] : llvm::reverse(
170 llvm::zip_equal(boundsRange, boundResults, allocasLeftArr))) {
178 mlir::Value eltsPerSubArray = getUpperBound(bound);
179 mlir::Value eltsToAlloca;
186 eltsToAlloca =
builder.createMul(loc, eltsPerSubArray, cumulativeElts);
188 eltsToAlloca = eltsPerSubArray;
190 if (!lastBoundWasArray) {
193 TypeInfoChars eltInfo =
cgf.getContext().getTypeInfoInChars(resultType);
194 cir::ConstantOp eltSize =
builder.getConstInt(
195 loc, itrTy, eltInfo.Width.alignTo(eltInfo.Align).getQuantity());
196 mlir::Value curSize =
builder.createMul(loc, eltsToAlloca, eltSize);
198 mlir::Type eltTy =
cgf.convertType(resultType);
199 cir::PointerType ptrTy =
builder.getPointerTo(eltTy);
200 mlir::Value curAlloca =
builder.createAlloca(
201 loc, ptrTy, eltTy,
"openacc.init.bounds",
202 cgf.getContext().getTypeAlignInChars(resultType), curSize);
204 makeAllocaCopy(loc, ptrTy, cumulativeElts, eltsPerSubArray, lastAlloca,
206 lastAlloca = curAlloca;
211 cir::ConstantOp constZero =
builder.getConstInt(loc, itrTy, 0);
212 lastAlloca =
builder.getArrayElement(loc, loc, lastAlloca,
213 cgf.convertType(resultType),
217 cumulativeElts = eltsToAlloca;
218 lastBoundWasArray = isArrayTy(resultType);
220 return initialAlloca;
224 mlir::Value subscriptedValue, mlir::Value subscriptedValue2,
225 mlir::Value bound, mlir::Location loc,
bool inverse) {
226 mlir::Operation *bodyInsertLoc;
228 mlir::Type itrTy =
cgf.cgm.convertType(
cgf.getContext().UnsignedLongLongTy);
229 auto itrPtrTy = cir::PointerType::get(itrTy);
230 mlir::IntegerAttr itrAlign =
231 cgf.cgm.getSize(
cgf.getContext().getTypeAlignInChars(
232 cgf.getContext().UnsignedLongLongTy));
233 auto idxType = mlir::IndexType::get(&
cgf.getMLIRContext());
235 auto doSubscriptOp = [&](mlir::Value subVal,
236 cir::LoadOp idxLoad) -> mlir::Value {
239 if (
auto arrayTy = dyn_cast<cir::ArrayType>(eltTy))
240 return builder.getArrayElement(loc, loc, subVal, arrayTy.getElementType(),
246 auto eltLoad = cir::LoadOp::create(
builder, loc, {subVal});
248 return cir::PtrStrideOp::create(
builder, loc, eltLoad.getType(), eltLoad,
252 auto forStmtBuilder = [&]() {
255 mlir::acc::GetLowerboundOp::create(
builder, loc, idxType, bound);
256 auto lbConversion = mlir::UnrealizedConversionCastOp::create(
257 builder, loc, itrTy, lowerBoundVal.getResult());
259 mlir::acc::GetUpperboundOp::create(
builder, loc, idxType, bound);
260 auto ubConversion = mlir::UnrealizedConversionCastOp::create(
261 builder, loc, itrTy, upperBoundVal.getResult());
265 cir::AllocaOp::create(
builder, loc, itrPtrTy, itrTy,
"iter", itrAlign);
269 cir::ConstantOp constOne =
builder.getConstInt(loc, itrTy, 1);
272 cir::SubOp::create(
builder, loc, ubConversion.getResult(0), constOne);
275 builder.CIRBaseBuilderTy::createStore(loc, sub, itr);
278 builder.CIRBaseBuilderTy::createStore(loc, lbConversion.getResult(0),
284 auto endItr = inverse ? lbConversion : ubConversion;
289 [&](mlir::OpBuilder &
b, mlir::Location loc) {
290 auto loadCur = cir::LoadOp::create(
builder, loc, {itr});
292 auto cmp =
builder.createCompare(
293 loc, inverse ? cir::CmpOpKind::ge : cir::CmpOpKind::lt, loadCur,
294 endItr.getResult(0));
298 [&](mlir::OpBuilder &
b, mlir::Location loc) {
299 auto load = cir::LoadOp::create(
builder, loc, {itr});
301 if (subscriptedValue)
302 subscriptedValue = doSubscriptOp(subscriptedValue, load);
303 if (subscriptedValue2)
304 subscriptedValue2 = doSubscriptOp(subscriptedValue2, load);
305 bodyInsertLoc =
builder.createYield(loc);
308 [&](mlir::OpBuilder &
b, mlir::Location loc) {
309 auto load = cir::LoadOp::create(
builder, loc, {itr});
310 auto unary = inverse ?
builder.createDec(loc, load)
311 :
builder.createInc(loc, load);
312 builder.CIRBaseBuilderTy::createStore(loc, unary, itr);
317 cir::ScopeOp::create(
builder, loc,
318 [&](mlir::OpBuilder &
b, mlir::Location loc) {
325 builder.setInsertionPoint(bodyInsertLoc);
326 return {subscriptedValue, subscriptedValue2};
329mlir::acc::ReductionOperator
333 return mlir::acc::ReductionOperator::AccAdd;
335 return mlir::acc::ReductionOperator::AccMul;
337 return mlir::acc::ReductionOperator::AccMax;
339 return mlir::acc::ReductionOperator::AccMin;
341 return mlir::acc::ReductionOperator::AccIand;
343 return mlir::acc::ReductionOperator::AccIor;
345 return mlir::acc::ReductionOperator::AccXor;
347 return mlir::acc::ReductionOperator::AccLand;
349 return mlir::acc::ReductionOperator::AccLor;
351 llvm_unreachable(
"invalid reduction operator");
354 llvm_unreachable(
"invalid reduction operator");
362 mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
364 mlir::Region &destroyRegion) {
367 builder.setInsertionPointToEnd(&destroyRegion.back());
370 mlir::Type elementTy =
371 mlir::cast<cir::PointerType>(mainOp.getType()).getPointee();
372 auto emitDestroy = [&](mlir::Value var, mlir::Type ty) {
373 Address addr{var, ty, alignment};
374 cgf.emitDestroy(addr, origType,
379 mlir::OpBuilder::InsertionGuard guardCase(
builder);
383 block->getArguments().drop_front(2);
385 mlir::Value subscriptedValue = block->getArgument(1);
386 for (mlir::BlockArgument boundArg : llvm::reverse(boundsRange))
390 emitDestroy(subscriptedValue,
cgf.cgm.convertType(origType));
396 emitDestroy(block->getArgument(1), elementTy);
400 mlir::acc::YieldOp::create(
builder, locEnd);
402void OpenACCRecipeBuilderBase::makeBoundsInit(
403 mlir::Value alloca, mlir::Location loc, mlir::Block *block,
405 mlir::OpBuilder::InsertionGuard guardCase(
builder);
406 builder.setInsertionPointToEnd(block);
416 block->getArguments().drop_front(isInitSection ? 1 : 2);
418 mlir::Value subscriptedValue = alloca;
419 for (mlir::BlockArgument boundArg : llvm::reverse(boundsRange))
433 mlir::Location loc, mlir::Location locEnd,
SourceRange exprRange,
434 mlir::Value mainOp, mlir::Region &recipeInitRegion,
size_t numBounds,
436 QualType origType,
bool emitInitExpr) {
437 assert(allocaDecl &&
"Required recipe variable not set?");
441 loc, numBounds,
true);
442 builder.setInsertionPointToEnd(&recipeInitRegion.back());
445 const Type *allocaPointeeType =
449 if (
cgf.getContext().getLangOpts().CPlusPlus && !allocaDecl->
getInit() &&
458 cgf.cgm.errorNYI(exprRange,
"private/reduction default-init recipe");
465 cgf.emitAutoVarAlloca(*allocaDecl,
builder.saveInsertionPoint());
467 cgf.emitAutoVarInit(tempDeclEmission);
469 mlir::Value alloca = makeBoundsAlloca(
470 block, exprRange, loc, allocaDecl->
getName(), numBounds, boundTypes);
474 if (emitInitExpr && allocaDecl->
getInit() &&
475 (!
cgf.isTrivialInitializer(allocaDecl->
getInit()) ||
476 cgf.getContext().getLangOpts().getTrivialAutoVarInit() !=
478 makeBoundsInit(alloca, loc, block, allocaDecl, origType,
483 mlir::acc::YieldOp::create(
builder, locEnd);
487 mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
489 mlir::Region ©Region,
size_t numBounds) {
492 builder.setInsertionPointToEnd(©Region.back());
495 mlir::Value fromArg = block->getArgument(0);
496 mlir::Value toArg = block->getArgument(1);
499 block->getArguments().drop_front(2);
501 for (mlir::BlockArgument boundArg : llvm::reverse(boundsRange))
502 std::tie(fromArg, toArg) =
506 mlir::Type elementTy =
507 mlir::cast<cir::PointerType>(toArg.getType()).getPointee();
511 Address{toArg, elementTy,
cgf.getContext().getDeclAlign(allocaDecl)});
515 cgf.setAddrOfLocalVar(
517 Address{fromArg, elementTy,
cgf.getContext().getDeclAlign(allocaDecl)});
518 cgf.emitAutoVarInit(tempDeclEmission);
520 builder.setInsertionPointToEnd(©Region.back());
522 mlir::acc::YieldOp::create(
builder, locEnd);
530 mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
531 mlir::acc::ReductionRecipeOp recipe,
size_t numBounds,
QualType origType,
536 builder.setInsertionPointToEnd(&recipe.getCombinerRegion().back());
539 mlir::Value lhsArg = block->getArgument(0);
540 mlir::Value rhsArg = block->getArgument(1);
542 block->getArguments().drop_front(2);
544 if (llvm::any_of(combinerRecipes, [](
auto &r) {
return r.Op ==
nullptr; })) {
545 cgf.cgm.errorNYI(loc,
"OpenACC Reduction combiner not generated");
546 mlir::acc::YieldOp::create(
builder, locEnd, block->getArgument(0));
551 for (mlir::BlockArgument boundArg : llvm::reverse(boundsRange))
552 std::tie(lhsArg, rhsArg) =
558 auto emitSingleCombiner =
559 [&](mlir::Value lhsArg, mlir::Value rhsArg,
561 mlir::Type elementTy =
562 mlir::cast<cir::PointerType>(lhsArg.getType()).getPointee();
564 cgf.setAddrOfLocalVar(
565 combiner.LHS,
Address{lhsArg, elementTy,
566 cgf.getContext().getDeclAlign(combiner.LHS)});
568 cgf.setAddrOfLocalVar(
569 combiner.RHS,
Address{rhsArg, elementTy,
570 cgf.getContext().getDeclAlign(combiner.RHS)});
572 [[maybe_unused]] mlir::LogicalResult stmtRes =
573 cgf.emitStmt(combiner.Op,
true);
580 auto emitCombiner = [&](mlir::Value lhsArg, mlir::Value rhsArg,
QualType ty) {
581 assert(!ty->isArrayType() &&
"Array type shouldn't get here");
582 if (
const auto *rd = ty->getAsRecordDecl()) {
583 if (combinerRecipes.size() == 1 &&
584 cgf.getContext().hasSameType(ty, combinerRecipes[0].LHS->getType())) {
587 emitSingleCombiner(lhsArg, rhsArg, combinerRecipes[0]);
592 cgf.cgm.getTypes().getCIRGenRecordLayout(rd);
593 for (
const auto &[field, combiner] :
594 llvm::zip_equal(rd->fields(), combinerRecipes)) {
595 mlir::Type fieldType =
cgf.convertType(field->getType());
596 auto fieldPtr = cir::PointerType::get(fieldType);
599 mlir::Value lhsField =
builder.createGetMember(
600 loc, fieldPtr, lhsArg, field->getName(), fieldIndex);
601 mlir::Value rhsField =
builder.createGetMember(
602 loc, fieldPtr, rhsArg, field->getName(), fieldIndex);
604 emitSingleCombiner(lhsField, rhsField, combiner);
611 emitSingleCombiner(lhsArg, rhsArg, combinerRecipes[0]);
615 if (
const auto *cat =
cgf.getContext().getAsConstantArrayType(origType)) {
618 auto itrTy = mlir::cast<cir::IntType>(
cgf.ptrDiffTy);
619 auto itrPtrTy = cir::PointerType::get(itrTy);
622 builder.getConstInt(loc, mlir::cast<cir::IntType>(
cgf.ptrDiffTy), 0);
624 cir::AllocaOp::create(
builder, loc, itrPtrTy, itrTy,
"itr",
625 cgf.cgm.getSize(
cgf.getPointerAlign()));
626 builder.CIRBaseBuilderTy::createStore(loc, zero, itr);
631 [&](mlir::OpBuilder &
b, mlir::Location loc) {
632 auto loadItr = cir::LoadOp::create(builder, loc, {itr});
633 mlir::Value arraySize =
builder.getConstInt(
634 loc, mlir::cast<cir::IntType>(
cgf.ptrDiffTy), cat->getZExtSize());
635 auto cmp =
builder.createCompare(loc, cir::CmpOpKind::lt, loadItr,
640 [&](mlir::OpBuilder &
b, mlir::Location loc) {
641 auto loadItr = cir::LoadOp::create(
builder, loc, {itr});
642 auto lhsElt =
builder.getArrayElement(
643 loc, loc, lhsArg,
cgf.convertType(cat->getElementType()), loadItr,
645 auto rhsElt =
builder.getArrayElement(
646 loc, loc, rhsArg,
cgf.convertType(cat->getElementType()), loadItr,
649 emitCombiner(lhsElt, rhsElt, cat->getElementType());
653 [&](mlir::OpBuilder &
b, mlir::Location loc) {
654 auto loadItr = cir::LoadOp::create(
builder, loc, {itr});
655 auto inc =
builder.createInc(loc, loadItr);
656 builder.CIRBaseBuilderTy::createStore(loc, inc, itr);
661 cgf.cgm.errorNYI(loc,
662 "OpenACC Reduction combiner non-constant array recipe");
664 emitCombiner(lhsArg, rhsArg, origType);
667 builder.setInsertionPointToEnd(&recipe.getCombinerRegion().back());
669 mlir::acc::YieldOp::create(builder, locEnd, block->getArgument(0));
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.
CharUnits getDeclAlign(const Decl *D, bool ForAlignof=false) const
Return a conservative estimate of the alignment of the specified decl D.
CanQualType UnsignedLongLongTy
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal)
void forceCleanup(ArrayRef< mlir::Value * > valuesToReload={})
Force the emission of cleanups now, instead of waiting until this object is destroyed.
mlir::Type convertType(clang::QualType t)
void emitAutoVarInit(const AutoVarEmission &emission)
Emit the initializer for an allocated variable.
clang::ASTContext & getContext() const
mlir::Type convertType(clang::QualType type)
mlir::IntegerAttr getSize(CharUnits size)
This class handles record and union layout info while lowering AST types to CIR types.
unsigned getCIRFieldNo(const clang::FieldDecl *fd) const
Return cir::RecordType element number that corresponds to the field FD.
void createReductionRecipeCombiner(mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp, mlir::acc::ReductionRecipeOp recipe, size_t numBounds, QualType origType, llvm::ArrayRef< OpenACCReductionRecipe::CombinerRecipe > combinerRecipes)
void createInitRecipe(mlir::Location loc, mlir::Location locEnd, SourceRange exprRange, mlir::Value mainOp, mlir::Region &recipeInitRegion, size_t numBounds, llvm::ArrayRef< QualType > boundTypes, const VarDecl *allocaDecl, QualType origType, bool emitInitExpr)
CIRGen::CIRGenBuilderTy & builder
void createFirstprivateRecipeCopy(mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp, const VarDecl *allocaDecl, const VarDecl *temporary, mlir::Region ©Region, size_t numBounds)
mlir::acc::ReductionOperator convertReductionOp(OpenACCReductionOperator op)
CIRGen::CIRGenFunction & cgf
std::pair< mlir::Value, mlir::Value > createBoundsLoop(mlir::Value subscriptedValue, mlir::Value subscriptedValue2, mlir::Value bound, mlir::Location loc, bool inverse)
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 ®ion, mlir::Type opTy, mlir::Location loc, size_t numBounds, bool isInit)
CharUnits - This is an opaque type for sizes expressed in character units.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
A (possibly-)qualified type.
A trivial tuple used to represent a source range.
const Type * getPointeeOrArrayElementType() const
If this is a pointer type, return the pointee type.
bool isPointerType() const
bool isBuiltinType() const
Helper methods to distinguish type categories.
Represents a variable declaration or definition.
const Expr * getInit() const
@ Type
The l-value was considered opaque, so the alignment was determined from a type.
@ Invalid
Invalid Reduction Clause Kind.
bool isa(CodeGen::Address addr)
U cast(CodeGen::Address addr)
bool emittedAsOffload
True if the variable was emitted as an offload recipe, and thus doesn't have the same sort of alloca ...
void setAllocatedAddress(Address a)
Represents a scope, including function bodies, compound statements, and the substatements of if/while...