Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 159 additions & 7 deletions clang/lib/CIR/CodeGen/CIRGenDeclOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
//===----------------------------------------------------------------------===//

#include "CIRGenFunction.h"
#include "CIRGenOpenACCHelpers.h"

#include "mlir/Dialect/OpenACC/OpenACC.h"
#include "clang/AST/DeclOpenACC.h"
#include "llvm/Support/SaveAndRestore.h"

using namespace clang;
using namespace clang::CIRGen;
Expand Down Expand Up @@ -96,6 +99,13 @@ struct OpenACCDeclareCleanup final : EHScopeStack::Cleanup {
};
} // namespace

void CIRGenModule::emitGlobalOpenACCDecl(const OpenACCConstructDecl *d) {
if (const auto *rd = dyn_cast<OpenACCRoutineDecl>(d))
emitGlobalOpenACCRoutineDecl(rd);
else
emitGlobalOpenACCDeclareDecl(cast<OpenACCDeclareDecl>(d));
}

void CIRGenFunction::emitOpenACCDeclare(const OpenACCDeclareDecl &d) {
mlir::Location exprLoc = cgm.getLoc(d.getBeginLoc());
auto enterOp = mlir::acc::DeclareEnterOp::create(
Expand All @@ -109,15 +119,157 @@ void CIRGenFunction::emitOpenACCDeclare(const OpenACCDeclareDecl &d) {
enterOp);
}

// Helper function that gets the declaration referenced by the declare clause.
// This is a simplified verison of the work that `getOpenACCDataOperandInfo`
// does, as it only has to get forms that 'declare' does.
static const Decl *getDeclareReferencedDecl(const Expr *e) {
const Expr *curVarExpr = e->IgnoreParenImpCasts();

// Since we allow array sections, we have to unpack the array sections here.
// We don't have to worry about other bounds, since only variable or array
// name (plus array sections as an extension) are permitted.
while (const auto *ase = dyn_cast<ArraySectionExpr>(curVarExpr))
curVarExpr = ase->getBase()->IgnoreParenImpCasts();

if (const auto *DRE = dyn_cast<DeclRefExpr>(curVarExpr))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (const auto *DRE = dyn_cast<DeclRefExpr>(curVarExpr))
if (const auto *dre= dyn_cast<DeclRefExpr>(curVarExpr))

return DRE->getFoundDecl()->getCanonicalDecl();

// MemberExpr is allowed when it is implicit 'this'.
return cast<MemberExpr>(curVarExpr)->getMemberDecl()->getCanonicalDecl();
}

template <typename BeforeOpTy, typename DataClauseTy>
void CIRGenModule::emitGlobalOpenACCDeclareDataOperands(
const Expr *varOperand, DataClauseTy dataClause,
OpenACCModifierKind modifiers, bool structured, bool implicit,
bool requiresDtor) {
// This is a template argument so that we don't have to include all of
// mlir::acc into CIRGenModule.
static_assert(std::is_same_v<DataClauseTy, mlir::acc::DataClause>);
mlir::Location exprLoc = getLoc(varOperand->getBeginLoc());
const Decl *refedDecl = getDeclareReferencedDecl(varOperand);
StringRef varName = getMangledName(GlobalDecl{cast<VarDecl>(refedDecl)});

// We have to emit two separate functions in this case, an acc_ctor and an
// acc_dtor. These two sections are/should remain reasonably equal, however
// the order of the clauses/vs-enter&exit in them makes combining these two
// sections not particularly attractive, so we have a bit of repetition.
{
mlir::OpBuilder::InsertionGuard guardCase(builder);
auto ctorOp = mlir::acc::GlobalConstructorOp::create(
builder, exprLoc, (varName + "_acc_ctor").str());
getModule().push_back(ctorOp);
mlir::Block *block = builder.createBlock(&ctorOp.getRegion(),
ctorOp.getRegion().end(), {}, {});
builder.setInsertionPointToEnd(block);
// These things are close enough to a function handling-wise we can just
// create this here.
CIRGenFunction cgf{*this, builder, true};
llvm::SaveAndRestore<CIRGenFunction *> savedCGF(curCGF, &cgf);
cgf.curFn = ctorOp;
CIRGenFunction::SourceLocRAIIObject fnLoc{cgf, exprLoc};

// This gets the information we need, PLUS emits the bounds correctly, so we
// have to do this in both enter and exit.
CIRGenFunction::OpenACCDataOperandInfo inf =
cgf.getOpenACCDataOperandInfo(varOperand);
auto beforeOp =
BeforeOpTy::create(builder, exprLoc, inf.varValue, structured, implicit,
inf.name, inf.bounds);
beforeOp.setDataClause(dataClause);
beforeOp.setModifiers(convertOpenACCModifiers(modifiers));

mlir::acc::DeclareEnterOp::create(
builder, exprLoc, mlir::acc::DeclareTokenType::get(&getMLIRContext()),
beforeOp.getResult());

mlir::acc::TerminatorOp::create(builder, exprLoc);
}

// copyin, create, and device_resident require a destructor, link does not. In
// the case of the first three, they are all a 'getdeviceptr', followed by the
// declare_exit, followed by a delete op in the destructor region.
if (requiresDtor) {
mlir::OpBuilder::InsertionGuard guardCase(builder);
auto ctorOp = mlir::acc::GlobalDestructorOp::create(
builder, exprLoc, (varName + "_acc_dtor").str());
getModule().push_back(ctorOp);
mlir::Block *block = builder.createBlock(&ctorOp.getRegion(),
ctorOp.getRegion().end(), {}, {});
builder.setInsertionPointToEnd(block);

// These things are close enough to a function handling-wise we can just
// create this here.
CIRGenFunction cgf{*this, builder, true};
llvm::SaveAndRestore<CIRGenFunction *> savedCGF(curCGF, &cgf);
cgf.curFn = ctorOp;
CIRGenFunction::SourceLocRAIIObject fnLoc{cgf, exprLoc};

CIRGenFunction::OpenACCDataOperandInfo inf =
cgf.getOpenACCDataOperandInfo(varOperand);
auto getDevPtr = mlir::acc::GetDevicePtrOp::create(
builder, exprLoc, inf.varValue, structured, implicit, inf.name,
inf.bounds);
getDevPtr.setDataClause(dataClause);
getDevPtr.setModifiers(convertOpenACCModifiers(modifiers));

mlir::acc::DeclareExitOp::create(builder, exprLoc, /*token=*/mlir::Value{},
getDevPtr.getResult());
auto deleteOp = mlir::acc::DeleteOp::create(
builder, exprLoc, getDevPtr, structured, implicit, inf.name, {});
deleteOp.setDataClause(dataClause);
deleteOp.setModifiers(convertOpenACCModifiers(modifiers));
mlir::acc::TerminatorOp::create(builder, exprLoc);
}
}
namespace {
// This class emits all of the information for a 'declare' at a global/ns/class
// scope. Each clause results in its own acc_ctor and acc_dtor for the variable.
// This class creates those and emits them properly.
// This behavior is unique/special enough from the emission of statement-level
// clauses that it doesn't really make sense to use that clause visitor.
class OpenACCGlobalDeclareClauseEmitter final
: public OpenACCClauseVisitor<OpenACCGlobalDeclareClauseEmitter> {
CIRGenModule &cgm;
void clauseNotImplemented(const OpenACCClause &c) {
cgm.errorNYI(c.getSourceRange(), "OpenACC Global Declare Clause",
c.getClauseKind());
}

public:
OpenACCGlobalDeclareClauseEmitter(CIRGenModule &cgm) : cgm(cgm) {}

void VisitClause(const OpenACCClause &clause) {
clauseNotImplemented(clause);
}

void emitClauses(ArrayRef<const OpenACCClause *> clauses) {
this->VisitClauseList(clauses);
}

void VisitCreateClause(const OpenACCCreateClause &clause) {
for (const Expr *var : clause.getVarList())
cgm.emitGlobalOpenACCDeclareDataOperands<mlir::acc::CreateOp>(
var, mlir::acc::DataClause::acc_create, clause.getModifierList(),
/*structured=*/true,
/*implicit=*/false, /*requiresDtor=*/true);
}
};
} // namespace

void CIRGenModule::emitGlobalOpenACCDeclareDecl(const OpenACCDeclareDecl *d) {
// Declare creates 1 'acc_ctor' and 0-1 'acc_dtor' per clause, since it needs
// a unique one on a per-variable basis. We can just use a clause emitter to
// do all the work.
mlir::OpBuilder::InsertionGuard guardCase(builder);
OpenACCGlobalDeclareClauseEmitter em{*this};
em.emitClauses(d->clauses());
}

void CIRGenFunction::emitOpenACCRoutine(const OpenACCRoutineDecl &d) {
getCIRGenModule().errorNYI(d.getSourceRange(), "OpenACC Routine Construct");
}

void CIRGenModule::emitGlobalOpenACCDecl(const OpenACCConstructDecl *d) {
if (isa<OpenACCRoutineDecl>(d))
errorNYI(d->getSourceRange(), "OpenACC Routine Construct");
else if (isa<OpenACCDeclareDecl>(d))
errorNYI(d->getSourceRange(), "OpenACC Declare Construct");
else
llvm_unreachable("unknown OpenACC declaration kind?");
void CIRGenModule::emitGlobalOpenACCRoutineDecl(const OpenACCRoutineDecl *d) {
errorNYI(d->getSourceRange(), "OpenACC Global Routine Construct");
}
6 changes: 3 additions & 3 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1513,10 +1513,10 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) {
break;
}
case Decl::OpenACCRoutine:
emitGlobalOpenACCDecl(cast<OpenACCRoutineDecl>(decl));
emitGlobalOpenACCRoutineDecl(cast<OpenACCRoutineDecl>(decl));
break;
case Decl::OpenACCDeclare:
emitGlobalOpenACCDecl(cast<OpenACCDeclareDecl>(decl));
emitGlobalOpenACCDeclareDecl(cast<OpenACCDeclareDecl>(decl));
break;
case Decl::Enum:
case Decl::Using: // using X; [C++]
Expand Down Expand Up @@ -1560,7 +1560,7 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) {
CXXRecordDecl *crd = cast<CXXRecordDecl>(decl);
assert(!cir::MissingFeatures::generateDebugInfo());
for (auto *childDecl : crd->decls())
if (isa<VarDecl, CXXRecordDecl, EnumDecl>(childDecl))
if (isa<VarDecl, CXXRecordDecl, EnumDecl, OpenACCDeclareDecl>(childDecl))
emitTopLevelDecl(childDecl);
break;
}
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,14 @@ class CIRGenModule : public CIRGenTypeCache {
bool performInit);

