Skip to content

Commit 542cba8

Browse files
authored
[OpenACC][CIR] Handle firstprivate bounds recipe lowering (#161873)
These work the same as the other two (private and reduction) except that the expression for the 'init' is a copy instead of a default/value init, and in a separate region. This patch gets all of that correct, and ensures we generate these as expected. There is a little extra work to make sure that the bounds-loop generation does 2 separate array index operations, otherwise this is very much like the reduction implementation.
1 parent 8bab6c4 commit 542cba8

File tree

7 files changed

+1312
-803
lines changed

7 files changed

+1312
-803
lines changed

clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -221,10 +221,9 @@ mlir::Value OpenACCRecipeBuilderBase::makeBoundsAlloca(
221221
return initialAlloca;
222222
}
223223

224-
mlir::Value
225-
OpenACCRecipeBuilderBase::createBoundsLoop(mlir::Value subscriptedValue,
226-
mlir::Value bound,
227-
mlir::Location loc, bool inverse) {
224+
std::pair<mlir::Value, mlir::Value> OpenACCRecipeBuilderBase::createBoundsLoop(
225+
mlir::Value subscriptedValue, mlir::Value subscriptedValue2,
226+
mlir::Value bound, mlir::Location loc, bool inverse) {
228227
mlir::Operation *bodyInsertLoc;
229228

230229
mlir::Type itrTy = cgf.cgm.convertType(cgf.getContext().UnsignedLongLongTy);
@@ -249,7 +248,6 @@ OpenACCRecipeBuilderBase::createBoundsLoop(mlir::Value subscriptedValue,
249248

250249
return cir::PtrStrideOp::create(builder, loc, eltLoad.getType(), eltLoad,
251250
idxLoad);
252-
253251
};
254252

255253
auto forStmtBuilder = [&]() {
@@ -303,6 +301,8 @@ OpenACCRecipeBuilderBase::createBoundsLoop(mlir::Value subscriptedValue,
303301

304302
if (subscriptedValue)
305303
subscriptedValue = doSubscriptOp(subscriptedValue, load);
304+
if (subscriptedValue2)
305+
subscriptedValue2 = doSubscriptOp(subscriptedValue2, load);
306306
bodyInsertLoc = builder.createYield(loc);
307307
},
308308
/*stepBuilder=*/
@@ -325,7 +325,7 @@ OpenACCRecipeBuilderBase::createBoundsLoop(mlir::Value subscriptedValue,
325325
// Leave the insertion point to be inside the body, so we can loop over
326326
// these things.
327327
builder.setInsertionPoint(bodyInsertLoc);
328-
return subscriptedValue;
328+
return {subscriptedValue, subscriptedValue2};
329329
}
330330

331331
mlir::acc::ReductionOperator
@@ -434,7 +434,7 @@ void OpenACCRecipeBuilderBase::createInitRecipe(
434434
mlir::Location loc, mlir::Location locEnd, SourceRange exprRange,
435435
mlir::Value mainOp, mlir::Region &recipeInitRegion, size_t numBounds,
436436
llvm::ArrayRef<QualType> boundTypes, const VarDecl *allocaDecl,
437-
QualType origType) {
437+
QualType origType, bool emitInitExpr) {
438438
assert(allocaDecl && "Required recipe variable not set?");
439439
CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, allocaDecl};
440440

@@ -464,14 +464,15 @@ void OpenACCRecipeBuilderBase::createInitRecipe(
464464
// initialize this variable correctly.
465465
CIRGenFunction::AutoVarEmission tempDeclEmission =
466466
cgf.emitAutoVarAlloca(*allocaDecl, builder.saveInsertionPoint());
467-
cgf.emitAutoVarInit(tempDeclEmission);
467+
if (emitInitExpr)
468+
cgf.emitAutoVarInit(tempDeclEmission);
468469
} else {
469470
mlir::Value alloca = makeBoundsAlloca(
470471
block, exprRange, loc, allocaDecl->getName(), numBounds, boundTypes);
471472

472473
// If the initializer is trivial, there is nothing to do here, so save
473474
// ourselves some effort.
474-
if (allocaDecl->getInit() &&
475+
if (emitInitExpr && allocaDecl->getInit() &&
475476
(!cgf.isTrivialInitializer(allocaDecl->getInit()) ||
476477
cgf.getContext().getLangOpts().getTrivialAutoVarInit() !=
477478
LangOptions::TrivialAutoVarInitKind::Uninitialized))
@@ -484,35 +485,42 @@ void OpenACCRecipeBuilderBase::createInitRecipe(
484485

485486
void OpenACCRecipeBuilderBase::createFirstprivateRecipeCopy(
486487
mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
487-
CIRGenFunction::AutoVarEmission tempDeclEmission,
488-
mlir::acc::FirstprivateRecipeOp recipe, const VarDecl *varRecipe,
489-
const VarDecl *temporary) {
490-
mlir::Block *block =
491-
createRecipeBlock(recipe.getCopyRegion(), mainOp.getType(), loc,
492-
/*numBounds=*/0, /*isInit=*/false);
493-
builder.setInsertionPointToEnd(&recipe.getCopyRegion().back());
488+
const VarDecl *allocaDecl, const VarDecl *temporary,
489+
mlir::Region &copyRegion, size_t numBounds) {
490+
mlir::Block *block = createRecipeBlock(copyRegion, mainOp.getType(), loc,
491+
numBounds, /*isInit=*/false);
492+
builder.setInsertionPointToEnd(&copyRegion.back());
494493
CIRGenFunction::LexicalScope ls(cgf, loc, block);
495494

496-
mlir::BlockArgument fromArg = block->getArgument(0);
497-
mlir::BlockArgument toArg = block->getArgument(1);
495+
mlir::Value fromArg = block->getArgument(0);
496+
mlir::Value toArg = block->getArgument(1);
498497

499-
mlir::Type elementTy =
500-
mlir::cast<cir::PointerType>(mainOp.getType()).getPointee();
498+
llvm::MutableArrayRef<mlir::BlockArgument> boundsRange =
499+
block->getArguments().drop_front(2);
501500

502-
// Set the address of the emission to be the argument, so that we initialize
503-
// that instead of the variable in the other block.
504-
tempDeclEmission.setAllocatedAddress(
505-
Address{toArg, elementTy, cgf.getContext().getDeclAlign(varRecipe)});
501+
for (mlir::BlockArgument boundArg : llvm::reverse(boundsRange))
502+
std::tie(fromArg, toArg) =
503+
createBoundsLoop(fromArg, toArg, boundArg, loc, /*inverse=*/false);
504+
505+
// Set up the 'to' address.
506+
mlir::Type elementTy =
507+
mlir::cast<cir::PointerType>(toArg.getType()).getPointee();
508+
CIRGenFunction::AutoVarEmission tempDeclEmission(*allocaDecl);
506509
tempDeclEmission.emittedAsOffload = true;
510+
tempDeclEmission.setAllocatedAddress(
511+
Address{toArg, elementTy, cgf.getContext().getDeclAlign(allocaDecl)});
507512

513+
// Set up the 'from' address from the temporary.
508514
CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, temporary};
509515
cgf.setAddrOfLocalVar(
510516
temporary,
511-
Address{fromArg, elementTy, cgf.getContext().getDeclAlign(varRecipe)});
512-
517+
Address{fromArg, elementTy, cgf.getContext().getDeclAlign(allocaDecl)});
513518
cgf.emitAutoVarInit(tempDeclEmission);
519+
520+
builder.setInsertionPointToEnd(&copyRegion.back());
514521
mlir::acc::YieldOp::create(builder, locEnd);
515522
}
523+
516524
// This function generates the 'combiner' section for a reduction recipe. Note
517525
// that this function is not 'insertion point' clean, in that it alters the
518526
// insertion point to be inside of the 'combiner' section of the recipe, but

clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h

Lines changed: 24 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,16 @@ class OpenACCRecipeBuilderBase {
4949
// Creates a loop through an 'acc.bounds', leaving the 'insertion' point to be
5050
// the inside of the loop body. Traverses LB->UB UNLESS `inverse` is set.
5151
// Returns the 'subscriptedValue' changed with the new bounds subscript.
52+
std::pair<mlir::Value, mlir::Value>
53+
createBoundsLoop(mlir::Value subscriptedValue, mlir::Value subscriptedValue2,
54+
mlir::Value bound, mlir::Location loc, bool inverse);
55+
5256
mlir::Value createBoundsLoop(mlir::Value subscriptedValue, mlir::Value bound,
53-
mlir::Location loc, bool inverse);
57+
mlir::Location loc, bool inverse) {
58+
return createBoundsLoop(subscriptedValue, {}, bound, loc, inverse).first;
59+
}
60+
5461
mlir::acc::ReductionOperator convertReductionOp(OpenACCReductionOperator op);
55-
void createFirstprivateRecipeCopy(
56-
mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
57-
CIRGenFunction::AutoVarEmission tempDeclEmission,
58-
mlir::acc::FirstprivateRecipeOp recipe, const VarDecl *varRecipe,
59-
const VarDecl *temporary);
6062

6163
// This function generates the 'combiner' section for a reduction recipe. Note
6264
// that this function is not 'insertion point' clean, in that it alters the
@@ -66,11 +68,19 @@ class OpenACCRecipeBuilderBase {
6668
mlir::Value mainOp,
6769
mlir::acc::ReductionRecipeOp recipe,
6870
size_t numBounds);
71+
6972
void createInitRecipe(mlir::Location loc, mlir::Location locEnd,
7073
SourceRange exprRange, mlir::Value mainOp,
7174
mlir::Region &recipeInitRegion, size_t numBounds,
7275
llvm::ArrayRef<QualType> boundTypes,
73-
const VarDecl *allocaDecl, QualType origType);
76+
const VarDecl *allocaDecl, QualType origType,
77+
bool emitInitExpr);
78+
79+
void createFirstprivateRecipeCopy(mlir::Location loc, mlir::Location locEnd,
80+
mlir::Value mainOp,
81+
const VarDecl *allocaDecl,
82+
const VarDecl *temporary,
83+
mlir::Region &copyRegion, size_t numBounds);
7484

7585
void createRecipeDestroySection(mlir::Location loc, mlir::Location locEnd,
7686
mlir::Value mainOp, CharUnits alignment,
@@ -150,63 +160,6 @@ class OpenACCRecipeBuilder : OpenACCRecipeBuilderBase {
150160
return recipeName;
151161
}
152162

153-
// Create the 'init' section of the recipe, including the 'copy' section for
154-
// 'firstprivate'. Note that this function is not 'insertion point' clean, in
155-
// that it alters the insertion point to be inside of the 'destroy' section of
156-
// the recipe, but doesn't restore it aftewards.
157-
void createRecipeInitCopy(mlir::Location loc, mlir::Location locEnd,
158-
SourceRange exprRange, mlir::Value mainOp,
159-
RecipeTy recipe, const VarDecl *varRecipe,
160-
const VarDecl *temporary) {
161-
// TODO: OpenACC: when we get the 'pointer' variants for
162-
// firstprivate/reduction, this probably should be removed/split into
163-
// functions for the BuilderBase.
164-
assert(varRecipe && "Required recipe variable not set?");
165-
166-
CIRGenFunction::AutoVarEmission tempDeclEmission{
167-
CIRGenFunction::AutoVarEmission::invalid()};
168-
CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, varRecipe};
169-
170-
// Do the 'init' section of the recipe IR, which does an alloca, then the
171-
// initialization (except for firstprivate).
172-
mlir::Block *block =
173-
createRecipeBlock(recipe.getInitRegion(), mainOp.getType(), loc,
174-
/*numBounds=*/0, /*isInit=*/true);
175-
builder.setInsertionPointToEnd(&recipe.getInitRegion().back());
176-
CIRGenFunction::LexicalScope ls(cgf, loc, block);
177-
178-
tempDeclEmission =
179-
cgf.emitAutoVarAlloca(*varRecipe, builder.saveInsertionPoint());
180-
181-
// 'firstprivate' doesn't do its initialization in the 'init' section,
182-
// instead it does it in the 'copy' section. SO, only do 'init' here for
183-
// reduction.
184-
if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) {
185-
// Unlike Private, the recipe here is always required as it has to do
186-
// init, not just 'default' init.
187-
if (!varRecipe->getInit())
188-
cgf.cgm.errorNYI(exprRange, "reduction init recipe");
189-
cgf.emitAutoVarInit(tempDeclEmission);
190-
}
191-
192-
mlir::acc::YieldOp::create(builder, locEnd);
193-
194-
if constexpr (std::is_same_v<RecipeTy, mlir::acc::FirstprivateRecipeOp>) {
195-
if (!varRecipe->getInit()) {
196-
// If we don't have any initialization recipe, we failed during Sema to
197-
// initialize this correctly. If we disable the
198-
// Sema::TentativeAnalysisScopes in SemaOpenACC::CreateInitRecipe, it'll
199-
// emit an error to tell us. However, emitting those errors during
200-
// production is a violation of the standard, so we cannot do them.
201-
cgf.cgm.errorNYI(
202-
exprRange, "firstprivate copy-init recipe not properly generated");
203-
}
204-
205-
createFirstprivateRecipeCopy(loc, locEnd, mainOp, tempDeclEmission,
206-
recipe, varRecipe, temporary);
207-
}
208-
}
209-
210163
public:
211164
OpenACCRecipeBuilder(CIRGen::CIRGenFunction &cgf,
212165
CIRGen::CIRGenBuilderTy &builder)
@@ -221,19 +174,6 @@ class OpenACCRecipeBuilder : OpenACCRecipeBuilderBase {
221174
BuiltinType::ArraySection) &&
222175
"array section shouldn't make it to recipe creation");
223176

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::FirstprivateRecipeOp>) {
228-
if (numBounds) {
229-
cgf.cgm.errorNYI(varRef->getSourceRange(),
230-
"firstprivate-init with bounds");
231-
}
232-
boundTypes = {};
233-
numBounds = 0;
234-
origType = baseType;
235-
}
236-
237177
mlir::ModuleOp mod = builder.getBlock()
238178
->getParent()
239179
->template getParentOfType<mlir::ModuleOp>();
@@ -262,21 +202,20 @@ class OpenACCRecipeBuilder : OpenACCRecipeBuilderBase {
262202
if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
263203
createInitRecipe(loc, locEnd, varRef->getSourceRange(), mainOp,
264204
recipe.getInitRegion(), numBounds, boundTypes, varRecipe,
265-
origType);
205+
origType, /*emitInitExpr=*/true);
266206
} else if constexpr (std::is_same_v<RecipeTy,
267207
mlir::acc::ReductionRecipeOp>) {
268208
createInitRecipe(loc, locEnd, varRef->getSourceRange(), mainOp,
269209
recipe.getInitRegion(), numBounds, boundTypes, varRecipe,
270-
origType);
210+
origType, /*emitInitExpr=*/true);
271211
createReductionRecipeCombiner(loc, locEnd, mainOp, recipe, numBounds);
272212
} else {
273213
static_assert(std::is_same_v<RecipeTy, mlir::acc::FirstprivateRecipeOp>);
274-
// TODO: OpenACC: we probably want this to call createInitRecipe as well,
275-
// but do so in a way that omits the 'initialization', so that we can do
276-
// it separately, since it belongs in the 'copy' region. It also might
277-
// need a way of getting the tempDeclEmission out of it for that purpose.
278-
createRecipeInitCopy(loc, locEnd, varRef->getSourceRange(), mainOp,
279-
recipe, varRecipe, temporary);
214+
createInitRecipe(loc, locEnd, varRef->getSourceRange(), mainOp,
215+
recipe.getInitRegion(), numBounds, boundTypes, varRecipe,
216+
origType, /*emitInitExpr=*/false);
217+
createFirstprivateRecipeCopy(loc, locEnd, mainOp, varRecipe, temporary,
218+
recipe.getCopyRegion(), numBounds);
280219
}
281220

