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/STLFunctionalExtras.h"
29#include "llvm/ADT/ScopeExit.h"
30#include "llvm/ADT/SmallString.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/Support/LibraryOptionsContext.h"
38#include "llvm/Support/MemoryBuffer.h"
39#include "llvm/Support/Path.h"
40#include "llvm/Support/raw_ostream.h"
53 "Unsupported output type for getBackendActionFromOutputType!");
66 llvm_unreachable(
"Unsupported output type!");
69static std::unique_ptr<llvm::Module>
72 llvm::StringRef mlirSaveTempsOutFile = {},
73 llvm::vfs::FileSystem *fs =
nullptr) {
75 mlirSaveTempsOutFile, fs);
81 mlir::OpPrintingFlags Flags;
82 Flags.enableDebugInfo(
true,
false);
83 MLIRModule->print(OS, Flags);
92 if (std::error_code ec = bufferOrErr.getError()) {
94 << fileName << ec.message();
97 std::unique_ptr<llvm::MemoryBuffer> buffer = std::move(bufferOrErr.get());
98 if (llvm::Error err = llvm::offloading::wrapSYCLBinaries(
99 M,
ArrayRef<char>(buffer->getBufferStart(), buffer->getBufferSize()),
100 llvm::offloading::SYCLJITOptions(),
true)) {
102 << llvm::toString(std::move(err));
115 mlir::ModuleOp MlirModule, llvm::LLVMContext &LLVMCtx,
118 std::unique_ptr<raw_pwrite_stream> OutputStream,
119 llvm::function_ref<
void(llvm::Module &)> AddFunctionSourceLocations = {}) {
123 if (OutputStream && MlirModule)
127 if (OutputStream && MlirModule &&
128 failed(mlir::writeBytecodeToFile(MlirModule, *OutputStream)) &&
137 std::string cirSaveTempsOutFile, mlirSaveTempsOutFile;
138 if (!saveTempsPrefix.empty()) {
140 llvm::sys::path::replace_extension(stem,
"cir");
141 cirSaveTempsOutFile = std::string(stem);
142 llvm::sys::path::replace_extension(stem,
"mlir");
143 mlirSaveTempsOutFile = std::string(stem);
146 if (!cirSaveTempsOutFile.empty()) {
148 llvm::raw_fd_ostream
out(cirSaveTempsOutFile, ec);
150 MlirModule->print(
out);
159 auto LangOptsAttr = MlirModule->getAttrOfType<cir::LoweringLangOptionsAttr>(
160 cir::CIRDialect::getLoweringLangOptionsAttrName());
161 const bool EnableOpenMP = LangOptsAttr && LangOptsAttr.getOpenmp();
166 std::unique_ptr<llvm::DiagnosticHandler> OldDiagnosticHandler =
167 LLVMCtx.getDiagnosticHandler();
168 llvm::scope_exit RestoreDiagnosticHandler([&]() {
169 LLVMCtx.setDiagnosticHandler(std::move(OldDiagnosticHandler));
178 std::unique_ptr<llvm::Module> LLVMModule =
191 if (AddFunctionSourceLocations)
192 AddFunctionSourceLocations(*LLVMModule);
213 "ClangIR code gen Not Yet Implemented: embedding offload objects "
214 "for CUDA, HIP or OpenMP offloading"));
222 EmbedBitcode(LLVMModule.get(), CGO, llvm::MemoryBufferRef());
234 virtual void anchor();
240 std::unique_ptr<raw_pwrite_stream> OutputStream;
244 std::unique_ptr<CIRGenerator> Gen;
248 llvm::LLVMContext &LLVMCtx;
251 std::optional<CIRDiagnosticHandler> MLIRDiagHandler;
261 llvm::LLVMContext &LLVMCtx,
263 : Action(Action), CI(CI), OutputStream(
std::move(OS)),
264 FS(&CI.getVirtualFileSystem()),
266 CI.getCodeGenOpts())),
267 FEOptions(CI.getFrontendOpts()), CGO(CGO), LLVMCtx(LLVMCtx),
268 LinkModules(LinkModules),
269 DiagConsumer(CI.getDiagnostics(), CI.getCodeGenOpts()) {}
272 assert(!Context &&
"initialized multiple times");
275 Gen->Initialize(Ctx);
279 MLIRDiagHandler.emplace(&Gen->getMLIRContext(), CI.getDiagnostics(),
280 CI.getSourceManager(), CI.getFileManager());
284 Gen->HandleTopLevelDecl(D);
289 Gen->HandleCXXStaticMemberVarInstantiation(VD);
294 Gen->HandleOpenACCRoutineReference(FD, RD);
298 Gen->HandleInlineFunctionDefinition(D);
302 Gen->HandleTranslationUnit(
C);
304 if (!FEOptions.ClangIRDisableCIRVerifier) {
305 if (!Gen->verifyModule()) {
308 if (!CI.getDiagnostics().hasErrorOccurred())
309 CI.getDiagnostics().Report(
310 diag::err_cir_verification_failed_pre_passes);
311 llvm::report_fatal_error(
312 "CIR codegen: module verification error before running CIR passes");
317 mlir::ModuleOp MlirModule = Gen->getModule();
318 mlir::MLIRContext &MlirCtx = Gen->getMLIRContext();
320 if (!FEOptions.ClangIRDisablePasses) {
321 std::string LibOptOptions = FEOptions.ClangIRLibOptOptions;
324 const bool EnableLibOpt =
325 FEOptions.ClangIRLibOptEnabled && (CGO.OptimizationLevel > 0);
327 MlirModule, MlirCtx, !FEOptions.ClangIRDisableCIRVerifier,
328 FEOptions.ClangIREnableIdiomRecognizer, CGO.OptimizationLevel > 0,
329 EnableLibOpt, LibOptOptions, FEOptions.ClangIRCallConvLowering)
333 if (!CI.getDiagnostics().hasErrorOccurred())
334 CI.getDiagnostics().Report(diag::err_cir_to_cir_transform_failed);
341 auto AddFunctionSourceLocations = [&](llvm::Module &LLVMModule) {
342 for (llvm::Function &F : LLVMModule.functions())
343 if (
const Decl *FD = Gen->getDeclForMangledName(F.getName()))
344 DiagConsumer.addFunctionSourceLocation(
345 F.getName(), FD->getASTContext().getFullLoc(FD->getLocation()));
348 DiagConsumer, std::move(OutputStream),
349 AddFunctionSourceLocations);
354 Context->getSourceManager(),
355 "CIR generation of declaration");
356 Gen->HandleTagDeclDefinition(D);
360 Gen->HandleTagDeclRequiredDefinition(D);
364 Gen->CompleteTentativeDefinition(D);
371void CIRGenConsumer::anchor() {}
387static std::unique_ptr<raw_pwrite_stream>
407 std::optional<llvm::MemoryBufferRef> MainFile =
412 mlir::MLIRContext MLIRContext;
425 mlir::OwningOpRef<mlir::ModuleOp>
Module =
426 mlir::parseSourceString<mlir::ModuleOp>(MainFile->getBuffer(),
427 mlir::ParserConfig(&MLIRContext),
428 MainFile->getBufferIdentifier());
431 Diags.
Report(diag::err_invalid_cir);
437 auto ModuleTriple = mlir::dyn_cast_if_present<mlir::StringAttr>(
438 (*Module)->getAttr(cir::CIRDialect::getTripleAttrName()));
440 Diags.
Report(diag::err_cir_input_missing_triple);
444 if (ModuleTriple.getValue() != TargetTriple) {
445 Diags.
Report(diag::err_cir_input_triple_mismatch)
446 << ModuleTriple.getValue() << TargetTriple;
460static std::unique_ptr<raw_pwrite_stream>
477 llvm_unreachable(
"Invalid CIRGenAction::OutputType");
480std::unique_ptr<ASTConsumer>
487 auto Result = std::make_unique<cir::CIRGenConsumer>(
493void EmitAssemblyAction::anchor() {}
497void EmitCIRAction::anchor() {}
500void EmitCIRBCAction::anchor() {}
503void EmitLLVMAction::anchor() {}
506void EmitBCAction::anchor() {}
509void 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...
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
CIRGenAction(OutputType Action)
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...
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 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.
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,...
std::unique_ptr< llvm::DiagnosticHandler > createDiagnosticHandler()
Create an llvm::DiagnosticHandler that forwards diagnostics to this consumer.
void setSourceManager(SourceManager *SM)
The SourceManager used to translate backend-reported file:line:col locations back into clang SourceLo...
Represents a C++ struct/union/class.
CodeGenOptions - Track various options which control how the code is optimized and passed to the back...
std::string OffloadBinaryToEmbedFile
Name of file passed with -foffload-include-binary option to forward to offloading runtime back-end fo...
std::string SaveTempsFilePrefix
Prefix to use for -save-temps output.
std::vector< std::string > OffloadObjects
List of filenames passed in using the -fembed-offload-object option.
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.
const llvm::cl::LibraryOptionsContext & getLibraryOptions() const
IntrusiveRefCntPtr< llvm::vfs::FileSystem > getVirtualFileSystemPtr() const
TargetOptions & getTargetOpts()
std::unique_ptr< llvm::raw_pwrite_stream > takeOutputStream()
TargetInfo & getTarget() const
llvm::vfs::FileSystem & getVirtualFileSystem() const
LangOptions & getLangOpts()
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.
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.
const char * getDataLayoutString() const
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)
Lowers mlirModule, a CIR module, to an LLVM module in llvmCtx.
static BackendAction getBackendActionFromOutputType(CIRGenAction::OutputType Action)
static void emitCIRModuleOutput(CIRGenAction::OutputType Action, CompilerInstance &CI, mlir::ModuleOp MlirModule, llvm::LLVMContext &LLVMCtx, SmallVectorImpl<::clang::LinkModule > &LinkModules, BackendDiagnosticConsumer &DiagConsumer, std::unique_ptr< raw_pwrite_stream > OutputStream, llvm::function_ref< void(llvm::Module &)> AddFunctionSourceLocations={})
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 void embedSYCLDeviceBinary(CompilerInstance &CI, llvm::Module &M)
static std::unique_ptr< llvm::Module > lowerFromCIRToLLVMIR(mlir::ModuleOp MLIRModule, llvm::LLVMContext &LLVMCtx, bool EnableOpenMP, llvm::StringRef mlirSaveTempsOutFile={}, llvm::vfs::FileSystem *fs=nullptr)
Top level wrappers for InstallAPI frontend operations.
bool loadLinkModules(CompilerInstance &CI, llvm::LLVMContext &Ctx, llvm::SmallVectorImpl< LinkModule > &LinkModules, bool OnlyInternalized)
Load every bitcode file listed in CodeGenOpts.LinkBitcodeFiles into LinkModules.
@ CIR
LLVM IR & CIR: we accept these so that we can run the optimizer on them, and compile them to assembly...
bool linkInModules(llvm::Module &M, llvm::SmallVectorImpl< LinkModule > &LinkModules, const CodeGenOptions &CodeGenOpts, const LangOptions &LangOpts, const TargetOptions &TargetOpts, BackendDiagnosticConsumer &DiagConsumer)
Link every module in LinkModules into M, propagating default function attributes and internalizing as...
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)
void EmbedBitcode(llvm::Module *M, const CodeGenOptions &CGOpts, llvm::MemoryBufferRef Buf)
@ 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.
Diagnostic wrappers for TextAPI types for error reporting.