Skip to content

Commit b604562

Browse files
authored
[OpenACC][CIR] Implement 'reduction' combiner lowering for 5 ops (#162906)
Following on the Sema changes, this does the lowering for all of the operators that can be done as a compound operator. Lowering is very simply looping through the objects based on array/compound/etc, and doing a call to the operation.
1 parent aa84998 commit b604562

24 files changed

+6395
-337
lines changed

clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,7 +1005,7 @@ class OpenACCClauseCIREmitter final
10051005
/*temporary=*/nullptr, OpenACCReductionOperator::Invalid,
10061006
Decl::castToDeclContext(cgf.curFuncDecl), opInfo.origType,
10071007
opInfo.bounds.size(), opInfo.boundTypes, opInfo.baseType,
1008-
privateOp);
1008+
privateOp, /*reductionCombinerRecipes=*/{});
10091009
// TODO: OpenACC: The dialect is going to change in the near future to
10101010
// have these be on a different operation, so when that changes, we
10111011
// probably need to change these here.
@@ -1046,7 +1046,7 @@ class OpenACCClauseCIREmitter final
10461046
OpenACCReductionOperator::Invalid,
10471047
Decl::castToDeclContext(cgf.curFuncDecl), opInfo.origType,
10481048
opInfo.bounds.size(), opInfo.boundTypes, opInfo.baseType,
1049-
firstPrivateOp);
1049+
firstPrivateOp, /*reductionCombinerRecipe=*/{});
10501050

10511051
// TODO: OpenACC: The dialect is going to change in the near future to
10521052
// have these be on a different operation, so when that changes, we
@@ -1088,7 +1088,7 @@ class OpenACCClauseCIREmitter final
10881088
/*temporary=*/nullptr, clause.getReductionOp(),
10891089
Decl::castToDeclContext(cgf.curFuncDecl), opInfo.origType,
10901090
opInfo.bounds.size(), opInfo.boundTypes, opInfo.baseType,
1091-
reductionOp);
1091+
reductionOp, varRecipe.CombinerRecipes);
10921092

10931093
operation.addReduction(builder.getContext(), reductionOp, recipe);
10941094
}

clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp

Lines changed: 129 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -527,16 +527,142 @@ void OpenACCRecipeBuilderBase::createFirstprivateRecipeCopy(
527527
// doesn't restore it aftewards.
528528
void OpenACCRecipeBuilderBase::createReductionRecipeCombiner(
529529
mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
530-
mlir::acc::ReductionRecipeOp recipe, size_t numBounds) {
530+
mlir::acc::ReductionRecipeOp recipe, size_t numBounds, QualType origType,
531+
llvm::ArrayRef<OpenACCReductionRecipe::CombinerRecipe> combinerRecipes) {
531532
mlir::Block *block =
532533
createRecipeBlock(recipe.getCombinerRegion(), mainOp.getType(), loc,
533534
numBounds, /*isInit=*/false);
534535
builder.setInsertionPointToEnd(&recipe.getCombinerRegion().back());
535536
CIRGenFunction::LexicalScope ls(cgf, loc, block);
536537

537-
mlir::BlockArgument lhsArg = block->getArgument(0);
538+
mlir::Value lhsArg = block->getArgument(0);
539+
mlir::Value rhsArg = block->getArgument(1);
540+
llvm::MutableArrayRef<mlir::BlockArgument> boundsRange =
541+
block->getArguments().drop_front(2);
542+
543+
if (llvm::any_of(combinerRecipes, [](auto &r) { return r.Op == nullptr; })) {
544+
cgf.cgm.errorNYI(loc, "OpenACC Reduction combiner not generated");
545+
mlir::acc::YieldOp::create(builder, locEnd, block->getArgument(0));
546+
return;
547+
}
548+
549+
// apply the bounds so that we can get our bounds emitted correctly.
550+
for (mlir::BlockArgument boundArg : llvm::reverse(boundsRange))
551+
std::tie(lhsArg, rhsArg) =
552+
createBoundsLoop(lhsArg, rhsArg, boundArg, loc, /*inverse=*/false);
553+
554+
// Emitter for when we know this isn't a struct or array we have to loop
555+
// through. This should work for the 'field' once the get-element call has
556+
// been made.
557+
auto emitSingleCombiner =
558+
[&](mlir::Value lhsArg, mlir::Value rhsArg,
559+
const OpenACCReductionRecipe::CombinerRecipe &combiner) {
560+
mlir::Type elementTy =
561+
mlir::cast<cir::PointerType>(lhsArg.getType()).getPointee();
562+
CIRGenFunction::DeclMapRevertingRAII declMapRAIILhs{cgf, combiner.LHS};
563+
cgf.setAddrOfLocalVar(
564+
combiner.LHS, Address{lhsArg, elementTy,
565+
cgf.getContext().getDeclAlign(combiner.LHS)});
566+
CIRGenFunction::DeclMapRevertingRAII declMapRAIIRhs{cgf, combiner.RHS};
567+
cgf.setAddrOfLocalVar(
568+
combiner.RHS, Address{rhsArg, elementTy,
569+
cgf.getContext().getDeclAlign(combiner.RHS)});
570+
571+
[[maybe_unused]] mlir::LogicalResult stmtRes =
572+
cgf.emitStmt(combiner.Op, /*useCurrentScope=*/true);
573+
};
574+
575+
// Emitter for when we know this is either a non-array or element of an array
576+
// (which also shouldn't be an array type?). This function should generate the
577+
// initialization code for an entire 'array-element'/non-array, including
578+
// diving into each element of a struct (if necessary).
579+
auto emitCombiner = [&](mlir::Value lhsArg, mlir::Value rhsArg, QualType ty) {
580+
assert(!ty->isArrayType() && "Array type shouldn't get here");
581+
if (const auto *rd = ty->getAsRecordDecl()) {
582+
if (combinerRecipes.size() == 1 &&
583+
cgf.getContext().hasSameType(ty, combinerRecipes[0].LHS->getType())) {
584+
// If this is a 'top level' operator on the type we can just emit this
585+
// as a simple one.
586+
emitSingleCombiner(lhsArg, rhsArg, combinerRecipes[0]);
587+
} else {
588+
// else we have to handle each individual field after after a
589+
// get-element.
590+
for (const auto &[field, combiner] :
591+
llvm::zip_equal(rd->fields(), combinerRecipes)) {
592+
mlir::Type fieldType = cgf.convertType(field->getType());
593+
auto fieldPtr = cir::PointerType::get(fieldType);
594+
595+
mlir::Value lhsField = builder.createGetMember(
596+
loc, fieldPtr, lhsArg, field->getName(), field->getFieldIndex());
597+
mlir::Value rhsField = builder.createGetMember(
598+
loc, fieldPtr, rhsArg, field->getName(), field->getFieldIndex());
599+
600+
emitSingleCombiner(lhsField, rhsField, combiner);
601+
}
602+
}
603+
604+
} else {
605+
// if this is a single-thing (because we should know this isn't an array,
606+
// as Sema wouldn't let us get here), we can just do a normal emit call.
607+
emitSingleCombiner(lhsArg, rhsArg, combinerRecipes[0]);
608+
}
609+
};
610+
611+
if (const auto *cat = cgf.getContext().getAsConstantArrayType(origType)) {
612+
// If we're in an array, we have to emit the combiner for each element of
613+
// the array.
614+
auto itrTy = mlir::cast<cir::IntType>(cgf.PtrDiffTy);
615+
auto itrPtrTy = cir::PointerType::get(itrTy);
616+
617+
mlir::Value zero =
618+
builder.getConstInt(loc, mlir::cast<cir::IntType>(cgf.PtrDiffTy), 0);
619+
mlir::Value itr =
620+
cir::AllocaOp::create(builder, loc, itrPtrTy, itrTy, "itr",
621+
cgf.cgm.getSize(cgf.getPointerAlign()));
622+
builder.CIRBaseBuilderTy::createStore(loc, zero, itr);
623+
624+
builder.setInsertionPointAfter(builder.createFor(
625+
loc,
626+
/*condBuilder=*/
627+
[&](mlir::OpBuilder &b, mlir::Location loc) {
628+
auto loadItr = cir::LoadOp::create(builder, loc, {itr});
629+
mlir::Value arraySize = builder.getConstInt(
630+
loc, mlir::cast<cir::IntType>(cgf.PtrDiffTy), cat->getZExtSize());
631+
auto cmp = builder.createCompare(loc, cir::CmpOpKind::lt, loadItr,
632+
arraySize);
633+
builder.createCondition(cmp);
634+
},
635+
/*bodyBuilder=*/
636+
[&](mlir::OpBuilder &b, mlir::Location loc) {
637+
auto loadItr = cir::LoadOp::create(builder, loc, {itr});
638+
auto lhsElt = builder.getArrayElement(
639+
loc, loc, lhsArg, cgf.convertType(cat->getElementType()), loadItr,
640+
/*shouldDecay=*/true);
641+
auto rhsElt = builder.getArrayElement(
642+
loc, loc, rhsArg, cgf.convertType(cat->getElementType()), loadItr,
643+
/*shouldDecay=*/true);
644+
645+
emitCombiner(lhsElt, rhsElt, cat->getElementType());
646+
builder.createYield(loc);
647+
},
648+
/*stepBuilder=*/
649+
[&](mlir::OpBuilder &b, mlir::Location loc) {
650+
auto loadItr = cir::LoadOp::create(builder, loc, {itr});
651+
auto inc = cir::UnaryOp::create(builder, loc, loadItr.getType(),
652+
cir::UnaryOpKind::Inc, loadItr);
653+
builder.CIRBaseBuilderTy::createStore(loc, inc, itr);
654+
builder.createYield(loc);
655+
}));
538656

539-
mlir::acc::YieldOp::create(builder, locEnd, lhsArg);
657+
} else if (origType->isArrayType()) {
658+
cgf.cgm.errorNYI(loc,
659+
"OpenACC Reduction combiner non-constant array recipe");
660+
} else {
661+
emitCombiner(lhsArg, rhsArg, origType);
662+
}
663+
664+
builder.setInsertionPointToEnd(&recipe.getCombinerRegion().back());
665+
mlir::acc::YieldOp::create(builder, locEnd, block->getArgument(0));
540666
}
541667

542668
} // namespace clang::CIRGen

clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ class OpenACCRecipeBuilderBase {
6464
// that this function is not 'insertion point' clean, in that it alters the
6565
// insertion point to be inside of the 'combiner' section of the recipe, but
6666
// doesn't restore it aftewards.
67-
void createReductionRecipeCombiner(mlir::Location loc, mlir::Location locEnd,
68-
mlir::Value mainOp,
69-
mlir::acc::ReductionRecipeOp recipe,
70-
size_t numBounds);
67+
void createReductionRecipeCombiner(
68+
mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
69+
mlir::acc::ReductionRecipeOp recipe, size_t numBounds, QualType origType,
70+
llvm::ArrayRef<OpenACCReductionRecipe::CombinerRecipe> combinerRecipes);
7171

7272
void createInitRecipe(mlir::Location loc, mlir::Location locEnd,
7373
SourceRange exprRange, mlir::Value mainOp,
@@ -169,7 +169,9 @@ class OpenACCRecipeBuilder : OpenACCRecipeBuilderBase {
169169
const Expr *varRef, const VarDecl *varRecipe, const VarDecl *temporary,
170170
OpenACCReductionOperator reductionOp, DeclContext *dc, QualType origType,
171171
size_t numBounds, llvm::ArrayRef<QualType> boundTypes, QualType baseType,
172-
mlir::Value mainOp) {
172+
mlir::Value mainOp,
173+
llvm::ArrayRef<OpenACCReductionRecipe::CombinerRecipe>
174+
reductionCombinerRecipes) {
173175
assert(!varRecipe->getType()->isSpecificBuiltinType(
174176
BuiltinType::ArraySection) &&
175177
"array section shouldn't make it to recipe creation");
@@ -208,7 +210,8 @@ class OpenACCRecipeBuilder : OpenACCRecipeBuilderBase {
208210
createInitRecipe(loc, locEnd, varRef->getSourceRange(), mainOp,
209211
recipe.getInitRegion(), numBounds, boundTypes, varRecipe,
210212
origType, /*emitInitExpr=*/true);
211-
createReductionRecipeCombiner(loc, locEnd, mainOp, recipe, numBounds);
213+
createReductionRecipeCombiner(loc, locEnd, mainOp, recipe, numBounds,
214+
origType, reductionCombinerRecipes);
212215
} else {
213216
static_assert(std::is_same_v<RecipeTy, mlir::acc::FirstprivateRecipeOp>);
214217
createInitRecipe(loc, locEnd, varRef->getSourceRange(), mainOp,

clang/lib/Sema/SemaOpenACCClause.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1924,7 +1924,7 @@ bool SemaOpenACC::CheckReductionVarType(Expr *VarExpr) {
19241924
// off here. This will result in CurType being the actual 'type' of the
19251925
// expression, which is what we are looking to check.
19261926
QualType CurType = isa<ArraySectionExpr>(VarExpr)
1927-
? ArraySectionExpr::getBaseOriginalType(VarExpr)
1927+
? cast<ArraySectionExpr>(VarExpr)->getElementType()
19281928
: VarExpr->getType();
19291929

19301930
// This can happen when we have a dependent type in an array element that the

0 commit comments

Comments
 (0)