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 = cir::UnaryOp::create(
builder, loc, load.getType(),
96 cir::UnaryOpKind::Inc, load);
97 builder.CIRBaseBuilderTy::createStore(loc, inc, itr);
102 cir::ScopeOp::create(
builder, loc,
103 [&](mlir::OpBuilder &
b, mlir::Location loc) {
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);
116 llvm::ArrayRef<mlir::BlockArgument> boundsRange =
117 block->getArguments().drop_front(1);
122 assert(boundsRange.size() + 1 == boundTypes.size());
124 mlir::Type itrTy =
cgf.cgm.convertType(
cgf.getContext().UnsignedLongLongTy);
125 auto idxType = mlir::IndexType::get(&
cgf.getMLIRContext());
127 auto getUpperBound = [&](mlir::Value bound) {
129 mlir::acc::GetUpperboundOp::create(
builder, loc, idxType, bound);
130 return mlir::UnrealizedConversionCastOp::create(
builder, loc, itrTy,
131 upperBoundVal.getResult())
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();
141 mlir::Type topLevelTy =
cgf.convertType(boundTypes.back());
142 cir::PointerType topLevelTyPtr =
builder.getPointerTo(topLevelTy);
144 mlir::Value initialAlloca =
builder.createAlloca(
145 loc, topLevelTyPtr, topLevelTy, allocaName,
146 cgf.getContext().getTypeAlignInChars(boundTypes.back()));
148 bool lastBoundWasArray = isArrayTy(boundTypes.back());
152 mlir::Value lastAlloca = initialAlloca;
157 llvm::ArrayRef<QualType> boundResults = boundTypes.drop_back(1);
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);
169 mlir::Value cumulativeElts;
170 for (
auto [bound, resultType, allocasLeft] : llvm::reverse(
171 llvm::zip_equal(boundsRange, boundResults, allocasLeftArr))) {
179 mlir::Value eltsPerSubArray = getUpperBound(bound);
180 mlir::Value eltsToAlloca;
187 eltsToAlloca =
builder.createMul(loc, eltsPerSubArray, cumulativeElts);
189 eltsToAlloca = eltsPerSubArray;
191 if (!lastBoundWasArray) {
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);
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);
205 makeAllocaCopy(loc, ptrTy, cumulativeElts, eltsPerSubArray, lastAlloca,
207 lastAlloca = curAlloca;
212 cir::ConstantOp constZero =
builder.getConstInt(loc, itrTy, 0);
213 lastAlloca =
builder.getArrayElement(loc, loc, lastAlloca,
214 cgf.convertType(resultType),
218 cumulativeElts = eltsToAlloca;
219 lastBoundWasArray = isArrayTy(resultType);
221 return initialAlloca;
227 mlir::Location loc,
bool inverse) {
228 mlir::Operation *bodyInsertLoc;
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());
237 auto doSubscriptOp = [&](mlir::Value subVal,
238 cir::LoadOp idxLoad) -> mlir::Value {
241 if (
auto arrayTy = dyn_cast<cir::ArrayType>(eltTy))
242 return builder.getArrayElement(loc, loc, subVal, arrayTy.getElementType(),
248 auto eltLoad = cir::LoadOp::create(
builder, loc, {subVal});
250 return cir::PtrStrideOp::create(
builder, loc, eltLoad.getType(), eltLoad,
255 auto forStmtBuilder = [&]() {
258 mlir::acc::GetLowerboundOp::create(
builder, loc, idxType, bound);
259 auto lbConversion = mlir::UnrealizedConversionCastOp::create(
260 builder, loc, itrTy, lowerBoundVal.getResult());
262 mlir::acc::GetUpperboundOp::create(
builder, loc, idxType, bound);
263 auto ubConversion = mlir::UnrealizedConversionCastOp::create(
264 builder, loc, itrTy, upperBoundVal.getResult());
268 cir::AllocaOp::create(
builder, loc, itrPtrTy, itrTy,
"iter", itrAlign);
272 cir::ConstantOp constOne =
builder.getConstInt(loc, itrTy, 1);
274 auto sub = cir::BinOp::create(
builder, loc, itrTy, cir::BinOpKind::Sub,
275 ubConversion.getResult(0), constOne);
278 builder.CIRBaseBuilderTy::createStore(loc, sub, itr);
281 builder.CIRBaseBuilderTy::createStore(loc, lbConversion.getResult(0),
287 auto endItr = inverse ? lbConversion : ubConversion;
292 [&](mlir::OpBuilder &
b, mlir::Location loc) {
293 auto loadCur = cir::LoadOp::create(
builder, loc, {itr});
295 auto cmp =
builder.createCompare(
296 loc, inverse ? cir::CmpOpKind::ge : cir::CmpOpKind::lt, loadCur,
297 endItr.getResult(0));
301 [&](mlir::OpBuilder &
b, mlir::Location loc) {
302 auto load = cir::LoadOp::create(
builder, loc, {itr});
304 if (subscriptedValue)
305 subscriptedValue = doSubscriptOp(subscriptedValue, load);
306 bodyInsertLoc =
builder.createYield(loc);
309 [&](mlir::OpBuilder &
b, mlir::Location loc) {
310 auto load = cir::LoadOp::create(
builder, loc, {itr});
311 auto unary = cir::UnaryOp::create(
313 inverse ? cir::UnaryOpKind::Dec : cir::UnaryOpKind::Inc, load);
314 builder.CIRBaseBuilderTy::createStore(loc, unary, itr);
319 cir::ScopeOp::create(
builder, loc,
320 [&](mlir::OpBuilder &
b, mlir::Location loc) {
327 builder.setInsertionPoint(bodyInsertLoc);
328 return subscriptedValue;
331mlir::acc::ReductionOperator
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");
356 llvm_unreachable(
"invalid reduction operator");
364 mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
366 mlir::Region &destroyRegion) {
369 builder.setInsertionPointToEnd(&destroyRegion.back());
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,
381 mlir::OpBuilder::InsertionGuard guardCase(
builder);
385 block->getArguments().drop_front(2);
387 mlir::Value subscriptedValue = block->getArgument(1);
388 for (mlir::BlockArgument boundArg : llvm::reverse(boundsRange))
392 emitDestroy(subscriptedValue,
cgf.cgm.convertType(origType));
398 emitDestroy(block->getArgument(1), elementTy);
401 mlir::acc::YieldOp::create(
builder, locEnd);
409 mlir::Location loc, mlir::Location locEnd,
SourceRange exprRange,
410 mlir::Value mainOp, mlir::acc::PrivateRecipeOp recipe,
size_t numBounds,
413 assert(allocaDecl &&
"Required recipe variable not set?");
419 builder.setInsertionPointToEnd(&recipe.getInitRegion().back());
422 const Type *allocaPointeeType =
426 if (
cgf.getContext().getLangOpts().CPlusPlus && !allocaDecl->
getInit() &&
435 cgf.cgm.errorNYI(exprRange,
"private default-init recipe");
442 cgf.emitAutoVarAlloca(*allocaDecl,
builder.saveInsertionPoint());
443 cgf.emitAutoVarInit(tempDeclEmission);
445 makeBoundsAlloca(block, exprRange, loc,
"openacc.private.init", numBounds,
449 cgf.cgm.errorNYI(exprRange,
"private-init with bounds initialization");
452 mlir::acc::YieldOp::create(
builder, locEnd);
456 mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
458 mlir::acc::FirstprivateRecipeOp recipe,
const VarDecl *varRecipe,
463 builder.setInsertionPointToEnd(&recipe.getCopyRegion().back());
466 mlir::BlockArgument fromArg = block->getArgument(0);
467 mlir::BlockArgument toArg = block->getArgument(1);
469 mlir::Type elementTy =
470 mlir::cast<cir::PointerType>(mainOp.getType()).getPointee();
475 Address{toArg, elementTy,
cgf.getContext().getDeclAlign(varRecipe)});
479 cgf.setAddrOfLocalVar(
481 Address{fromArg, elementTy,
cgf.getContext().getDeclAlign(varRecipe)});
483 cgf.emitAutoVarInit(tempDeclEmission);
484 mlir::acc::YieldOp::create(
builder, locEnd);
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());
499 mlir::BlockArgument lhsArg = block->getArgument(0);
501 mlir::acc::YieldOp::create(
builder, locEnd, lhsArg);
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)
CIRGen::CIRGenBuilderTy & builder
mlir::acc::ReductionOperator convertReductionOp(OpenACCReductionOperator op)
CIRGen::CIRGenFunction & cgf
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 ®ion, mlir::Type opTy, mlir::Location loc, size_t numBounds, bool isInit)
CharUnits - This is an opaque type for sizes expressed in character units.
This represents one expression.
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)
void setAllocatedAddress(Address A)
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...