llvm-project/clang/lib/CIR/CodeGen/CIRGenerator.cpp
Morris Hafner 0045bfca9c
[CIR} Add support for static member variable instantiation (#153200)
This patch handles both implicit and explicit template instantiations of
template class static member variables.
2025-08-13 18:03:05 +02:00

182 lines
6.2 KiB
C++

//===--- CIRGenerator.cpp - Emit CIR from ASTs ----------------------------===//
//
// 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 builds an AST and converts it to CIR.
//
//===----------------------------------------------------------------------===//
#include "CIRGenModule.h"
#include "mlir/Dialect/OpenACC/OpenACC.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/Target/LLVMIR/Import.h"
#include "clang/AST/DeclGroup.h"
#include "clang/CIR/CIRGenerator.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/OpenACC/RegisterOpenACCExtensions.h"
#include "llvm/IR/DataLayout.h"
using namespace cir;
using namespace clang;
void CIRGenerator::anchor() {}
CIRGenerator::CIRGenerator(clang::DiagnosticsEngine &diags,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
const CodeGenOptions &cgo)
: diags(diags), fs(std::move(vfs)), codeGenOpts{cgo},
handlingTopLevelDecls{0} {}
CIRGenerator::~CIRGenerator() {
// There should normally not be any leftover inline method definitions.
assert(deferredInlineMemberFuncDefs.empty() || diags.hasErrorOccurred());
}
static void setMLIRDataLayout(mlir::ModuleOp &mod, const llvm::DataLayout &dl) {
mlir::MLIRContext *mlirContext = mod.getContext();
mlir::DataLayoutSpecInterface dlSpec =
mlir::translateDataLayout(dl, mlirContext);
mod->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dlSpec);
}
void CIRGenerator::Initialize(ASTContext &astContext) {
using namespace llvm;
this->astContext = &astContext;
mlirContext = std::make_unique<mlir::MLIRContext>();
mlirContext->loadDialect<mlir::DLTIDialect>();
mlirContext->loadDialect<cir::CIRDialect>();
mlirContext->getOrLoadDialect<mlir::acc::OpenACCDialect>();
// Register extensions to integrate CIR types with OpenACC.
mlir::DialectRegistry registry;
cir::acc::registerOpenACCExtensions(registry);
mlirContext->appendDialectRegistry(registry);
cgm = std::make_unique<clang::CIRGen::CIRGenModule>(
*mlirContext.get(), astContext, codeGenOpts, diags);
mlir::ModuleOp mod = cgm->getModule();
llvm::DataLayout layout =
llvm::DataLayout(astContext.getTargetInfo().getDataLayoutString());
setMLIRDataLayout(mod, layout);
}
bool CIRGenerator::verifyModule() const { return cgm->verifyModule(); }
mlir::ModuleOp CIRGenerator::getModule() const { return cgm->getModule(); }
bool CIRGenerator::HandleTopLevelDecl(DeclGroupRef group) {
if (diags.hasUnrecoverableErrorOccurred())
return true;
HandlingTopLevelDeclRAII handlingDecl(*this);
for (Decl *decl : group)
cgm->emitTopLevelDecl(decl);
return true;
}
void CIRGenerator::HandleTranslationUnit(ASTContext &astContext) {
// Release the Builder when there is no error.
if (!diags.hasErrorOccurred() && cgm)
cgm->release();
// If there are errors before or when releasing the cgm, reset the module to
// stop here before invoking the backend.
assert(!cir::MissingFeatures::cleanupAfterErrorDiags());
}
void CIRGenerator::HandleInlineFunctionDefinition(FunctionDecl *d) {
if (diags.hasErrorOccurred())
return;
assert(d->doesThisDeclarationHaveABody());
// We may want to emit this definition. However, that decision might be
// based on computing the linkage, and we have to defer that in case we are
// inside of something that will chagne the method's final linkage, e.g.
// typedef struct {
// void bar();
// void foo() { bar(); }
// } A;
deferredInlineMemberFuncDefs.push_back(d);
// Provide some coverage mapping even for methods that aren't emitted.
// Don't do this for templated classes though, as they may not be
// instantiable.
assert(!cir::MissingFeatures::coverageMapping());
}
void CIRGenerator::emitDeferredDecls() {
if (deferredInlineMemberFuncDefs.empty())
return;
// Emit any deferred inline method definitions. Note that more deferred
// methods may be added during this loop, since ASTConsumer callbacks can be
// invoked if AST inspection results in declarations being added. Therefore,
// we use an index to loop over the deferredInlineMemberFuncDefs rather than
// a range.
HandlingTopLevelDeclRAII handlingDecls(*this);
for (unsigned i = 0; i != deferredInlineMemberFuncDefs.size(); ++i)
cgm->emitTopLevelDecl(deferredInlineMemberFuncDefs[i]);
deferredInlineMemberFuncDefs.clear();
}
/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl to
/// (e.g. struct, union, enum, class) is completed. This allows the client to
/// hack on the type, which can occur at any point in the file (because these
/// can be defined in declspecs).
void CIRGenerator::HandleTagDeclDefinition(TagDecl *d) {
if (diags.hasErrorOccurred())
return;
// Don't allow re-entrant calls to CIRGen triggered by PCH deserialization to
// emit deferred decls.
HandlingTopLevelDeclRAII handlingDecl(*this, /*EmitDeferred=*/false);
cgm->updateCompletedType(d);
// For MSVC compatibility, treat declarations of static data members with
// inline initializers as definitions.
if (astContext->getTargetInfo().getCXXABI().isMicrosoft())
cgm->errorNYI(d->getSourceRange(), "HandleTagDeclDefinition: MSABI");
// For OpenMP emit declare reduction functions, if required.
if (astContext->getLangOpts().OpenMP)
cgm->errorNYI(d->getSourceRange(), "HandleTagDeclDefinition: OpenMP");
}
void CIRGenerator::HandleTagDeclRequiredDefinition(const TagDecl *D) {
if (diags.hasErrorOccurred())
return;
assert(!cir::MissingFeatures::generateDebugInfo());
}
void CIRGenerator::HandleCXXStaticMemberVarInstantiation(VarDecl *D) {
if (diags.hasErrorOccurred())
return;
cgm->handleCXXStaticMemberVarInstantiation(D);
}
void CIRGenerator::CompleteTentativeDefinition(VarDecl *d) {
if (diags.hasErrorOccurred())
return;
cgm->emitTentativeDefinition(d);
}
void CIRGenerator::HandleVTable(CXXRecordDecl *rd) {
if (diags.hasErrorOccurred())
return;
cgm->errorNYI(rd->getSourceRange(), "HandleVTable");
}