282221
if (origType.isDestructedType())

clang/lib/Sema/SemaOpenACC.cpp

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2724,16 +2724,6 @@ Expr *GenerateReductionInitRecipeExpr(ASTContext &Context,
27242724
return InitExpr;
27252725
}
27262726

2727-
const Expr *StripOffBounds(const Expr *VarExpr) {
2728-
while (isa_and_present<ArraySectionExpr, ArraySubscriptExpr>(VarExpr)) {
2729-
if (const auto *AS = dyn_cast<ArraySectionExpr>(VarExpr))
2730-
VarExpr = AS->getBase()->IgnoreParenImpCasts();
2731-
else if (const auto *Sub = dyn_cast<ArraySubscriptExpr>(VarExpr))
2732-
VarExpr = Sub->getBase()->IgnoreParenImpCasts();
2733-
}
2734-
return VarExpr;
2735-
}
2736-
27372727
VarDecl *CreateAllocaDecl(ASTContext &Ctx, DeclContext *DC,
27382728
SourceLocation BeginLoc, IdentifierInfo *VarName,
27392729
QualType VarTy) {
@@ -2794,17 +2784,18 @@ OpenACCPrivateRecipe SemaOpenACC::CreatePrivateInitRecipe(const Expr *VarExpr) {
27942784

27952785
OpenACCFirstPrivateRecipe
27962786
SemaOpenACC::CreateFirstPrivateInitRecipe(const Expr *VarExpr) {
2797-
// TODO: OpenACC: This shouldn't be necessary, see PrivateInitRecipe
2798-
VarExpr = StripOffBounds(VarExpr);
2799-
2787+
// We don't strip bounds here, so that we are doing our recipe init at the
2788+
// 'lowest' possible level. Codegen is going to have to do its own 'looping'.
28002789
if (!VarExpr || VarExpr->getType()->isDependentType())
28012790
return OpenACCFirstPrivateRecipe::Empty();
28022791

28032792
QualType VarTy =
28042793
VarExpr->getType().getNonReferenceType().getUnqualifiedType();
28052794

2806-
// TODO: OpenACC: for arrays/bounds versions, we're going to have to do a
2807-
// different initializer, but for now we can go ahead with this.
2795+
// Array sections are special, and we have to treat them that way.
2796+
if (const auto *ASE =
2797+
dyn_cast<ArraySectionExpr>(VarExpr->IgnoreParenImpCasts()))
2798+
VarTy = ArraySectionExpr::getBaseOriginalType(ASE);
28082799

28092800
VarDecl *AllocaDecl = CreateAllocaDecl(
28102801
getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),

0 commit comments

Comments
 (0)