Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
6 changes: 6 additions & 0 deletions clang/include/clang/AST/ASTConsumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ namespace clang {
class VarDecl;
class FunctionDecl;
class ImportDecl;
class OpenACCRoutineDecl;

/// ASTConsumer - This is an abstract interface that should be implemented by
/// clients that read ASTs. This abstraction layer allows the client to be
Expand Down Expand Up @@ -116,6 +117,11 @@ class ASTConsumer {
// variable has been instantiated.
virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *D) {}

/// Callback to handle the end-of-translation unit attachment of OpenACC
/// routine declaration information.
virtual void HandleOpenACCRoutineReference(const FunctionDecl *FD,
const OpenACCRoutineDecl *RD) {}

/// Callback involved at the end of a translation unit to
/// notify the consumer that a vtable for the given C++ class is
/// required.
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/CIR/CIRGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ class CIRGenerator : public clang::ASTConsumer {
void HandleTagDeclDefinition(clang::TagDecl *d) override;
void HandleTagDeclRequiredDefinition(const clang::TagDecl *D) override;
void HandleCXXStaticMemberVarInstantiation(clang::VarDecl *D) override;
void
HandleOpenACCRoutineReference(const clang::FunctionDecl *FD,
const clang::OpenACCRoutineDecl *RD) override;
void CompleteTentativeDefinition(clang::VarDecl *d) override;
void HandleVTable(clang::CXXRecordDecl *rd) override;

Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/Sema/SemaOpenACC.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,16 @@ class Scope;
class SemaOpenACC : public SemaBase {
public:
using DeclGroupPtrTy = OpaquePtr<DeclGroupRef>;
using RoutineRefListTy = std::pair<FunctionDecl *, OpenACCRoutineDecl *>;

private:
// We save a list of routine clauses that refer to a different function(that
// is, routine-with-a-name) so that we can do the emission at the 'end'. We
// have to do this, since functions can be emitted before they are referenced,
// and the OpenACCRoutineDecl isn't necessarily emitted, as it might be in a
// function/etc. So we do these emits at the end of the TU.
llvm::SmallVector<RoutineRefListTy> RoutineRefList;

struct ComputeConstructInfo {
/// Which type of compute construct we are inside of, which we can use to
/// determine whether we should add loops to the above collection. We can
Expand Down Expand Up @@ -752,6 +760,7 @@ class SemaOpenACC : public SemaBase {
};

SemaOpenACC(Sema &S);
void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU);

// Called when we encounter a 'while' statement, before looking at its 'body'.
void ActOnWhileStmt(SourceLocation WhileLoc);
Expand Down
77 changes: 75 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenDeclOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,9 +287,82 @@ void CIRGenModule::emitGlobalOpenACCDeclareDecl(const OpenACCDeclareDecl *d) {
}

void CIRGenFunction::emitOpenACCRoutine(const OpenACCRoutineDecl &d) {
getCIRGenModule().errorNYI(d.getSourceRange(), "OpenACC Routine Construct");
// Do nothing here. The OpenACCRoutineDeclAttr handles the implicit name
// cases, and the end-of-TU handling manages the named cases. This is
// necessary because these references aren't necessarily emitted themselves,
// but can be named anywhere.
}

void CIRGenModule::emitGlobalOpenACCRoutineDecl(const OpenACCRoutineDecl *d) {
errorNYI(d->getSourceRange(), "OpenACC Global Routine Construct");
// Do nothing here. The OpenACCRoutineDeclAttr handles the implicit name
// cases, and the end-of-TU handling manages the named cases. This is
// necessary because these references aren't necessarily emitted themselves,
// but can be named anywhere.
}

namespace {
class OpenACCRoutineClauseEmitter final
: public OpenACCClauseVisitor<OpenACCRoutineClauseEmitter> {
CIRGen::CIRGenBuilderTy &builder;
mlir::acc::RoutineOp routineOp;
llvm::SmallVector<mlir::acc::DeviceType> lastDeviceTypeValues;

public:
OpenACCRoutineClauseEmitter(CIRGen::CIRGenBuilderTy &builder,
mlir::acc::RoutineOp routineOp)
: builder(builder), routineOp(routineOp) {}

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

void VisitClause(const OpenACCClause &clause) {
llvm_unreachable("Invalid OpenACC clause on routine");
}

void VisitSeqClause(const OpenACCSeqClause &clause) {
routineOp.addSeq(builder.getContext(), lastDeviceTypeValues);
}
};
} // namespace

void CIRGenModule::emitOpenACCRoutineDecl(
const clang::FunctionDecl *funcDecl, cir::FuncOp func,
SourceLocation pragmaLoc, ArrayRef<const OpenACCClause *> clauses) {
mlir::OpBuilder::InsertionGuard guardCase(builder);
// These need to appear at the global module.
builder.setInsertionPointToEnd(&getModule().getBodyRegion().front());

mlir::Location routineLoc = getLoc(pragmaLoc);

std::stringstream routineNameSS;
// This follows the same naming format as Flang.
routineNameSS << "acc_routine_" << routineCounter++;
std::string routineName = routineNameSS.str();

// There isn't a good constructor for RoutineOp that just takes a location +
Copy link
Contributor

Choose a reason for hiding this comment

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

You're welcome to add it! :) Seems useful to me.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Perhaps I'll do so! I'll have to see what infra is around to do that.

// name + function, so we use one that creates an otherwise RoutineOp and
// count on the visitor/emitter to fill these in.
auto routineOp = mlir::acc::RoutineOp::create(
builder, routineLoc, routineName,
mlir::SymbolRefAttr::get(builder.getContext(), func.getName()), {}, {},
{}, {}, {}, {}, {}, /*hasNoHost=*/false, /*implicit=*/false, {}, {}, {});

// We have to add a pointer going the other direction via an acc.routine_info,
// from the func to the routine.
llvm::SmallVector<mlir::SymbolRefAttr> funcRoutines;
if (auto routineInfo =
func.getOperation()->getAttrOfType<mlir::acc::RoutineInfoAttr>(
mlir::acc::getRoutineInfoAttrName()))
funcRoutines.append(routineInfo.getAccRoutines().begin(),
routineInfo.getAccRoutines().end());

funcRoutines.push_back(
mlir::SymbolRefAttr::get(builder.getContext(), routineName));
func.getOperation()->setAttr(
mlir::acc::getRoutineInfoAttrName(),
mlir::acc::RoutineInfoAttr::get(func.getContext(), funcRoutines));

OpenACCRoutineClauseEmitter emitter{builder, routineOp};
emitter.emitClauses(clauses);
}
9 changes: 9 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2234,6 +2234,15 @@ CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name,

if (!cgf)
theModule.push_back(func);

if (this->getLangOpts().OpenACC) {
// We only have to handle this attribute, since OpenACCAnnotAttrs are
// handled via the end-of-TU work.
for (const auto *attr :
funcDecl->specific_attrs<OpenACCRoutineDeclAttr>())
emitOpenACCRoutineDecl(funcDecl, func, attr->getLocation(),
attr->Clauses);
}
}
return func;
}
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,12 @@ class CIRGenModule : public CIRGenTypeCache {
OpenACCModifierKind modifiers,
bool structured, bool implicit,
bool requiresDtor);
// Each of the acc.routine operations must have a unique name, so we just use
// an integer counter. This is how Flang does it, so it seems reasonable.
unsigned routineCounter = 0;
void emitOpenACCRoutineDecl(const clang::FunctionDecl *funcDecl,
cir::FuncOp func, SourceLocation pragmaLoc,
ArrayRef<const OpenACCClause *> clauses);

// C++ related functions.
void emitDeclContext(const DeclContext *dc);
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,18 @@ void CIRGenerator::HandleCXXStaticMemberVarInstantiation(VarDecl *D) {
cgm->handleCXXStaticMemberVarInstantiation(D);
}

void CIRGenerator::HandleOpenACCRoutineReference(const FunctionDecl *FD,
const OpenACCRoutineDecl *RD) {
llvm::StringRef mangledName = cgm->getMangledName(FD);
cir::FuncOp entry =
mlir::dyn_cast_if_present<cir::FuncOp>(cgm->getGlobalValue(mangledName));

// if this wasn't generated, don't force it to be.
if (!entry)
return;
cgm->emitOpenACCRoutineDecl(FD, entry, RD->getBeginLoc(), RD->clauses());
}

void CIRGenerator::CompleteTentativeDefinition(VarDecl *d) {
if (diags.hasErrorOccurred())
return;
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/CIR/FrontendAction/CIRGenAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ class CIRGenConsumer : public clang::ASTConsumer {
Gen->HandleCXXStaticMemberVarInstantiation(VD);
}

void HandleOpenACCRoutineReference(const FunctionDecl *FD,
const OpenACCRoutineDecl *RD) override {
Gen->HandleOpenACCRoutineReference(FD, RD);
}

void HandleInlineFunctionDefinition(FunctionDecl *D) override {
Gen->HandleInlineFunctionDefinition(D);
}
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1497,6 +1497,9 @@ void Sema::ActOnEndOfTranslationUnit() {

if (LangOpts.HLSL)
HLSL().ActOnEndOfTranslationUnit(getASTContext().getTranslationUnitDecl());
if (LangOpts.OpenACC)
OpenACC().ActOnEndOfTranslationUnit(
getASTContext().getTranslationUnitDecl());

// If there were errors, disable 'unused' warnings since they will mostly be
// noise. Don't warn for a use from a module: either we should warn on all
Expand Down
23 changes: 17 additions & 6 deletions clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//

#include "clang/Sema/SemaOpenACC.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclOpenACC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/Basic/DiagnosticSema.h"
Expand Down Expand Up @@ -2457,7 +2458,8 @@ OpenACCRoutineDecl *SemaOpenACC::CheckRoutineDecl(
ArrayRef<const OpenACCClause *> Clauses, SourceLocation EndLoc) {
assert(LParenLoc.isValid());

if (FunctionDecl *FD = getFunctionFromRoutineName(FuncRef)) {
FunctionDecl *FD = nullptr;
if ((FD = getFunctionFromRoutineName(FuncRef))) {
// OpenACC 3.3 2.15:
// In C and C++, function static variables are not supported in functions to
// which a routine directive applies.
Expand Down Expand Up @@ -2509,11 +2511,9 @@ OpenACCRoutineDecl *SemaOpenACC::CheckRoutineDecl(
{DirLoc, BindLoc});
FD->addAttr(RAA);
// In case we are referencing not the 'latest' version, make sure we add
// the attribute to all declarations.
while (FD != FD->getMostRecentDecl()) {
FD = FD->getMostRecentDecl();
FD->addAttr(RAA);
}
// the attribute to all declarations after the 'found' one.
for (auto *CurFD : FD->redecls())
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I have no idea what sort of nonsense I was trying at before. But this should do what I ACTUALLY meant to do.

CurFD->addAttr(RAA->clone(getASTContext()));
}

LastRoutineDecl = OpenACCRoutineDecl::Create(
Expand All @@ -2522,9 +2522,20 @@ OpenACCRoutineDecl *SemaOpenACC::CheckRoutineDecl(
LastRoutineDecl->setAccess(AS_public);
getCurContext()->addDecl(LastRoutineDecl);

if (FD) {
// Add this attribute to the list of annotations so that codegen can visit
// it later. FD doesn't necessarily exist, but that case should be
// diagnosed.
RoutineRefList.emplace_back(FD, LastRoutineDecl);
}
return LastRoutineDecl;
}

void SemaOpenACC::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) {
for (auto [FD, RoutineDecl] : RoutineRefList)
SemaRef.Consumer.HandleOpenACCRoutineReference(FD, RoutineDecl);
}

DeclGroupRef SemaOpenACC::ActOnEndRoutineDeclDirective(
SourceLocation StartLoc, SourceLocation DirLoc, SourceLocation LParenLoc,
Expr *ReferencedFunc, SourceLocation RParenLoc,
Expand Down

This file was deleted.

27 changes: 27 additions & 0 deletions clang/test/CIR/CodeGenOpenACC/routine-anon-ns.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// RUN: %clang_cc1 -fopenacc -Wno-openacc-self-if-potential-conflict -emit-cir -fclangir %s -o - | FileCheck %s

namespace {
#pragma acc routine seq
void NSFunc1(){}
#pragma acc routine seq
auto Lambda1 = [](){};

auto Lambda2 = [](){};
} // namespace

#pragma acc routine(NSFunc1) seq
#pragma acc routine(Lambda2) seq
void force_emit() {
NSFunc1();
Lambda1();
Lambda2();
}

// CHECK: cir.func{{.*}} @[[F1_NAME:[^\(]*]]({{.*}}){{.*}} attributes {acc.routine_info = #acc.routine_info<[@[[F1_R_NAME:.*]], @[[F1_R2_NAME:.*]]]>}
// CHECK: cir.func lambda{{.*}} @[[L1_NAME:[^\(]*]]({{.*}}){{.*}} attributes {acc.routine_info = #acc.routine_info<[@[[L1_R_NAME:.*]]]>}
// CHECK: cir.func lambda{{.*}} @[[L2_NAME:[^\(]*]]({{.*}}){{.*}} attributes {acc.routine_info = #acc.routine_info<[@[[L2_R_NAME:.*]]]>}
//
// CHECK: acc.routine @[[F1_R_NAME]] func(@[[F1_NAME]]) seq
// CHECK: acc.routine @[[L1_R_NAME]] func(@[[L1_NAME]]) seq
// CHECK: acc.routine @[[F1_R2_NAME]] func(@[[F1_NAME]]) seq
// CHECK: acc.routine @[[L2_R_NAME]] func(@[[L2_NAME]]) seq
35 changes: 35 additions & 0 deletions clang/test/CIR/CodeGenOpenACC/routine-globals.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// RUN: %clang_cc1 -fopenacc -Wno-openacc-self-if-potential-conflict -emit-cir -fclangir %s -o - | FileCheck %s

#pragma acc routine seq
auto Lambda1 = [](){};

auto Lambda2 = [](){};
#pragma acc routine(Lambda2) seq
#pragma acc routine(Lambda2) seq

#pragma acc routine seq
int GlobalFunc1();

int GlobalFunc2();
#pragma acc routine(GlobalFunc2) seq
#pragma acc routine(GlobalFunc1) seq

void force_emit() {
Lambda1();
Lambda2();
GlobalFunc1();
GlobalFunc2();
}

// CHECK: cir.func lambda{{.*}} @[[L1_NAME:[^\(]*]]({{.*}}){{.*}} attributes {acc.routine_info = #acc.routine_info<[@[[L1_R_NAME:.*]]]>}
// CHECK: cir.func lambda{{.*}} @[[L2_NAME:[^\(]*]]({{.*}}){{.*}} attributes {acc.routine_info = #acc.routine_info<[@[[L2_R_NAME:.*]], @[[L2_R2_NAME:.*]]]>}
//
// CHECK: cir.func{{.*}} @[[G1_NAME:[^\(]*]]({{.*}}){{.*}} attributes {acc.routine_info = #acc.routine_info<[@[[G1_R_NAME:.*]], @[[G1_R2_NAME:.*]]]>}
// CHECK: cir.func{{.*}} @[[G2_NAME:[^\(]*]]({{.*}}){{.*}} attributes {acc.routine_info = #acc.routine_info<[@[[G2_R_NAME:.*]]]>}

// CHECK: acc.routine @[[L1_R_NAME]] func(@[[L1_NAME]]) seq
// CHECK: acc.routine @[[G1_R_NAME]] func(@[[G1_NAME]]) seq
// CHECK: acc.routine @[[L2_R_NAME]] func(@[[L2_NAME]]) seq
// CHECK: acc.routine @[[L2_R2_NAME]] func(@[[L2_NAME]]) seq
// CHECK: acc.routine @[[G2_R_NAME]] func(@[[G2_NAME]]) seq
// CHECK: acc.routine @[[G1_R2_NAME]] func(@[[G1_NAME]]) seq
44 changes: 44 additions & 0 deletions clang/test/CIR/CodeGenOpenACC/routine-globals2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// RUN: %clang_cc1 -fopenacc -Wno-openacc-self-if-potential-conflict -emit-cir -fclangir %s -o - | FileCheck %s

#pragma acc routine seq
void GlobalFunc4();
#pragma acc routine(GlobalFunc4) seq

#pragma acc routine seq
#pragma acc routine seq
void GlobalFunc5();
#pragma acc routine(GlobalFunc5) seq
#pragma acc routine(GlobalFunc5) seq

void GlobalFunc6();
void GlobalFunc6();
#pragma acc routine(GlobalFunc6) seq
void GlobalFunc6(){}

void GlobalFunc7(){}
#pragma acc routine(GlobalFunc7) seq

void force_emit() {
GlobalFunc4();
GlobalFunc5();
GlobalFunc6();
GlobalFunc7();
}

// CHECK: cir.func{{.*}} @[[G6_NAME:[^\(]*]]({{.*}}){{.*}} attributes {acc.routine_info = #acc.routine_info<[@[[G6_R_NAME:.*]]]>}
// CHECK: cir.func{{.*}} @[[G7_NAME:[^\(]*]]({{.*}}){{.*}} attributes {acc.routine_info = #acc.routine_info<[@[[G7_R_NAME:.*]]]>}

// CHECK: cir.func{{.*}} @[[G4_NAME:[^\(]*]]({{.*}}){{.*}} attributes {acc.routine_info = #acc.routine_info<[@[[G4_R_NAME:.*]], @[[G4_R2_NAME:.*]]]>}
// CHECK: cir.func{{.*}} @[[G5_NAME:[^\(]*]]({{.*}}){{.*}} attributes {acc.routine_info = #acc.routine_info<[@[[G5_R_NAME:.*]], @[[G5_R1_NAME:.*]], @[[G5_R2_NAME:.*]], @[[G5_R3_NAME:.*]]]>}

// CHECK: acc.routine @[[G4_R_NAME]] func(@[[G4_NAME]]) seq
// CHECK: acc.routine @[[G5_R_NAME]] func(@[[G5_NAME]]) seq
// CHECK: acc.routine @[[G5_R1_NAME]] func(@[[G5_NAME]]) seq
//
// CHECK: acc.routine @[[G4_R2_NAME]] func(@[[G4_NAME]]) seq
//
// CHECK: acc.routine @[[G5_R2_NAME]] func(@[[G5_NAME]]) seq
// CHECK: acc.routine @[[G5_R3_NAME]] func(@[[G5_NAME]]) seq
//
// CHECK: acc.routine @[[G6_R_NAME]] func(@[[G6_NAME]]) seq
// CHECK: acc.routine @[[G7_R_NAME]] func(@[[G7_NAME]]) seq
Loading
Loading