mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Generalize the existing `-playground-high-performance` flag into a set of options that control various aspects of the "playground transformation" in Sema. This commit adds the first two of those controllable parts of the transform, matching what the existing flag already controls (scope entry/exit and function arguments), but in an extensible way. The intent is for this to be a scalable way to control a larger set of upcoming options. So instead of a single flag, we represent the playground transform options as a set of well-defined choices, with a new `-playground-option` flag to individually enable or disable those options (when prefixed with "No", the corresponding option is instead disabled). Enabling an already-enabled option or disabling an already-disabled option is a no-op. For compatibility, the existing `-playground-high-performance` flag causes "expensive" transforms to be disabled, as before. We can also leave it as a useful shorthand to include or exclude new options even in the future, based on their cost. There is a comment on the old function indicating that new code should use the more general form, but it remains for clients like LLDB until they can switch over. The machinery for implementing the playground options is similar to how `Features.def` works, with a new `PlaygroundOptions.def` that defines the supported playground transform options. Each playground definition specifies the name and description, as well as whether the option is enabled by default, and whether it's also enabled in the "high performance" case. Adding a new option in the future only requires adding it to `PlaygroundOptions.def`, deciding whether it should be on or off by default, deciding whether it should also be on or off in `-playground-high-performance` mode, and checking for its presence from the appropriate places in `PlaygroundTransform.cpp`. Note that this is intended to control the types of user-visible results that the invoker of the compiler wants, from an externally detectable standpoint. Other flags, such as whether or not to use the extended form of the callbacks, remain as experimental features, since those deal with the mechanics and not the desired observed behavior. rdar://109911673
423 lines
17 KiB
C++
423 lines
17 KiB
C++
//===--- 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/AST/TBDGenRequests.h"
|
|
#include "swift/Basic/LLVM.h"
|
|
#include "swift/Basic/OptionSet.h"
|
|
#include "swift/Basic/PrimarySpecificPaths.h"
|
|
#include "swift/Basic/Version.h"
|
|
#include "swift/Frontend/Frontend.h"
|
|
#include "swift/SIL/SILDeclRef.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/StringSet.h"
|
|
#include "llvm/Support/Mutex.h"
|
|
|
|
#include <memory>
|
|
|
|
namespace llvm {
|
|
class raw_pwrite_stream;
|
|
class GlobalVariable;
|
|
class MemoryBuffer;
|
|
class Module;
|
|
class TargetOptions;
|
|
class TargetMachine;
|
|
namespace vfs {
|
|
class OutputBackend;
|
|
}
|
|
}
|
|
|
|
namespace swift {
|
|
class GenericSignatureBuilder;
|
|
class ASTContext;
|
|
class IDEInspectionCallbacksFactory;
|
|
class Decl;
|
|
class DeclContext;
|
|
class DiagnosticConsumer;
|
|
class DiagnosticEngine;
|
|
class Evaluator;
|
|
class FileUnit;
|
|
class GeneratedModule;
|
|
class GenericParamList;
|
|
class GenericSignature;
|
|
class IRGenOptions;
|
|
class LangOptions;
|
|
class SILOptions;
|
|
class ModuleDecl;
|
|
/// A opaque syntax node created by a \c SyntaxParseAction, whose contents
|
|
/// must be interpreted by the \c SyntaxParseAction which created it.
|
|
/// Requires the two low bits to be 0, so that it can be stored in an
|
|
/// \c llvm::PointerIntPair. This is in particular guaranteed for pointers
|
|
/// to C/C++ objects and for pointers that were generated by Swift and passed
|
|
/// to the compiler via a C API (in particular \c CLibParseActions ).
|
|
class Parser;
|
|
class SerializationOptions;
|
|
class SILOptions;
|
|
class SILModule;
|
|
class SILTypeResolutionContext;
|
|
class SourceFile;
|
|
enum class SourceFileKind;
|
|
class SourceManager;
|
|
struct TBDGenOptions;
|
|
class Token;
|
|
class TopLevelContext;
|
|
class Type;
|
|
class TypeCheckerOptions;
|
|
class TypeRepr;
|
|
class UnifiedStatsReporter;
|
|
|
|
namespace Lowering {
|
|
class TypeConverter;
|
|
}
|
|
|
|
namespace fine_grained_dependencies {
|
|
class SourceFileDepGraph;
|
|
}
|
|
|
|
namespace symbolgraphgen {
|
|
struct SymbolGraphOptions;
|
|
}
|
|
|
|
/// @{
|
|
|
|
/// \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);
|
|
|
|
/// 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);
|
|
|
|
/// @}
|
|
|
|
void performIDEInspectionSecondPass(SourceFile &SF,
|
|
IDEInspectionCallbacksFactory &Factory);
|
|
|
|
/// 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,
|
|
DiagnosticEngine *Diags = nullptr,
|
|
bool KeepComments = true,
|
|
bool TokenizeInterpolatedString = true,
|
|
ArrayRef<Token> SplitTokens = ArrayRef<Token>());
|
|
|
|
/// This walks the AST to resolve imports.
|
|
void performImportResolution(SourceFile &SF);
|
|
|
|
/// Once type-checking is complete, this instruments code with calls to an
|
|
/// intrinsic that record the expected values of local variables so they can
|
|
/// be compared against the results from the debugger.
|
|
void performDebuggerTestingTransform(SourceFile &SF);
|
|
|
|
/// Once type checking is complete, this optionally transforms the ASTs to
|
|
/// insert calls to external logging functions.
|
|
///
|
|
/// \param Opts The specific set of transforms that should be applied.
|
|
void performPlaygroundTransform(SourceFile &SF, PlaygroundOptionSet Opts);
|
|
|
|
/// Once type checking is complete, this optionally transforms the ASTs to
|
|
/// insert calls to external logging functions. This function is provided
|
|
/// for backward compatibility with existing code; for new code, the variant
|
|
/// that takes an `PlaygroundOptionSet` parameter should be used.
|
|
///
|
|
/// \param HighPerformance True if the playground transform should omit
|
|
/// instrumentation that has a high runtime performance impact.
|
|
///
|
|
/// This function is provided for backward compatibility with older code, and
|
|
/// is a convenience for calling `performPlaygroundTransform()` with the set
|
|
/// of options that are enabled in high-performance mode. New uses should call
|
|
/// the newer form of this function that takes a `PlaygroundOptionSet`.
|
|
void performPlaygroundTransform(SourceFile &SF, bool HighPerformance);
|
|
|
|
/// Once type checking is complete this optionally walks the ASTs to add calls
|
|
/// to externally provided functions that simulate "program counter"-like
|
|
/// debugging events. See the comment at the top of lib/Sema/PCMacro.cpp for a
|
|
/// description of the calls inserted.
|
|
void performPCMacro(SourceFile &SF);
|
|
|
|
/// Bind all 'extension' visible from \p SF to the extended nominal.
|
|
void bindExtensions(ModuleDecl &mod);
|
|
|
|
/// Once import resolution is complete, this walks the AST to resolve types
|
|
/// and diagnose problems therein.
|
|
void performTypeChecking(SourceFile &SF);
|
|
|
|
/// 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);
|
|
|
|
/// Load derivative configurations from @derivative attributes (including
|
|
/// those defined in non-primary sources).
|
|
void loadDerivativeConfigurations(SourceFile &SF);
|
|
|
|
/// Resolve the given \c TypeRepr to an interface type.
|
|
///
|
|
/// This is used when dealing with partial source files (e.g. SIL parsing,
|
|
/// code completion).
|
|
///
|
|
/// \returns A well-formed type on success, or an \c ErrorType.
|
|
Type performTypeResolution(TypeRepr *TyR, ASTContext &Ctx,
|
|
GenericSignature GenericSig,
|
|
SILTypeResolutionContext *SILContext,
|
|
DeclContext *DC, bool ProduceDiagnostics = true);
|
|
|
|
/// Expose TypeChecker's handling of GenericParamList to SIL parsing.
|
|
GenericSignature handleSILGenericParams(GenericParamList *genericParams,
|
|
DeclContext *DC);
|
|
|
|
/// Turn the given module into SIL IR.
|
|
///
|
|
/// The module must contain source files. The optimizer will assume that the
|
|
/// SIL of all files in the module is present in the SILModule.
|
|
std::unique_ptr<SILModule>
|
|
performASTLowering(ModuleDecl *M, Lowering::TypeConverter &TC,
|
|
const SILOptions &options,
|
|
const IRGenOptions *irgenOptions = nullptr);
|
|
|
|
/// Turn the given module into SIL IR.
|
|
///
|
|
/// The module must contain source files. The optimizer will assume that the
|
|
/// SIL of all files in the module is present in the SILModule.
|
|
std::unique_ptr<SILModule>
|
|
performASTLowering(CompilerInstance &CI,
|
|
llvm::SmallVector<SymbolSource, 1> Sources);
|
|
|
|
/// Turn a source file into SIL IR.
|
|
std::unique_ptr<SILModule>
|
|
performASTLowering(FileUnit &SF, Lowering::TypeConverter &TC,
|
|
const SILOptions &options,
|
|
const IRGenOptions *irgenOptions = nullptr);
|
|
|
|
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 symbolgraphgen::SymbolGraphOptions &symbolGraphOptions,
|
|
const SILModule *M = nullptr,
|
|
const fine_grained_dependencies::SourceFileDepGraph *DG = nullptr);
|
|
|
|
/// Serializes a module or single source file to the given output file and
|
|
/// returns back the file's contents as a memory buffer.
|
|
///
|
|
/// Use this if you intend to immediately load the serialized module, as that
|
|
/// will both avoid extra filesystem traffic and will ensure you read back
|
|
/// exactly what was written.
|
|
void serializeToBuffers(ModuleOrSourceFile DC,
|
|
const SerializationOptions &opts,
|
|
std::unique_ptr<llvm::MemoryBuffer> *moduleBuffer,
|
|
std::unique_ptr<llvm::MemoryBuffer> *moduleDocBuffer,
|
|
std::unique_ptr<llvm::MemoryBuffer> *moduleSourceInfoBuffer,
|
|
const SILModule *M = nullptr);
|
|
|
|
/// Get the CPU, subtarget feature options, and triple to use when emitting code.
|
|
std::tuple<llvm::TargetOptions, std::string, std::vector<std::string>,
|
|
std::string>
|
|
getIRTargetOptions(const IRGenOptions &Opts, ASTContext &Ctx);
|
|
|
|
/// Turn the given Swift module into LLVM IR and return the generated module.
|
|
/// To compile and output the generated code, call \c performLLVM.
|
|
GeneratedModule
|
|
performIRGeneration(ModuleDecl *M, const IRGenOptions &Opts,
|
|
const TBDGenOptions &TBDOpts,
|
|
std::unique_ptr<SILModule> SILMod,
|
|
StringRef ModuleName, const PrimarySpecificPaths &PSPs,
|
|
ArrayRef<std::string> parallelOutputFilenames,
|
|
llvm::GlobalVariable **outModuleHash = nullptr);
|
|
|
|
/// Turn the given Swift file into LLVM IR and return the generated module.
|
|
/// To compile and output the generated code, call \c performLLVM.
|
|
GeneratedModule
|
|
performIRGeneration(FileUnit *file, const IRGenOptions &Opts,
|
|
const TBDGenOptions &TBDOpts,
|
|
std::unique_ptr<SILModule> SILMod,
|
|
StringRef ModuleName, const PrimarySpecificPaths &PSPs,
|
|
StringRef PrivateDiscriminator,
|
|
llvm::GlobalVariable **outModuleHash = nullptr);
|
|
|
|
/// Given an already created LLVM module, construct a pass pipeline and run
|
|
/// the Swift LLVM Pipeline upon it. This will include the emission of LLVM IR
|
|
/// if requested (\out is not null).
|
|
void performLLVMOptimizations(const IRGenOptions &Opts, llvm::Module *Module,
|
|
llvm::TargetMachine *TargetMachine,
|
|
llvm::raw_pwrite_stream *out);
|
|
|
|
/// Compiles and writes the given LLVM module into an output stream in the
|
|
/// format specified in the \c IRGenOptions.
|
|
bool compileAndWriteLLVM(llvm::Module *module,
|
|
llvm::TargetMachine *targetMachine,
|
|
const IRGenOptions &opts,
|
|
UnifiedStatsReporter *stats, DiagnosticEngine &diags,
|
|
llvm::raw_pwrite_stream &out,
|
|
llvm::sys::Mutex *diagMutex = nullptr,
|
|
llvm::raw_pwrite_stream *casid = nullptr);
|
|
|
|
/// 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(const IRGenOptions &Opts,
|
|
ASTContext &Ctx,
|
|
llvm::Module *Module,
|
|
StringRef OutputFilename);
|
|
|
|
bool writeEmptyOutputFilesFor(
|
|
const ASTContext &Context,
|
|
std::vector<std::string> &ParallelOutputFilenames,
|
|
const IRGenOptions &IRGenOpts);
|
|
|
|
/// Run the LLVM passes. In multi-threaded compilation this will be done for
|
|
/// multiple LLVM modules in parallel.
|
|
/// \param Diags The Diagnostic Engine.
|
|
/// \param DiagMutex in contexts that require parallel codegen, a mutex that the
|
|
/// diagnostic engine uses to synchronize emission.
|
|
/// \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 OutputFilename Filename for output.
|
|
/// \param Backend OutputBackend for writing output.
|
|
bool performLLVM(const IRGenOptions &Opts,
|
|
DiagnosticEngine &Diags,
|
|
llvm::sys::Mutex *DiagMutex,
|
|
llvm::GlobalVariable *HashGlobal,
|
|
llvm::Module *Module,
|
|
llvm::TargetMachine *TargetMachine,
|
|
StringRef OutputFilename,
|
|
llvm::vfs::OutputBackend &Backend,
|
|
UnifiedStatsReporter *Stats);
|
|
|
|
/// Dump YAML describing all fixed-size types imported from the given module.
|
|
bool performDumpTypeInfo(const IRGenOptions &Opts, SILModule &SILMod);
|
|
|
|
/// Creates a TargetMachine from the IRGen opts and AST Context.
|
|
std::unique_ptr<llvm::TargetMachine>
|
|
createTargetMachine(const IRGenOptions &Opts, ASTContext &Ctx);
|
|
|
|
/// A convenience wrapper for Parser functionality.
|
|
class ParserUnit {
|
|
public:
|
|
ParserUnit(SourceManager &SM, SourceFileKind SFKind, unsigned BufferID,
|
|
const LangOptions &LangOpts, const TypeCheckerOptions &TyOpts,
|
|
const SILOptions &SILOpts, StringRef ModuleName);
|
|
ParserUnit(SourceManager &SM, SourceFileKind SFKind, unsigned BufferID);
|
|
ParserUnit(SourceManager &SM, SourceFileKind SFKind, unsigned BufferID,
|
|
unsigned Offset, unsigned EndOffset);
|
|
|
|
~ParserUnit();
|
|
|
|
void parse();
|
|
|
|
Parser &getParser();
|
|
SourceFile &getSourceFile();
|
|
DiagnosticEngine &getDiagnosticEngine();
|
|
const LangOptions &getLangOptions() const;
|
|
|
|
private:
|
|
struct Implementation;
|
|
Implementation &Impl;
|
|
};
|
|
|
|
/// Register AST-level request functions with the evaluator.
|
|
///
|
|
/// The ASTContext will automatically call these upon construction.
|
|
void registerAccessRequestFunctions(Evaluator &evaluator);
|
|
|
|
/// Register AST-level request functions with the evaluator.
|
|
///
|
|
/// The ASTContext will automatically call these upon construction.
|
|
void registerNameLookupRequestFunctions(Evaluator &evaluator);
|
|
|
|
/// Register Parse-level request functions with the evaluator.
|
|
///
|
|
/// Clients that form an ASTContext and will perform any parsing queries
|
|
/// using Parse-level logic should call these functions after forming the
|
|
/// ASTContext.
|
|
void registerParseRequestFunctions(Evaluator &evaluator);
|
|
|
|
/// Register Sema-level request functions with the evaluator.
|
|
///
|
|
/// Clients that form an ASTContext and will perform any semantic queries
|
|
/// using Sema-level logic should call these functions after forming the
|
|
/// ASTContext.
|
|
void registerTypeCheckerRequestFunctions(Evaluator &evaluator);
|
|
|
|
/// Register SILGen-level request functions with the evaluator.
|
|
///
|
|
/// Clients that form an ASTContext and will perform any SIL generation
|
|
/// should call this functions after forming the ASTContext.
|
|
void registerSILGenRequestFunctions(Evaluator &evaluator);
|
|
|
|
/// Register SILOptimizer-level request functions with the evaluator.
|
|
///
|
|
/// Clients that form an ASTContext and will perform any SIL optimization
|
|
/// should call this functions after forming the ASTContext.
|
|
void registerSILOptimizerRequestFunctions(Evaluator &evaluator);
|
|
|
|
/// Register TBDGen-level request functions with the evaluator.
|
|
///
|
|
/// Clients that form an ASTContext and will perform any TBD generation
|
|
/// should call this functions after forming the ASTContext.
|
|
void registerTBDGenRequestFunctions(Evaluator &evaluator);
|
|
|
|
/// Register IRGen-level request functions with the evaluator.
|
|
///
|
|
/// Clients that form an ASTContext and will perform any IR generation
|
|
/// should call this functions after forming the ASTContext.
|
|
void registerIRGenRequestFunctions(Evaluator &evaluator);
|
|
|
|
/// Register IDE-level request functions with the evaluator.
|
|
///
|
|
/// The ASTContext will automatically call these upon construction.
|
|
void registerIDERequestFunctions(Evaluator &evaluator);
|
|
|
|
/// Register type check request functions for IDE's usage with the evaluator.
|
|
///
|
|
/// The ASTContext will automatically call these upon construction.
|
|
/// Calling registerIDERequestFunctions will invoke this function as well.
|
|
void registerIDETypeCheckRequestFunctions(Evaluator &evaluator);
|
|
|
|
/// Register clang importer request functions with the evaluator.
|
|
///
|
|
/// Clients that form an ASTContext and import any Clang APIs should call this function
|
|
/// after forming the ASTContext.
|
|
void registerClangImporterRequestFunctions(Evaluator &evaluator);
|
|
|
|
/// Register constant value extraction request functons with the evaluator.
|
|
void registerConstExtractRequestFunctions(Evaluator &evaluator);
|
|
|
|
/// Register SILOptimizer passes necessary for IRGen.
|
|
void registerIRGenSILTransforms(ASTContext &ctx);
|
|
|
|
} // end namespace swift
|
|
|
|
#endif // SWIFT_SUBSYSTEMS_H
|