blob: 4d6a6c6c5d84544ef7395581a444123339256136 [file] [log] [blame]
//===--- 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/DLTI/DLTI.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/Target/LLVMIR/Import.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/CIR/CIRGenerator.h"
#include "clang/CIR/Dialect/IR/CIRDialect.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) {
auto *context = mod.getContext();
mod->setAttr(mlir::LLVM::LLVMDialect::getDataLayoutAttrName(),
mlir::StringAttr::get(context, dl.getStringRepresentation()));
mlir::DataLayoutSpecInterface dlSpec = mlir::translateDataLayout(dl, context);
mod->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dlSpec);
}
void CIRGenerator::Initialize(ASTContext &astCtx) {
using namespace llvm;
this->astCtx = &astCtx;
mlirCtx = std::make_unique<mlir::MLIRContext>();
mlirCtx->getOrLoadDialect<mlir::DLTIDialect>();
mlirCtx->getOrLoadDialect<mlir::func::FuncDialect>();
mlirCtx->getOrLoadDialect<mlir::cir::CIRDialect>();
mlirCtx->getOrLoadDialect<mlir::LLVM::LLVMDialect>();
mlirCtx->getOrLoadDialect<mlir::memref::MemRefDialect>();
mlirCtx->getOrLoadDialect<mlir::omp::OpenMPDialect>();
CGM = std::make_unique<CIRGenModule>(*mlirCtx.get(), astCtx, codeGenOpts,
Diags);
auto mod = CGM->getModule();
auto layout = llvm::DataLayout(astCtx.getTargetInfo().getDataLayoutString());
setMLIRDataLayout(mod, layout);
}
bool CIRGenerator::verifyModule() { return CGM->verifyModule(); }
bool CIRGenerator::EmitFunction(const FunctionDecl *FD) {
llvm_unreachable("NYI");
}
mlir::ModuleOp CIRGenerator::getModule() { return CGM->getModule(); }
bool CIRGenerator::HandleTopLevelDecl(DeclGroupRef D) {
if (Diags.hasErrorOccurred())
return true;
HandlingTopLevelDeclRAII HandlingDecl(*this);
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
CGM->buildTopLevelDecl(*I);
}
return true;
}
void CIRGenerator::HandleTranslationUnit(ASTContext &C) {
// 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.
if (Diags.hasErrorOccurred()) {
if (CGM)
// TODO: CGM->clear();
// TODO: M.reset();
return;
}
}
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.
if (!D->getLexicalDeclContext()->isDependentContext())
CGM->AddDeferredUnusedCoverageMapping(D);
}
void CIRGenerator::buildDefaultMethods() { CGM->buildDefaultMethods(); }
void CIRGenerator::buildDeferredDecls() {
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.
HandlingTopLevelDeclRAII HandlingDecls(*this);
for (unsigned I = 0; I != DeferredInlineMemberFuncDefs.size(); ++I)
CGM->buildTopLevelDecl(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 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 (astCtx->getTargetInfo().getCXXABI().isMicrosoft()) {
llvm_unreachable("NYI");
}
// For OpenMP emit declare reduction functions, if required.
if (astCtx->getLangOpts().OpenMP) {
llvm_unreachable("NYI");
}
}
void CIRGenerator::HandleTagDeclRequiredDefinition(const 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);
if (CGM->getModuleDebugInfo())
llvm_unreachable("NYI");
}
void CIRGenerator::HandleCXXStaticMemberVarInstantiation(VarDecl *D) {
if (Diags.hasErrorOccurred())
return;
CGM->HandleCXXStaticMemberVarInstantiation(D);
}
void CIRGenerator::CompleteTentativeDefinition(VarDecl *D) {
if (Diags.hasErrorOccurred())
return;
CGM->buildTentativeDefinition(D);
}