Skip to content

Commit 25c0776

Browse files
authored
[OpenACC][CIR] Implement 'private' clause lowering. (#151360)
The private clause is the first with 'recipes', so a lot of infrastructure is included here, including some MLIR dialect changes that allow simple adding of a privatization. We'll likely get similar for firstprivate and reduction. Also, we have quite a bit of infrastructure in clause lowering to make sure we have most cases we could think of covered. At the moment, ONLY private is implemented, so all it requires is an 'init' segment (that doesn't call any copy operations), and potentially a 'destroy' segment. However, actually calling 'init' functions on each of the elements in them are not properly implemented, and will be in a followup patch. This patch implements all of that, and adds tests in a way that will be useful for firstprivate as well.
1 parent e7200c7 commit 25c0776

File tree

10 files changed

+1643
-7
lines changed

10 files changed

+1643
-7
lines changed

clang/lib/CIR/CodeGen/CIRGenDecl.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ using namespace clang;
2424
using namespace clang::CIRGen;
2525

2626
CIRGenFunction::AutoVarEmission
27-
CIRGenFunction::emitAutoVarAlloca(const VarDecl &d) {
27+
CIRGenFunction::emitAutoVarAlloca(const VarDecl &d,
28+
mlir::OpBuilder::InsertPoint ip) {
2829
QualType ty = d.getType();
2930
if (ty.getAddressSpace() != LangAS::Default)
3031
cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: address space");
@@ -50,7 +51,8 @@ CIRGenFunction::emitAutoVarAlloca(const VarDecl &d) {
5051
// A normal fixed sized variable becomes an alloca in the entry block,
5152
mlir::Type allocaTy = convertTypeForMem(ty);
5253
// Create the temp alloca and declare variable using it.
53-
address = createTempAlloca(allocaTy, alignment, loc, d.getName());
54+
address = createTempAlloca(allocaTy, alignment, loc, d.getName(),
55+
/*arraySize=*/nullptr, /*alloca=*/nullptr, ip);
5456
declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()), alignment);
5557

5658
emission.Addr = address;

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,8 @@ class CIRGenFunction : public CIRGenTypeCache {
858858

859859
Address emitArrayToPointerDecay(const Expr *array);
860860

861-
AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d);
861+
AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d,
862+
mlir::OpBuilder::InsertPoint ip = {});
862863

863864
/// Emit code and set up symbol table for a variable declaration with auto,
864865
/// register, or no storage class specifier. These turn into simple stack
@@ -1377,6 +1378,7 @@ class CIRGenFunction : public CIRGenTypeCache {
13771378
mlir::Location beginLoc;
13781379
mlir::Value varValue;
13791380
std::string name;
1381+
QualType baseType;
13801382
llvm::SmallVector<mlir::Value> bounds;
13811383
};
13821384
// Gets the collection of info required to lower and OpenACC clause or cache

clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,13 @@ CIRGenFunction::getOpenACCDataOperandInfo(const Expr *e) {
119119

120120
if (const auto *memExpr = dyn_cast<MemberExpr>(curVarExpr))
121121
return {exprLoc, emitMemberExpr(memExpr).getPointer(), exprString,
122-
std::move(bounds)};
122+
curVarExpr->getType(), std::move(bounds)};
123123

124124
// Sema has made sure that only 4 types of things can get here, array
125125
// subscript, array section, member expr, or DRE to a var decl (or the
126126
// former 3 wrapping a var-decl), so we should be able to assume this is
127127
// right.
128128
const auto *dre = cast<DeclRefExpr>(curVarExpr);
129129
return {exprLoc, emitDeclRefLValue(dre).getPointer(), exprString,
130-
std::move(bounds)};
130+
curVarExpr->getType(), std::move(bounds)};
131131
}

clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <type_traits>
1414

15+
#include "CIRGenCXXABI.h"
1516
#include "CIRGenFunction.h"
1617

1718
#include "clang/AST/ExprCXX.h"
@@ -355,6 +356,110 @@ class OpenACCClauseCIREmitter final
355356
}
356357
}
357358

