| //===--- Subsystems.h - Swift Compiler Subsystem Entrypoints ----*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file declares the main entrypoints to the various subsystems. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_SUBSYSTEMS_H |
| #define SWIFT_SUBSYSTEMS_H |
| |
| #include "swift/Basic/LLVM.h" |
| #include "swift/Basic/OptionSet.h" |
| #include "swift/Basic/Version.h" |
| #include "llvm/IR/LLVMContext.h" |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/Optional.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/Support/Mutex.h" |
| |
| #include <memory> |
| |
| namespace llvm { |
| class GlobalVariable; |
| class MemoryBuffer; |
| class Module; |
| class TargetOptions; |
| class TargetMachine; |
| } |
| |
| namespace swift { |
| class GenericSignatureBuilder; |
| class ASTContext; |
| class CodeCompletionCallbacksFactory; |
| class Decl; |
| class DeclContext; |
| class DelayedParsingCallbacks; |
| class DiagnosticConsumer; |
| class DiagnosticEngine; |
| class FileUnit; |
| class GenericEnvironment; |
| class GenericParamList; |
| class IRGenOptions; |
| class LangOptions; |
| class ModuleDecl; |
| class Parser; |
| class PersistentParserState; |
| class SerializationOptions; |
| class SILOptions; |
| class SILModule; |
| class SILParserTUState; |
| class SourceFile; |
| class SourceManager; |
| class Token; |
| class TopLevelContext; |
| struct TypeLoc; |
| class UnifiedStatsReporter; |
| |
| /// Used to optionally maintain SIL parsing context for the parser. |
| /// |
| /// When not parsing SIL, this has no overhead. |
| class SILParserState { |
| public: |
| std::unique_ptr<SILParserTUState> Impl; |
| |
| explicit SILParserState(SILModule *M); |
| ~SILParserState(); |
| }; |
| |
| /// @{ |
| |
| /// \returns true if the declaration should be verified. This can return |
| /// false to decrease the number of declarations we verify in a single |
| /// compilation. |
| bool shouldVerify(const Decl *D, const ASTContext &Context); |
| |
| /// \brief Check that the source file is well-formed, aborting and spewing |
| /// errors if not. |
| /// |
| /// "Well-formed" here means following the invariants of the AST, not that the |
| /// code written by the user makes sense. |
| void verify(SourceFile &SF); |
| void verify(Decl *D); |
| |
| /// @} |
| |
| /// \brief Parse a single buffer into the given source file. |
| /// |
| /// If the source file is the main file, stop parsing after the next |
| /// stmt-brace-item with side-effects. |
| /// |
| /// \param SF the file within the module being parsed. |
| /// |
| /// \param BufferID the buffer to parse from. |
| /// |
| /// \param[out] Done set to \c true if end of the buffer was reached. |
| /// |
| /// \param SIL if non-null, we're parsing a SIL file. |
| /// |
| /// \param PersistentState if non-null the same PersistentState object can |
| /// be used to resume parsing or parse delayed function bodies. |
| /// |
| /// \param DelayedParseCB if non-null enables delayed parsing for function |
| /// bodies. |
| /// |
| /// \return true if the parser found code with side effects. |
| bool parseIntoSourceFile(SourceFile &SF, unsigned BufferID, bool *Done, |
| SILParserState *SIL = nullptr, |
| PersistentParserState *PersistentState = nullptr, |
| DelayedParsingCallbacks *DelayedParseCB = nullptr); |
| |
| /// \brief Finish the parsing by going over the nodes that were delayed |
| /// during the first parsing pass. |
| void performDelayedParsing(DeclContext *DC, |
| PersistentParserState &PersistentState, |
| CodeCompletionCallbacksFactory *Factory); |
| |
| /// \brief Lex and return a vector of tokens for the given buffer. |
| std::vector<Token> tokenize(const LangOptions &LangOpts, |
| const SourceManager &SM, unsigned BufferID, |
| unsigned Offset = 0, unsigned EndOffset = 0, |
| bool KeepComments = true, |
| bool TokenizeInterpolatedString = true, |
| ArrayRef<Token> SplitTokens = ArrayRef<Token>()); |
| |
| /// Once parsing is complete, this walks the AST to resolve imports, record |
| /// operators, and do other top-level validation. |
| /// |
| /// \param StartElem Where to start for incremental name binding in the main |
| /// source file. |
| void performNameBinding(SourceFile &SF, unsigned StartElem = 0); |
| |
| /// Once parsing and name-binding are complete, this optionally transforms the |
| /// ASTs to add calls to external logging functions. |
| /// |
| /// \param HighPerformance True if the playground transform should omit |
| /// instrumentation that has a high runtime performance impact. |
| void performPlaygroundTransform(SourceFile &SF, bool HighPerformance); |
| |
| /// Once parsing and name-binding are complete this optionally walks the ASTs |
| /// to add calls to externally provided functions that simulate |
| /// "program counter"-like debugging events. |
| void performPCMacro(SourceFile &SF, TopLevelContext &TLC); |
| |
| /// Flags used to control type checking. |
| enum class TypeCheckingFlags : unsigned { |
| /// Whether to delay checking that benefits from having the entire |
| /// module parsed, e.g., Objective-C method override checking. |
| DelayWholeModuleChecking = 1 << 0, |
| |
| /// If set, dumps wall time taken to check each function body to |
| /// llvm::errs(). |
| DebugTimeFunctionBodies = 1 << 1, |
| |
| /// Indicates that the type checker is checking code that will be |
| /// immediately executed. |
| ForImmediateMode = 1 << 2, |
| |
| /// If set, dumps wall time taken to type check each expression to |
| /// llvm::errs(). |
| DebugTimeExpressions = 1 << 3, |
| }; |
| |
| /// Once parsing and name-binding are complete, this walks the AST to resolve |
| /// types and diagnose problems therein. |
| /// |
| /// \param StartElem Where to start for incremental type-checking in the main |
| /// source file. |
| /// |
| /// \param WarnLongFunctionBodies If non-zero, warn when a function body takes |
| /// longer than this many milliseconds to type-check |
| void performTypeChecking(SourceFile &SF, TopLevelContext &TLC, |
| OptionSet<TypeCheckingFlags> Options, |
| unsigned StartElem = 0, |
| unsigned WarnLongFunctionBodies = 0, |
| unsigned WarnLongExpressionTypeChecking = 0, |
| unsigned ExpressionTimeoutThreshold = 0); |
| |
| /// Now that we have type-checked an entire module, perform any type |
| /// checking that requires the full module, e.g., Objective-C method |
| /// override checking. |
| /// |
| /// Note that clients still perform this checking file-by-file to |
| /// provide a somewhat defined order in which diagnostics should be |
| /// emitted. |
| void performWholeModuleTypeChecking(SourceFile &SF); |
| |
| /// Incrementally type-check only added external definitions. |
| void typeCheckExternalDefinitions(SourceFile &SF); |
| |
| /// \brief Recursively validate the specified type. |
| /// |
| /// This is used when dealing with partial source files (e.g. SIL parsing, |
| /// code completion). |
| /// |
| /// \returns false on success, true on error. |
| bool performTypeLocChecking(ASTContext &Ctx, TypeLoc &T, |
| DeclContext *DC, |
| bool ProduceDiagnostics = true); |
| |
| /// \brief Recursively validate the specified type. |
| /// |
| /// This is used when dealing with partial source files (e.g. SIL parsing, |
| /// code completion). |
| /// |
| /// \returns false on success, true on error. |
| bool performTypeLocChecking(ASTContext &Ctx, TypeLoc &T, |
| bool isSILMode, |
| bool isSILType, |
| GenericEnvironment *GenericEnv, |
| DeclContext *DC, |
| bool ProduceDiagnostics = true); |
| |
| /// Expose TypeChecker's handling of GenericParamList to SIL parsing. |
| GenericEnvironment *handleSILGenericParams(ASTContext &Ctx, |
| GenericParamList *genericParams, |
| DeclContext *DC); |
| |
| /// Turn the given module into SIL IR. |
| /// |
| /// The module must contain source files. |
| /// |
| /// if \p wholeModuleCompilation is true, the optimizer assumes that the SIL |
| /// of all files in the module is present in the SILModule. |
| std::unique_ptr<SILModule> |
| performSILGeneration(ModuleDecl *M, SILOptions &options, |
| bool wholeModuleCompilation = false); |
| |
| /// Turn a source file into SIL IR. |
| /// |
| /// If \p StartElem is provided, the module is assumed to be only part of the |
| /// SourceFile, and any optimizations should take that into account. |
| std::unique_ptr<SILModule> |
| performSILGeneration(FileUnit &SF, SILOptions &options, |
| Optional<unsigned> StartElem = None); |
| |
| using ModuleOrSourceFile = PointerUnion<ModuleDecl *, SourceFile *>; |
| |
| /// Serializes a module or single source file to the given output file. |
| void serialize(ModuleOrSourceFile DC, const SerializationOptions &options, |
| const SILModule *M = nullptr); |
| |
| /// Get the CPU and subtarget feature options to use when emitting code. |
| std::tuple<llvm::TargetOptions, std::string, std::vector<std::string>> |
| getIRTargetOptions(IRGenOptions &Opts, ASTContext &Ctx); |
| |
| /// Turn the given Swift module into either LLVM IR or native code |
| /// and return the generated LLVM IR module. |
| /// If you set an outModuleHash, then you need to call performLLVM. |
| std::unique_ptr<llvm::Module> |
| performIRGeneration(IRGenOptions &Opts, ModuleDecl *M, |
| std::unique_ptr<SILModule> SILMod, |
| StringRef ModuleName, llvm::LLVMContext &LLVMContext, |
| llvm::GlobalVariable **outModuleHash = nullptr); |
| |
| /// Turn the given Swift module into either LLVM IR or native code |
| /// and return the generated LLVM IR module. |
| /// If you set an outModuleHash, then you need to call performLLVM. |
| std::unique_ptr<llvm::Module> |
| performIRGeneration(IRGenOptions &Opts, SourceFile &SF, |
| std::unique_ptr<SILModule> SILMod, |
| StringRef ModuleName, llvm::LLVMContext &LLVMContext, |
| unsigned StartElem = 0, |
| llvm::GlobalVariable **outModuleHash = nullptr); |
| |
| /// Given an already created LLVM module, construct a pass pipeline and run |
| /// the Swift LLVM Pipeline upon it. This does not cause the module to be |
| /// printed, only to be optimized. |
| void performLLVMOptimizations(IRGenOptions &Opts, llvm::Module *Module, |
| llvm::TargetMachine *TargetMachine); |
| |
| /// Wrap a serialized module inside a swift AST section in an object file. |
| void createSwiftModuleObjectFile(SILModule &SILMod, StringRef Buffer, |
| StringRef OutputPath); |
| |
| /// Turn the given LLVM module into native code and return true on error. |
| bool performLLVM(IRGenOptions &Opts, ASTContext &Ctx, |
| llvm::Module *Module, |
| UnifiedStatsReporter *Stats=nullptr); |
| |
| /// Run the LLVM passes. In multi-threaded compilation this will be done for |
| /// multiple LLVM modules in parallel. |
| /// \param Diags may be null if LLVM code gen diagnostics are not required. |
| /// \param DiagMutex may also be null if a mutex around \p Diags is not |
| /// required. |
| /// \param HashGlobal used with incremental LLVMCodeGen to know if a module |
| /// was already compiled, may be null if not desired. |
| /// \param Module LLVM module to code gen, required. |
| /// \param TargetMachine target of code gen, required. |
| /// \param effectiveLanguageVersion version of the language, effectively. |
| /// \param OutputFilename Filename for output. |
| bool performLLVM(IRGenOptions &Opts, DiagnosticEngine *Diags, |
| llvm::sys::Mutex *DiagMutex, |
| llvm::GlobalVariable *HashGlobal, |
| llvm::Module *Module, |
| llvm::TargetMachine *TargetMachine, |
| const version::Version &effectiveLanguageVersion, |
| StringRef OutputFilename, |
| UnifiedStatsReporter *Stats=nullptr); |
| |
| /// Creates a TargetMachine from the IRGen opts and AST Context. |
| std::unique_ptr<llvm::TargetMachine> |
| createTargetMachine(IRGenOptions &Opts, ASTContext &Ctx); |
| |
| /// A convenience wrapper for Parser functionality. |
| class ParserUnit { |
| public: |
| ParserUnit(SourceManager &SM, unsigned BufferID, |
| const LangOptions &LangOpts, StringRef ModuleName); |
| ParserUnit(SourceManager &SM, unsigned BufferID); |
| ParserUnit(SourceManager &SM, unsigned BufferID, |
| unsigned Offset, unsigned EndOffset); |
| |
| ~ParserUnit(); |
| |
| Parser &getParser(); |
| SourceFile &getSourceFile(); |
| DiagnosticEngine &getDiagnosticEngine(); |
| const LangOptions &getLangOptions() const; |
| |
| private: |
| struct Implementation; |
| Implementation &Impl; |
| }; |
| } // end namespace swift |
| |
| #endif // SWIFT_SUBSYSTEMS_H |