Skip to content

Commit 893ce9b

Browse files
committed
[OpenACC][CIR] Implement 'reduction' combiner lowering for 5 ops
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 6010df0 commit 893ce9b

24 files changed

+6393
-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, /*reductionCombinerRecipe=*/{});
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: 127 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -527,16 +527,140 @@ 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+
// loop to do this on each individual array or struct element (if necessary).
578+
auto emitCombiner = [&](mlir::Value lhsArg, mlir::Value rhsArg, QualType Ty) {
579+
if (const auto *RD = Ty->getAsRecordDecl()) {
580+
if (combinerRecipes.size() == 1 &&
581+
cgf.getContext().hasSameType(Ty, combinerRecipes[0].LHS->getType())) {
582+
// If this is a 'top level' operator on the type we can just emit this
583+
// as a simple one.
584+
emitSingleCombiner(lhsArg, rhsArg, combinerRecipes[0]);
585+
} else {
586+
// else we have to handle each individual field after after a
587+
// get-element.
588+
for (const auto &[field, combiner] :
589+
llvm::zip_equal(RD->fields(), combinerRecipes)) {
590+
mlir::Type fieldType = cgf.convertType(field->getType());
591+
auto fieldPtr = cir::PointerType::get(fieldType);
592+
593+
mlir::Value lhsField = builder.createGetMember(
594+
loc, fieldPtr, lhsArg, field->getName(), field->getFieldIndex());
595+
mlir::Value rhsField = builder.createGetMember(
596+
loc, fieldPtr, rhsArg, field->getName(), field->getFieldIndex());
597+
598+
emitSingleCombiner(lhsField, rhsField, combiner);
599+
}
600+
}
601+
602+
} else {
603+
// if this is a single-thing (because we should know this isn't an array,
604+
// as Sema wouldn't let us get here), we can just do a normal emit call.
605+
emitSingleCombiner(lhsArg, rhsArg, combinerRecipes[0]);
606+
}
607+
};
608+
609+
if (const auto *cat = cgf.getContext().getAsConstantArrayType(origType)) {
610+
// If we're in an array, we have to emit the combiner for each element of
611+
// the array.
612+
auto itrTy = mlir::cast<cir::IntType>(cgf.PtrDiffTy);
613+
auto itrPtrTy = cir::PointerType::get(itrTy);
614+
615+
mlir::Value zero =
616+
builder.getConstInt(loc, mlir::cast<cir::IntType>(cgf.PtrDiffTy), 0);
617+
mlir::Value itr =
618+
cir::AllocaOp::create(builder, loc, itrPtrTy, itrTy, "itr",
619+
cgf.cgm.getSize(cgf.getPointerAlign()));
620+
builder.CIRBaseBuilderTy::createStore(loc, zero, itr);
621+
622+
builder.setInsertionPointAfter(builder.createFor(
623+
loc,
624+
/*condBuilder=*/
625+
[&](mlir::OpBuilder &b, mlir::Location loc) {
626+
auto loadItr = cir::LoadOp::create(builder, loc, {itr});
627+
mlir::Value arraySize = builder.getConstInt(
628+
loc, mlir::cast<cir::IntType>(cgf.PtrDiffTy), cat->getZExtSize());
629+
auto cmp = builder.createCompare(loc, cir::CmpOpKind::lt, loadItr,
630+
arraySize);
631+
builder.createCondition(cmp);
632+
},
633+
/*bodyBuilder=*/
634+
[&](mlir::OpBuilder &b, mlir::Location loc) {
635+
auto loadItr = cir::LoadOp::create(builder, loc, {itr});
636+
auto lhsElt = builder.getArrayElement(
637+
loc, loc, lhsArg, cgf.convertType(cat->getElementType()), loadItr,
638+
/*shouldDecay=*/true);
639+
auto rhsElt = builder.getArrayElement(
640+
loc, loc, rhsArg, cgf.convertType(cat->getElementType()), loadItr,
641+
/*shouldDecay=*/true);
642+
643+
emitCombiner(lhsElt, rhsElt, cat->getElementType());
644+
builder.createYield(loc);
645+
},
646+
/*stepBuilder=*/
647+
[&](mlir::OpBuilder &b, mlir::Location loc) {
648+
auto loadItr = cir::LoadOp::create(builder, loc, {itr});
649+
auto inc = cir::UnaryOp::create(builder, loc, loadItr.getType(),
650+
cir::UnaryOpKind::Inc, loadItr);
651+
builder.CIRBaseBuilderTy::createStore(loc, inc, itr);
652+
builder.createYield(loc);
653+
}));
538654

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

542666
} // 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)