359+
template <typename RecipeTy>
360+
RecipeTy getOrCreateRecipe(ASTContext &astCtx, const Expr *varRef,
361+
DeclContext *dc, QualType baseType,
362+
mlir::Value mainOp) {
363+
mlir::ModuleOp mod =
364+
builder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
365+
366+
std::string recipeName;
367+
{
368+
llvm::raw_string_ostream stream(recipeName);
369+
if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
370+
stream << "privatization_";
371+
} else if constexpr (std::is_same_v<RecipeTy,
372+
mlir::acc::FirstprivateRecipeOp>) {
373+
stream << "firstprivatization_";
374+
375+
} else if constexpr (std::is_same_v<RecipeTy,
376+
mlir::acc::ReductionRecipeOp>) {
377+
stream << "reduction_";
378+
// We don't have the reduction operation here well enough to know how to
379+
// spell this correctly (+ == 'add', etc), so when we implement
380+
// 'reduction' we have to do that here.
381+
cgf.cgm.errorNYI(varRef->getSourceRange(),
382+
"OpeNACC reduction recipe creation");
383+
} else {
384+
static_assert(!sizeof(RecipeTy), "Unknown Recipe op kind");
385+
}
386+
387+
MangleContext &mc = cgf.cgm.getCXXABI().getMangleContext();
388+
mc.mangleCanonicalTypeName(baseType, stream);
389+
}
390+
391+
if (auto recipe = mod.lookupSymbol<RecipeTy>(recipeName))
392+
return recipe;
393+
394+
mlir::Location loc = cgf.cgm.getLoc(varRef->getBeginLoc());
395+
mlir::Location locEnd = cgf.cgm.getLoc(varRef->getEndLoc());
396+
397+
mlir::OpBuilder modBuilder(mod.getBodyRegion());
398+
auto recipe =
399+
RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType());
400+
401+
// Magic-up a var-decl so we can use normal init/destruction operations for
402+
// a variable declaration.
403+
VarDecl &tempDecl = *VarDecl::Create(
404+
astCtx, dc, varRef->getBeginLoc(), varRef->getBeginLoc(),
405+
&astCtx.Idents.get("openacc.private.init"), baseType,
406+
astCtx.getTrivialTypeSourceInfo(baseType), SC_Auto);
407+
CIRGenFunction::AutoVarEmission tempDeclEmission{
408+
CIRGenFunction::AutoVarEmission::invalid()};
409+
410+
// Init section.
411+
{
412+
llvm::SmallVector<mlir::Type> argsTys{mainOp.getType()};
413+
llvm::SmallVector<mlir::Location> argsLocs{loc};
414+
builder.createBlock(&recipe.getInitRegion(), recipe.getInitRegion().end(),
415+
argsTys, argsLocs);
416+
builder.setInsertionPointToEnd(&recipe.getInitRegion().back());
417+
418+
if constexpr (!std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
419+
// We have only implemented 'init' for private, so make this NYI until
420+
// we have explicitly implemented everything.
421+
cgf.cgm.errorNYI(varRef->getSourceRange(),
422+
"OpenACC non-private recipe init");
423+
}
424+
425+
tempDeclEmission =
426+
cgf.emitAutoVarAlloca(tempDecl, builder.saveInsertionPoint());
427+
cgf.emitAutoVarInit(tempDeclEmission);
428+
429+
mlir::acc::YieldOp::create(builder, locEnd);
430+
}
431+
432+
// Copy section.
433+
if constexpr (std::is_same_v<RecipeTy, mlir::acc::FirstprivateRecipeOp> ||
434+
std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) {
435+
// TODO: OpenACC: 'private' doesn't emit this, but for the other two we
436+
// have to figure out what 'copy' means here.
437+
cgf.cgm.errorNYI(varRef->getSourceRange(),
438+
"OpenACC record type privatization copy section");
439+
}
440+
441+
// Destroy section (doesn't currently exist).
442+
if (tempDecl.needsDestruction(cgf.getContext())) {
443+
llvm::SmallVector<mlir::Type> argsTys{mainOp.getType()};
444+
llvm::SmallVector<mlir::Location> argsLocs{loc};
445+
mlir::Block *block = builder.createBlock(&recipe.getDestroyRegion(),
446+
recipe.getDestroyRegion().end(),
447+
argsTys, argsLocs);
448+
builder.setInsertionPointToEnd(&recipe.getDestroyRegion().back());
449+
450+
mlir::Type elementTy =
451+
mlir::cast<cir::PointerType>(mainOp.getType()).getPointee();
452+
Address addr{block->getArgument(0), elementTy,
453+
cgf.getContext().getDeclAlign(&tempDecl)};
454+
cgf.emitDestroy(addr, baseType,
455+
cgf.getDestroyer(QualType::DK_cxx_destructor));
456+
457+
mlir::acc::YieldOp::create(builder, locEnd);
458+
}
459+
460+
return recipe;
461+
}
462+
358463
public:
359464
OpenACCClauseCIREmitter(OpTy &operation, CIRGen::CIRGenFunction &cgf,
360465
CIRGen::CIRGenBuilderTy &builder,
@@ -971,6 +1076,37 @@ class OpenACCClauseCIREmitter final
9711076
llvm_unreachable("Unknown construct kind in VisitAttachClause");
9721077
}
9731078
}
1079+
1080+
void VisitPrivateClause(const OpenACCPrivateClause &clause) {
1081+
if constexpr (isOneOfTypes<OpTy, mlir::acc::ParallelOp, mlir::acc::SerialOp,
1082+
mlir::acc::LoopOp>) {
1083+
for (const Expr *var : clause.getVarList()) {
1084+
CIRGenFunction::OpenACCDataOperandInfo opInfo =
1085+
cgf.getOpenACCDataOperandInfo(var);
1086+
auto privateOp = mlir::acc::PrivateOp::create(
1087+
builder, opInfo.beginLoc, opInfo.varValue, /*structured=*/true,
1088+
/*implicit=*/false, opInfo.name, opInfo.bounds);
1089+
privateOp.setDataClause(mlir::acc::DataClause::acc_private);
1090+
1091+
{
1092+
mlir::OpBuilder::InsertionGuard guardCase(builder);
1093+
auto recipe = getOrCreateRecipe<mlir::acc::PrivateRecipeOp>(
1094+
cgf.getContext(), var, Decl::castToDeclContext(cgf.curFuncDecl),
1095+
opInfo.baseType, privateOp.getResult());
1096+
// TODO: OpenACC: The dialect is going to change in the near future to
1097+
// have these be on a different operation, so when that changes, we
1098+
// probably need to change these here.
1099+
operation.addPrivatization(builder.getContext(), privateOp, recipe);
1100+
}
1101+
}
1102+
} else if constexpr (isCombinedType<OpTy>) {
1103+
// Despite this being valid on ParallelOp or SerialOp, combined type
1104+
// applies to the 'loop'.
1105+
applyToLoopOp(clause);
1106+
} else {
1107+
llvm_unreachable("Unknown construct kind in VisitPrivateClause");
1108+
}
1109+
}
9741110
};
9751111

9761112
template <typename OpTy>

0 commit comments

Comments
 (0)