11#include "mlir/Bytecode/BytecodeWriter.h"
12#include "mlir/IR/BuiltinOps.h"
13#include "mlir/IR/MLIRContext.h"
14#include "mlir/IR/OwningOpRef.h"
15#include "mlir/Parser/Parser.h"
28#include "llvm/ADT/ScopeExit.h"
29#include "llvm/ADT/SmallString.h"
30#include "llvm/ADT/StringSet.h"
31#include "llvm/Frontend/Offloading/OffloadWrapper.h"
32#include "llvm/IR/DiagnosticHandler.h"
33#include "llvm/IR/Function.h"
34#include "llvm/IR/GlobalValue.h"
35#include "llvm/IR/LLVMContext.h"
36#include "llvm/IR/Module.h"
37#include "llvm/Linker/Linker.h"
38#include "llvm/Support/MemoryBuffer.h"
39#include "llvm/Support/Path.h"
40#include "llvm/Support/raw_ostream.h"
41#include "llvm/Transforms/IPO/Internalize.h"
54 "Unsupported output type for getBackendActionFromOutputType!");
67 llvm_unreachable(
"Unsupported output type!");
70static std::unique_ptr<llvm::Module>
73 llvm::StringRef mlirSaveTempsOutFile = {},
74 llvm::vfs::FileSystem *fs =
nullptr) {
76 mlirSaveTempsOutFile, fs);
82 mlir::OpPrintingFlags Flags;
83 Flags.enableDebugInfo(
true,
false);
84 MLIRModule->print(OS, Flags);
89 virtual void anchor();
95 std::unique_ptr<raw_pwrite_stream> OutputStream;
99 std::unique_ptr<CIRGenerator> Gen;
103 llvm::LLVMContext &LLVMCtx;
106 std::optional<CIRDiagnosticHandler> MLIRDiagHandler;
116 llvm::LLVMContext &LLVMCtx,
118 : Action(Action), CI(CI), OutputStream(
std::move(OS)),
119 FS(&CI.getVirtualFileSystem()),
121 CI.getCodeGenOpts())),
122 FEOptions(CI.getFrontendOpts()), CGO(CGO), LLVMCtx(LLVMCtx),
123 LinkModules(LinkModules),
124 DiagConsumer(CI.getDiagnostics(), CI.getCodeGenOpts()) {}
127 assert(!Context &&
"initialized multiple times");
130 Gen->Initialize(Ctx);
134 MLIRDiagHandler.emplace(&Gen->getMLIRContext(), CI.getDiagnostics(),
135 CI.getSourceManager(), CI.getFileManager());
139 Gen->HandleTopLevelDecl(D);
144 Gen->HandleCXXStaticMemberVarInstantiation(VD);
149 Gen->HandleOpenACCRoutineReference(FD, RD);
153 Gen->HandleInlineFunctionDefinition(D);
157 Gen->HandleTranslationUnit(
C);
159 if (!FEOptions.ClangIRDisableCIRVerifier) {
160 if (!Gen->verifyModule()) {
163 if (!CI.getDiagnostics().hasErrorOccurred())
164 CI.getDiagnostics().Report(
165 diag::err_cir_verification_failed_pre_passes);
166 llvm::report_fatal_error(
167 "CIR codegen: module verification error before running CIR passes");
172 mlir::ModuleOp MlirModule = Gen->getModule();
173 mlir::MLIRContext &MlirCtx = Gen->getMLIRContext();
175 if (!FEOptions.ClangIRDisablePasses) {
176 std::string LibOptOptions = FEOptions.ClangIRLibOptOptions;
179 const bool EnableLibOpt =
180 FEOptions.ClangIRLibOptEnabled && (CGO.OptimizationLevel > 0);
182 MlirModule, MlirCtx, !FEOptions.ClangIRDisableCIRVerifier,
183 FEOptions.ClangIREnableIdiomRecognizer, CGO.OptimizationLevel > 0,
184 EnableLibOpt, LibOptOptions, FEOptions.ClangIRCallConvLowering)
188 if (!CI.getDiagnostics().hasErrorOccurred())
189 CI.getDiagnostics().Report(diag::err_cir_to_cir_transform_failed);
196 if (OutputStream && MlirModule)
200 if (OutputStream && MlirModule &&
201 failed(mlir::writeBytecodeToFile(MlirModule, *OutputStream)) &&
202 !CI.getDiagnostics().hasErrorOccurred())
203 CI.getDiagnostics().Report(diag::err_cir_bc_write_failed);
209 StringRef saveTempsPrefix = CGO.SaveTempsFilePrefix;
210 std::string cirSaveTempsOutFile, mlirSaveTempsOutFile;
211 if (!saveTempsPrefix.empty()) {
213 llvm::sys::path::replace_extension(stem,
"cir");
214 cirSaveTempsOutFile = std::string(stem);
215 llvm::sys::path::replace_extension(stem,
"mlir");
216 mlirSaveTempsOutFile = std::string(stem);
219 if (!cirSaveTempsOutFile.empty()) {
221 llvm::raw_fd_ostream
out(cirSaveTempsOutFile, ec);
223 MlirModule->print(
out);
227 if (CI.getDiagnostics().hasErrorOccurred())
233 std::unique_ptr<llvm::DiagnosticHandler> OldDiagnosticHandler =
234 LLVMCtx.getDiagnosticHandler();
235 llvm::scope_exit RestoreDiagnosticHandler([&]() {
236 LLVMCtx.setDiagnosticHandler(std::move(OldDiagnosticHandler));
238 LLVMCtx.setDiagnosticHandler(DiagConsumer.createDiagnosticHandler());
241 MlirModule, LLVMCtx,
C.getLangOpts().OpenMP, mlirSaveTempsOutFile,
242 &CI.getVirtualFileSystem());
244 LLVMModule->setDataLayout(
C.getTargetInfo().getDataLayoutString());
246 for (llvm::Function &F : LLVMModule->functions())
247 if (
const Decl *FD = Gen->getDeclForMangledName(F.getName()))
248 DiagConsumer.addFunctionSourceLocation(
249 F.getName(), FD->getASTContext().getFullLoc(FD->getLocation()));
255 if (
C.getLangOpts().SYCLIsHost && !CGO.OffloadBinaryToEmbedFile.empty())
262 if (!CGO.OffloadObjects.empty() &&
267 "ClangIR code gen Not Yet Implemented: embedding offload objects "
268 "for CUDA, HIP or OpenMP offloading"));
273 EmbedObject(LLVMModule.get(), CGO, CI.getVirtualFileSystem(),
274 CI.getDiagnostics());
278 std::move(OutputStream));
287 for (
auto &LM : LinkModules) {
288 assert(LM.Module &&
"LinkModule does not actually have a module");
290 if (LM.PropagateAttrs)
291 for (llvm::Function &F : *LM.Module) {
295 F, CGO, CI.getLangOpts(), CI.getTargetOpts(), LM.Internalize);
298 DiagConsumer.setCurLinkModule(LM.Module.get());
300 if (LM.Internalize) {
301 Err = llvm::Linker::linkModules(
302 M, std::move(LM.Module), LM.LinkFlags,
303 [](llvm::Module &M,
const llvm::StringSet<> &GVS) {
304 llvm::internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) {
305 return !GV.hasName() || (GVS.count(GV.getName()) == 0);
309 Err = llvm::Linker::linkModules(M, std::move(LM.Module), LM.LinkFlags);
324 StringRef fileName = CGO.OffloadBinaryToEmbedFile;
325 auto bufferOrErr = CI.getVirtualFileSystem().getBufferForFile(fileName);
326 if (std::error_code ec = bufferOrErr.getError()) {
327 CI.getDiagnostics().Report(diag::err_cannot_open_file)
328 << fileName << ec.message();
331 std::unique_ptr<llvm::MemoryBuffer> buffer = std::move(bufferOrErr.get());
332 if (llvm::Error err = llvm::offloading::wrapSYCLBinaries(
334 ArrayRef<char>(buffer->getBufferStart(), buffer->getBufferSize()),
335 llvm::offloading::SYCLJITOptions(),
true)) {
336 CI.getDiagnostics().Report(diag::err_fe_error_backend)
337 << llvm::toString(std::move(err));
344 Context->getSourceManager(),
345 "CIR generation of declaration");
346 Gen->HandleTagDeclDefinition(D);
350 Gen->HandleTagDeclRequiredDefinition(D);
354 Gen->CompleteTentativeDefinition(D);
361void CIRGenConsumer::anchor() {}
364 : MLIRCtx(MLIRCtx ? MLIRCtx : new
mlir::MLIRContext),
375static std::unique_ptr<raw_pwrite_stream>
395 std::optional<llvm::MemoryBufferRef> MainFile =
400 mlir::MLIRContext MLIRContext;
413 mlir::OwningOpRef<mlir::ModuleOp>
Module =
414 mlir::parseSourceString<mlir::ModuleOp>(MainFile->getBuffer(),
415 mlir::ParserConfig(&MLIRContext),
416 MainFile->getBufferIdentifier());
419 Diags.
Report(diag::err_invalid_cir);
425 auto ModuleTriple = mlir::dyn_cast_if_present<mlir::StringAttr>(
426 (*Module)->getAttr(cir::CIRDialect::getTripleAttrName()));
428 Diags.
Report(diag::err_cir_input_missing_triple);
432 if (ModuleTriple.getValue() != TargetTriple) {
433 Diags.
Report(diag::err_cir_input_triple_mismatch)
434 << ModuleTriple.getValue() << TargetTriple;
445 if (failed(mlir::writeBytecodeToFile(*
Module, *OS)) &&
447 Diags.
Report(diag::err_cir_bc_write_failed);
453 Diags.
Report(diag::err_fe_cir_input_unsupported);
458static std::unique_ptr<raw_pwrite_stream>
475 llvm_unreachable(
"Invalid CIRGenAction::OutputType");
478std::unique_ptr<ASTConsumer>
485 auto Result = std::make_unique<cir::CIRGenConsumer>(
491void EmitAssemblyAction::anchor() {}
495void EmitCIRAction::anchor() {}
499void EmitCIRBCAction::anchor() {}
503void EmitLLVMAction::anchor() {}
507void EmitBCAction::anchor() {}
511void EmitObjAction::anchor() {}
Defines the clang::ASTContext interface.
static std::unique_ptr< raw_pwrite_stream > getOutputStream(CompilerInstance &CI, StringRef InFile, CIRGenAction::OutputType Action)
Routes MLIR-side diagnostics emitted during CIR passes, the verifier, and CIR-to-LLVM lowering throug...
CIRGenAction(OutputType Action, mlir::MLIRContext *MLIRCtx=nullptr)
void ExecuteAction() override
Implement the ExecuteAction interface by running Sema on the already-initialized AST consumer.
bool BeginSourceFileAction(clang::CompilerInstance &CI) override
Callback at the start of processing a single input.
std::unique_ptr< clang::ASTConsumer > CreateASTConsumer(clang::CompilerInstance &CI, llvm::StringRef InFile) override
void Initialize(ASTContext &Ctx) override
Initialize - This is called to initialize the consumer, providing the ASTContext.
bool HandleTopLevelDecl(DeclGroupRef D) override
HandleTopLevelDecl - Handle the specified top-level declaration.
void HandleTranslationUnit(ASTContext &C) override
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
bool linkInModules(llvm::Module &M)
void HandleInlineFunctionDefinition(FunctionDecl *D) override
This callback is invoked each time an inline (method or friend) function definition in a class is com...
void CompleteTentativeDefinition(VarDecl *D) override
CompleteTentativeDefinition - Callback invoked at the end of a translation unit to notify the consume...
void HandleTagDeclRequiredDefinition(const TagDecl *D) override
This callback is invoked the first time each TagDecl is required to be complete.
CIRGenConsumer(CIRGenAction::OutputType Action, CompilerInstance &CI, CodeGenOptions &CGO, std::unique_ptr< raw_pwrite_stream > OS, llvm::LLVMContext &LLVMCtx, SmallVectorImpl<::clang::LinkModule > &LinkModules)
void embedSYCLDeviceBinary(llvm::Module &M)
void HandleVTable(CXXRecordDecl *RD) override
Callback involved at the end of a translation unit to notify the consumer that a vtable for the given...
void HandleCXXStaticMemberVarInstantiation(clang::VarDecl *VD) override
HandleCXXStaticMemberVarInstantiation - Tell the consumer that this.
void HandleOpenACCRoutineReference(const FunctionDecl *FD, const OpenACCRoutineDecl *RD) override
Callback to handle the end-of-translation unit attachment of OpenACC routine declaration information.
void HandleTagDeclDefinition(TagDecl *D) override
HandleTagDeclDefinition - This callback is invoked each time a TagDecl (e.g.
EmitAssemblyAction(mlir::MLIRContext *MLIRCtx=nullptr)
EmitBCAction(mlir::MLIRContext *MLIRCtx=nullptr)
EmitCIRAction(mlir::MLIRContext *MLIRCtx=nullptr)
EmitCIRBCAction(mlir::MLIRContext *MLIRCtx=nullptr)
EmitLLVMAction(mlir::MLIRContext *MLIRCtx=nullptr)
EmitObjAction(mlir::MLIRContext *MLIRCtx=nullptr)
ASTConsumer - This is an abstract interface that should be implemented by clients that read ASTs.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
void ExecuteAction() override
Implement the ExecuteAction interface by running Sema on the already-initialized AST consumer.
Owns the state needed to translate LLVM backend diagnostics into clang diagnostics,...
Represents a C++ struct/union/class.
CodeGenOptions - Track various options which control how the code is optimized and passed to the back...
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
std::unique_ptr< raw_pwrite_stream > createDefaultOutputFile(bool Binary=true, StringRef BaseInput="", StringRef Extension="", bool RemoveFileOnSignal=true, bool CreateMissingDirectories=false, bool ForceUseTemporary=false, bool SetOnlyIfDifferent=false)
Create the default output file (from the invocation's options) and add it to the list of tracked outp...
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
FileManager & getFileManager() const
Return the current file manager to the caller.
std::unique_ptr< llvm::raw_pwrite_stream > takeOutputStream()
TargetInfo & getTarget() const
CodeGenOptions & getCodeGenOpts()
SourceManager & getSourceManager() const
Return the current source manager.
Decl - This represents one declaration (or definition), e.g.
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
unsigned getCustomDiagID(Level L, const char(&FormatString)[N])
Return an ID for a diagnostic with the specified format string and level.
bool hasErrorOccurred() const
InputKind getCurrentFileKind() const
virtual bool BeginSourceFileAction(CompilerInstance &CI)
Callback at the start of processing a single input.
CompilerInstance & getCompilerInstance() const
StringRef getCurrentFileOrBufferName() const
FrontendOptions - Options for controlling the behavior of the frontend.
Represents a function declaration or definition.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
std::vector< llvm::Triple > OMPTargetTriples
Triples of the OpenMP targets that the host code codegen should take into account in order to generat...
Describes a module or submodule.
PrettyStackTraceDecl - If a crash occurs, indicate that it happened when doing something to a specifi...
Encodes a location in the source.
This class handles loading and caching of source files into memory.
FileID getMainFileID() const
Returns the FileID of the main source file.
std::optional< llvm::MemoryBufferRef > getBufferOrNone(FileID FID, SourceLocation Loc=SourceLocation()) const
Return the buffer for the specified FileID.
Represents the declaration of a struct/union/class/enum.
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Represents a variable declaration or definition.
std::unique_ptr< llvm::Module > lowerDirectlyFromCIRToLLVMIR(mlir::ModuleOp mlirModule, llvm::LLVMContext &llvmCtx, bool enableOpenMP, llvm::StringRef mlirSaveTempsOutFile={}, llvm::vfs::FileSystem *fs=nullptr)
static BackendAction getBackendActionFromOutputType(CIRGenAction::OutputType Action)
mlir::LogicalResult runCIRToCIRPasses(mlir::ModuleOp theModule, mlir::MLIRContext &mlirCtx, bool enableVerifier, bool enableIdiomRecognizer, bool enableCIRSimplify, bool enableLibOpt, llvm::StringRef libOptOptions, bool enableCallConvLowering)
static void printCIRModule(mlir::ModuleOp MLIRModule, raw_ostream &OS)
void registerAllDialects(mlir::DialectRegistry ®istry)
static std::unique_ptr< llvm::Module > lowerFromCIRToLLVMIR(mlir::ModuleOp MLIRModule, llvm::LLVMContext &LLVMCtx, bool EnableOpenMP, llvm::StringRef mlirSaveTempsOutFile={}, llvm::vfs::FileSystem *fs=nullptr)
void mergeDefaultFunctionDefinitionAttributes(llvm::Function &F, const CodeGenOptions &CodeGenOpts, const LangOptions &LangOpts, const TargetOptions &TargetOpts, bool WillInternalize)
Adds attributes to F according to our CodeGenOpts and LangOpts, as though we had emitted it ourselves...
Top level wrappers for InstallAPI frontend operations.
@ CIR
LLVM IR & CIR: we accept these so that we can run the optimizer on them, and compile them to assembly...
void EmbedObject(llvm::Module *M, const CodeGenOptions &CGOpts, llvm::vfs::FileSystem &VFS, DiagnosticsEngine &Diags)
void emitBackendOutput(CompilerInstance &CI, CodeGenOptions &CGOpts, llvm::Module *M, BackendAction Action, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, std::unique_ptr< raw_pwrite_stream > OS, BackendConsumer *BC=nullptr)
@ Backend_EmitAssembly
Emit native assembly files.
@ Backend_EmitLL
Emit human-readable LLVM assembly.
@ Backend_EmitBC
Emit LLVM bitcode files.
@ Backend_EmitObj
Emit native object files.
bool loadLinkModules(CompilerInstance &CI, llvm::LLVMContext &Ctx, llvm::SmallVectorImpl< LinkModule > &LinkModules)
Load every bitcode file listed in CodeGenOpts.LinkBitcodeFiles into LinkModules.
Diagnostic wrappers for TextAPI types for error reporting.