void emitGlobalOpenACCDecl(const clang::OpenACCConstructDecl *cd);
void emitGlobalOpenACCRoutineDecl(const clang::OpenACCRoutineDecl *cd);
void emitGlobalOpenACCDeclareDecl(const clang::OpenACCDeclareDecl *cd);
template <typename BeforeOpTy, typename DataClauseTy>
void emitGlobalOpenACCDeclareDataOperands(const Expr *varOperand,
DataClauseTy dataClause,
OpenACCModifierKind modifiers,
bool structured, bool implicit,
bool requiresDtor);

// C++ related functions.
void emitDeclContext(const DeclContext *dc);
Expand Down
34 changes: 4 additions & 30 deletions clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "CIRGenCXXABI.h"
#include "CIRGenFunction.h"
#include "CIRGenOpenACCHelpers.h"
#include "CIRGenOpenACCRecipe.h"

#include "clang/AST/ExprCXX.h"
Expand Down Expand Up @@ -182,33 +183,6 @@ class OpenACCClauseCIREmitter final
dataOperands.append(computeEmitter.dataOperands);
}

mlir::acc::DataClauseModifier
convertModifiers(OpenACCModifierKind modifiers) {
using namespace mlir::acc;
static_assert(static_cast<int>(OpenACCModifierKind::Zero) ==
static_cast<int>(DataClauseModifier::zero) &&
static_cast<int>(OpenACCModifierKind::Readonly) ==
static_cast<int>(DataClauseModifier::readonly) &&
static_cast<int>(OpenACCModifierKind::AlwaysIn) ==
static_cast<int>(DataClauseModifier::alwaysin) &&
static_cast<int>(OpenACCModifierKind::AlwaysOut) ==
static_cast<int>(DataClauseModifier::alwaysout) &&
static_cast<int>(OpenACCModifierKind::Capture) ==
static_cast<int>(DataClauseModifier::capture));

DataClauseModifier mlirModifiers{};

// The MLIR representation of this represents `always` as `alwaysin` +
// `alwaysout`. So do a small fixup here.
if (isOpenACCModifierBitSet(modifiers, OpenACCModifierKind::Always)) {
mlirModifiers = mlirModifiers | DataClauseModifier::always;
modifiers &= ~OpenACCModifierKind::Always;
}

mlirModifiers = mlirModifiers | static_cast<DataClauseModifier>(modifiers);
return mlirModifiers;
}

