| //===-- CompilerInstance.h - Flang Compiler Instance ------------*- C++ -*-===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef FORTRAN_FRONTEND_COMPILERINSTANCE_H |
| #define FORTRAN_FRONTEND_COMPILERINSTANCE_H |
| |
| #include "flang/Frontend/CompilerInvocation.h" |
| #include "flang/Frontend/FrontendAction.h" |
| #include "flang/Frontend/PreprocessorOptions.h" |
| #include "flang/Parser/parsing.h" |
| #include "flang/Parser/provenance.h" |
| #include "flang/Semantics/runtime-type-info.h" |
| #include "flang/Semantics/semantics.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include "llvm/Target/TargetMachine.h" |
| |
| namespace Fortran::frontend { |
| |
| /// Helper class for managing a single instance of the Flang compiler. |
| /// |
| /// This class serves two purposes: |
| /// (1) It manages the various objects which are necessary to run the compiler |
| /// (2) It provides utility routines for constructing and manipulating the |
| /// common Flang objects. |
| /// |
| /// The compiler instance generally owns the instance of all the objects that it |
| /// manages. However, clients can still share objects by manually setting the |
| /// object and retaking ownership prior to destroying the CompilerInstance. |
| /// |
| /// The compiler instance is intended to simplify clients, but not to lock them |
| /// in to the compiler instance for everything. When possible, utility functions |
| /// come in two forms; a short form that reuses the CompilerInstance objects, |
| /// and a long form that takes explicit instances of any required objects. |
| class CompilerInstance { |
| |
| /// The options used in this compiler instance. |
| std::shared_ptr<CompilerInvocation> invocation; |
| |
| /// Flang file manager. |
| std::shared_ptr<Fortran::parser::AllSources> allSources; |
| |
| std::shared_ptr<Fortran::parser::AllCookedSources> allCookedSources; |
| |
| std::shared_ptr<Fortran::parser::Parsing> parsing; |
| |
| std::unique_ptr<Fortran::semantics::Semantics> semantics; |
| |
| std::unique_ptr<Fortran::semantics::RuntimeDerivedTypeTables> rtTyTables; |
| |
| std::unique_ptr<Fortran::semantics::SemanticsContext> semaContext; |
| |
| std::unique_ptr<llvm::TargetMachine> targetMachine; |
| |
| /// The stream for diagnostics from Semantics |
| llvm::raw_ostream *semaOutputStream = &llvm::errs(); |
| |
| /// The stream for diagnostics from Semantics if owned, otherwise nullptr. |
| std::unique_ptr<llvm::raw_ostream> ownedSemaOutputStream; |
| |
| /// The diagnostics engine instance. |
| llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics; |
| |
| /// Holds information about the output file. |
| struct OutputFile { |
| std::string filename; |
| OutputFile(std::string inputFilename) |
| : filename(std::move(inputFilename)) {} |
| }; |
| |
| /// The list of active output files. |
| std::list<OutputFile> outputFiles; |
| |
| /// Holds the output stream provided by the user. Normally, users of |
| /// CompilerInstance will call CreateOutputFile to obtain/create an output |
| /// stream. If they want to provide their own output stream, this field will |
| /// facilitate this. It is optional and will normally be just a nullptr. |
| std::unique_ptr<llvm::raw_pwrite_stream> outputStream; |
| |
| public: |
| explicit CompilerInstance(); |
| |
| ~CompilerInstance(); |
| |
| /// @name Compiler Invocation |
| /// { |
| |
| CompilerInvocation &getInvocation() { |
| assert(invocation && "Compiler instance has no invocation!"); |
| return *invocation; |
| }; |
| |
| /// Replace the current invocation. |
| void setInvocation(std::shared_ptr<CompilerInvocation> value); |
| |
| /// } |
| /// @name File manager |
| /// { |
| |
| /// Return the current allSources. |
| Fortran::parser::AllSources &getAllSources() const { return *allSources; } |
| |
| bool hasAllSources() const { return allSources != nullptr; } |
| |
| parser::AllCookedSources &getAllCookedSources() { |
| assert(allCookedSources && "Compiler instance has no AllCookedSources!"); |
| return *allCookedSources; |
| }; |
| |
| /// } |
| /// @name Parser Operations |
| /// { |
| |
| /// Return parsing to be used by Actions. |
| Fortran::parser::Parsing &getParsing() const { return *parsing; } |
| |
| /// } |
| /// @name Semantic analysis |
| /// { |
| |
| Fortran::semantics::SemanticsContext &getSemanticsContext() { |
| return *semaContext; |
| } |
| const Fortran::semantics::SemanticsContext &getSemanticsContext() const { |
| return *semaContext; |
| } |
| |
| /// Replace the current stream for verbose output. |
| void setSemaOutputStream(llvm::raw_ostream &value); |
| |
| /// Replace the current stream for verbose output. |
| void setSemaOutputStream(std::unique_ptr<llvm::raw_ostream> value); |
| |
| /// Get the current stream for verbose output. |
| llvm::raw_ostream &getSemaOutputStream() { return *semaOutputStream; } |
| |
| Fortran::semantics::Semantics &getSemantics() { return *semantics; } |
| const Fortran::semantics::Semantics &getSemantics() const { |
| return *semantics; |
| } |
| |
| void setSemantics(std::unique_ptr<Fortran::semantics::Semantics> sema) { |
| semantics = std::move(sema); |
| } |
| |
| void setRtTyTables( |
| std::unique_ptr<Fortran::semantics::RuntimeDerivedTypeTables> tables) { |
| rtTyTables = std::move(tables); |
| } |
| |
| Fortran::semantics::RuntimeDerivedTypeTables &getRtTyTables() { |
| assert(rtTyTables && "Missing runtime derived type tables!"); |
| return *rtTyTables; |
| } |
| |
| /// } |
| /// @name High-Level Operations |
| /// { |
| |
| /// Execute the provided action against the compiler's |
| /// CompilerInvocation object. |
| /// \param act - The action to execute. |
| /// \return - True on success. |
| bool executeAction(FrontendAction &act); |
| |
| /// } |
| /// @name Forwarding Methods |
| /// { |
| |
| clang::DiagnosticOptions &getDiagnosticOpts() { |
| return invocation->getDiagnosticOpts(); |
| } |
| const clang::DiagnosticOptions &getDiagnosticOpts() const { |
| return invocation->getDiagnosticOpts(); |
| } |
| |
| FrontendOptions &getFrontendOpts() { return invocation->getFrontendOpts(); } |
| const FrontendOptions &getFrontendOpts() const { |
| return invocation->getFrontendOpts(); |
| } |
| |
| PreprocessorOptions &preprocessorOpts() { |
| return invocation->getPreprocessorOpts(); |
| } |
| const PreprocessorOptions &preprocessorOpts() const { |
| return invocation->getPreprocessorOpts(); |
| } |
| |
| /// } |
| /// @name Diagnostics Engine |
| /// { |
| |
| bool hasDiagnostics() const { return diagnostics != nullptr; } |
| |
| /// Get the current diagnostics engine. |
| clang::DiagnosticsEngine &getDiagnostics() const { |
| assert(diagnostics && "Compiler instance has no diagnostics!"); |
| return *diagnostics; |
| } |
| |
| clang::DiagnosticConsumer &getDiagnosticClient() const { |
| assert(diagnostics && diagnostics->getClient() && |
| "Compiler instance has no diagnostic client!"); |
| return *diagnostics->getClient(); |
| } |
| |
| /// { |
| /// @name Output Files |
| /// { |
| |
| /// Clear the output file list. |
| void clearOutputFiles(bool eraseFiles); |
| |
| /// Create the default output file (based on the invocation's options) and |
| /// add it to the list of tracked output files. If the name of the output |
| /// file is not provided, it will be derived from the input file. |
| /// |
| /// \param binary The mode to open the file in. |
| /// \param baseInput If the invocation contains no output file name (i.e. |
| /// outputFile in FrontendOptions is empty), the input path |
| /// name to use for deriving the output path. |
| /// \param extension The extension to use for output names derived from |
| /// \p baseInput. |
| /// \return Null on error, ostream for the output file otherwise |
| std::unique_ptr<llvm::raw_pwrite_stream> |
| createDefaultOutputFile(bool binary = true, llvm::StringRef baseInput = "", |
| llvm::StringRef extension = ""); |
| |
| /// { |
| /// @name Target Machine |
| /// { |
| |
| /// Get the target machine. |
| const llvm::TargetMachine &getTargetMachine() const { |
| assert(targetMachine && "target machine was not set"); |
| return *targetMachine; |
| } |
| llvm::TargetMachine &getTargetMachine() { |
| assert(targetMachine && "target machine was not set"); |
| return *targetMachine; |
| } |
| |
| /// Sets up LLVM's TargetMachine. |
| bool setUpTargetMachine(); |
| |
| /// Produces the string which represents target feature |
| std::string getTargetFeatures(); |
| |
| private: |
| /// Create a new output file |
| /// |
| /// \param outputPath The path to the output file. |
| /// \param binary The mode to open the file in. |
| /// \return Null on error, ostream for the output file otherwise |
| llvm::Expected<std::unique_ptr<llvm::raw_pwrite_stream>> |
| createOutputFileImpl(llvm::StringRef outputPath, bool binary); |
| |
| public: |
| /// } |
| /// @name Construction Utility Methods |
| /// { |
| |
| /// Create a DiagnosticsEngine object |
| /// |
| /// If no diagnostic client is provided, this method creates a |
| /// DiagnosticConsumer that is owned by the returned diagnostic object. If |
| /// using directly the caller is responsible for releasing the returned |
| /// DiagnosticsEngine's client eventually. |
| /// |
| /// \param opts - The diagnostic options; note that the created text |
| /// diagnostic object contains a reference to these options. |
| /// |
| /// \param client - If non-NULL, a diagnostic client that will be attached to |
| /// (and optionally, depending on /p shouldOwnClient, owned by) the returned |
| /// DiagnosticsEngine object. |
| /// |
| /// \return The new object on success, or null on failure. |
| static clang::IntrusiveRefCntPtr<clang::DiagnosticsEngine> |
| createDiagnostics(clang::DiagnosticOptions *opts, |
| clang::DiagnosticConsumer *client = nullptr, |
| bool shouldOwnClient = true); |
| void createDiagnostics(clang::DiagnosticConsumer *client = nullptr, |
| bool shouldOwnClient = true); |
| |
| /// } |
| /// @name Output Stream Methods |
| /// { |
| void setOutputStream(std::unique_ptr<llvm::raw_pwrite_stream> outStream) { |
| outputStream = std::move(outStream); |
| } |
| |
| bool isOutputStreamNull() { return (outputStream == nullptr); } |
| |
| // Allow the frontend compiler to write in the output stream. |
| void writeOutputStream(const std::string &message) { |
| *outputStream << message; |
| } |
| |
| /// Get the user specified output stream. |
| llvm::raw_pwrite_stream &getOutputStream() { |
| assert(outputStream && |
| "Compiler instance has no user-specified output stream!"); |
| return *outputStream; |
| } |
| }; |
| |
| } // end namespace Fortran::frontend |
| #endif // FORTRAN_FRONTEND_COMPILERINSTANCE_H |