template <typename BeforeOpTy, typename AfterOpTy>
void addDataOperand(const Expr *varOperand, mlir::acc::DataClause dataClause,
OpenACCModifierKind modifiers, bool structured,
Expand Down Expand Up @@ -243,8 +217,8 @@ class OpenACCClauseCIREmitter final
// Set the 'rest' of the info for both operations.
beforeOp.setDataClause(dataClause);
afterOp.setDataClause(dataClause);
beforeOp.setModifiers(convertModifiers(modifiers));
afterOp.setModifiers(convertModifiers(modifiers));
beforeOp.setModifiers(convertOpenACCModifiers(modifiers));
afterOp.setModifiers(convertOpenACCModifiers(modifiers));

// Make sure we record these, so 'async' values can be updated later.
dataOperands.push_back(beforeOp.getOperation());
Expand All @@ -264,7 +238,7 @@ class OpenACCClauseCIREmitter final

// Set the 'rest' of the info for the operation.
beforeOp.setDataClause(dataClause);
beforeOp.setModifiers(convertModifiers(modifiers));
beforeOp.setModifiers(convertOpenACCModifiers(modifiers));

// Make sure we record these, so 'async' values can be updated later.
dataOperands.push_back(beforeOp.getOperation());
Expand Down
43 changes: 43 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenOpenACCHelpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This contains helpers for OpenACC emission that don't need to be in
// CIRGenModule, but can't live in a single .cpp file.
//
//===----------------------------------------------------------------------===//
#include "mlir/Dialect/OpenACC/OpenACC.h"
#include "clang/AST/DeclOpenACC.h"

namespace clang::CIRGen {
inline mlir::acc::DataClauseModifier
convertOpenACCModifiers(OpenACCModifierKind modifiers) {
using namespace mlir::acc;
static_assert(static_cast<int>(OpenACCModifierKind::Zero) ==
static_cast<int>(DataClauseModifier::zero) &&
static_cast<int>(OpenACCModifierKind::Readonly) ==
static_cast<int>(DataClauseModifier::readonly) &&
static_cast<int>(OpenACCModifierKind::AlwaysIn) ==
static_cast<int>(DataClauseModifier::alwaysin) &&
static_cast<int>(OpenACCModifierKind::AlwaysOut) ==
static_cast<int>(DataClauseModifier::alwaysout) &&
static_cast<int>(OpenACCModifierKind::Capture) ==
static_cast<int>(DataClauseModifier::capture));

DataClauseModifier mlirModifiers{};

// The MLIR representation of this represents `always` as `alwaysin` +
// `alwaysout`. So do a small fixup here.
if (isOpenACCModifierBitSet(modifiers, OpenACCModifierKind::Always)) {
mlirModifiers = mlirModifiers | DataClauseModifier::always;
modifiers &= ~OpenACCModifierKind::Always;
}

mlirModifiers = mlirModifiers | static_cast<DataClauseModifier>(modifiers);
return mlirModifiers;
}
} // namespace clang::CIRGen
Loading