//===--- sil_opt_main.cpp - SIL Optimization Driver -----------------------===// // // 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 is a tool for reading sil files and running sil passes on them. The // targeted usecase is debugging and testing SIL passes. // //===----------------------------------------------------------------------===// #include "swift/Subsystems.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/SILOptions.h" #include "swift/Basic/FileTypes.h" #include "swift/Basic/LLVMInitialize.h" #include "swift/Basic/InitializeSwiftModules.h" #include "swift/Basic/QuotedString.h" #include "swift/Frontend/DiagnosticVerifier.h" #include "swift/Frontend/Frontend.h" #include "swift/Frontend/PrintingDiagnosticConsumer.h" #include "swift/SIL/SILRemarkStreamer.h" #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/PassManager.h" #include "swift/Serialization/SerializedModuleLoader.h" #include "swift/Serialization/SerializedSILLoader.h" #include "swift/Serialization/SerializationOptions.h" #include "swift/SymbolGraphGen/SymbolGraphOptions.h" #include "swift/IRGen/IRGenPublic.h" #include "swift/IRGen/IRGenSILPasses.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/YAMLTraits.h" #include using namespace swift; namespace cl = llvm::cl; namespace { enum class OptGroup { Unknown, Diagnostics, OnonePerformance, Performance, Lowering }; llvm::Optional toOptionalBool(llvm::cl::boolOrDefault defaultable) { switch (defaultable) { case llvm::cl::BOU_TRUE: return true; case llvm::cl::BOU_FALSE: return false; case llvm::cl::BOU_UNSET: return llvm::None; } llvm_unreachable("Bad case for llvm::cl::boolOrDefault!"); } enum class EnforceExclusivityMode { Unchecked, // static only Checked, // static and dynamic DynamicOnly, None, }; } // end anonymous namespace namespace llvm { inline raw_ostream & operator<<(raw_ostream &os, const llvm::Optional option) { if (option) { switch (*option) { case CopyPropagationOption::Off: os << "off"; break; case CopyPropagationOption::RequestedPassesOnly: os << "requested-passes-only"; break; case CopyPropagationOption::On: os << "on"; break; } } else { os << ""; } return os; } namespace cl { template <> class parser> : public basic_parser> { public: parser(Option &O) : basic_parser>(O) {} // parse - Return true on error. bool parse(Option &O, StringRef ArgName, StringRef Arg, llvm::Optional &Value) { if (Arg == "" || Arg == "true" || Arg == "TRUE" || Arg == "True" || Arg == "1") { Value = CopyPropagationOption::On; return false; } if (Arg == "false" || Arg == "FALSE" || Arg == "False" || Arg == "0") { Value = CopyPropagationOption::Off; return false; } if (Arg == "requested-passes-only" || Arg == "REQUESTED-PASSES-ONLY" || Arg == "Requested-Passes-Only") { Value = CopyPropagationOption::RequestedPassesOnly; return false; } return O.error("'" + Arg + "' is invalid for CopyPropagationOption! Try true, false, " "or requested-passes-only."); } void initialize() {} enum ValueExpected getValueExpectedFlagDefault() const { return ValueOptional; } StringRef getValueName() const override { return "CopyPropagationOption"; } // Instantiate the macro PRINT_OPT_DIFF of llvm_project's CommandLine.cpp at // Optional. void printOptionDiff(const Option &O, llvm::Optional V, OptionValue> D, size_t GlobalWidth) const { size_t MaxOptWidth = 8; printOptionName(O, GlobalWidth); std::string Str; { raw_string_ostream SS(Str); SS << V; } outs() << "= " << Str; size_t NumSpaces = MaxOptWidth > Str.size() ? MaxOptWidth - Str.size() : 0; outs().indent(NumSpaces) << " (default:"; if (D.hasValue()) outs() << D.getValue(); else outs() << "*no default*"; outs() << ")\n"; } }; } // end namespace cl } // end namespace llvm struct SILOptOptions { llvm::cl::opt InputFilename = llvm::cl::opt(llvm::cl::desc("input file"), llvm::cl::init("-"), llvm::cl::Positional); llvm::cl::opt OutputFilename = llvm::cl::opt("o", llvm::cl::desc("output filename")); llvm::cl::list ImportPaths = llvm::cl::list("I", llvm::cl::desc("add a directory to the import search path")); llvm::cl::list FrameworkPaths = llvm::cl::list("F", llvm::cl::desc("add a directory to the framework search path")); llvm::cl::list VFSOverlays = llvm::cl::list("vfsoverlay", llvm::cl::desc("add a VFS overlay")); llvm::cl::opt ModuleName = llvm::cl::opt("module-name", llvm::cl::desc("The name of the module if processing" " a module. Necessary for processing " "stdin.")); llvm::cl::opt EnableLibraryEvolution = llvm::cl::opt("enable-library-evolution", llvm::cl::desc("Compile the module to export resilient " "interfaces for all public declarations by " "default")); llvm::cl::opt StrictImplicitModuleContext = llvm::cl::opt("strict-implicit-module-context", llvm::cl::desc("Enable the strict forwarding of compilation " "context to downstream implicit module dependencies")); llvm::cl::opt DisableSILOwnershipVerifier = llvm::cl::opt( "disable = llvm::cl::opt DisableSILOwnershipVerifier(-sil-ownership-verifier", llvm::cl::desc( "Do not verify SIL ownership invariants during SIL verification")); llvm::cl::opt EnableSILOpaqueValues = llvm::cl::opt("enable-sil-opaque-values", llvm::cl::desc("Compile the module with sil-opaque-values enabled.")); llvm::cl::opt EnableOSSACompleteLifetimes = llvm::cl::opt("enable-ossa-complete-lifetimes", llvm::cl::desc("Compile the module with sil-opaque-values enabled.")); llvm::cl::opt EnableObjCInterop = llvm::cl::opt("enable-objc-interop", llvm::cl::desc("Enable Objective-C interoperability.")); llvm::cl::opt DisableObjCInterop = llvm::cl::opt("disable-objc-interop", llvm::cl::desc("Disable Objective-C interoperability.")); llvm::cl::list ExperimentalFeatures = llvm::cl::list("enable-experimental-feature", llvm::cl::desc("Enable the given experimental feature.")); llvm::cl::opt EnableExperimentalConcurrency = llvm::cl::opt("enable-experimental-concurrency", llvm::cl::desc("Enable experimental concurrency model.")); llvm::cl::opt EnableLexicalLifetimes = llvm::cl::opt( "enable-lexical-lifetimes", llvm::cl::init(llvm::cl::BOU_UNSET), llvm::cl::desc("Enable lexical lifetimes. Mutually exclusive with " "enable-lexical-borrow-scopes and " "disable-lexical-lifetimes.")); llvm::cl::opt EnableLexicalBorrowScopes = llvm::cl::opt("enable-lexical-borrow-scopes", llvm::cl::init(llvm::cl::BOU_UNSET), llvm::cl::desc("Enable lexical borrow scopes.")); llvm::cl::opt EnableExperimentalMoveOnly = llvm::cl::opt( "enable-experimental-move-only", llvm::cl::init(llvm::cl::BOU_UNSET), llvm::cl::desc("Enable experimental move-only semantics.")); llvm::cl::opt EnablePackMetadataStackPromotion = llvm::cl::opt( "enable-pack-metadata-stack-promotion", llvm::cl::init(true), llvm::cl::desc( "Whether to skip heapifying stack metadata packs when possible.")); llvm::cl::opt EnableExperimentalDistributed = llvm::cl::opt("enable-experimental-distributed", llvm::cl::desc("Enable experimental distributed actors.")); llvm::cl::opt VerifyExclusivity = llvm::cl::opt("enable-verify-exclusivity", llvm::cl::desc("Verify the access markers used to enforce exclusivity.")); llvm::cl::opt EnableSpeculativeDevirtualization = llvm::cl::opt("enable-spec-devirt", llvm::cl::desc("Enable Speculative Devirtualization pass.")); llvm::cl::opt EnableAsyncDemotion = llvm::cl::opt("enable-async-demotion", llvm::cl::desc("Enables an optimization pass to demote async functions.")); llvm::cl::opt EnableMoveInoutStackProtection = llvm::cl::opt("enable-move-inout-stack-protector", llvm::cl::desc("Enable the stack protector by moving values to temporaries.")); llvm::cl::opt EnableOSSAModules = llvm::cl::opt( "enable-ossa-modules", llvm::cl::desc("Do we always serialize SIL in OSSA form? If " "this is disabled we do not serialize in OSSA " "form when optimizing.")); cl::opt EnforceExclusivity = cl::opt( "enforce-exclusivity", cl::desc("Enforce law of exclusivity " "(and support memory access markers)."), cl::init(EnforceExclusivityMode::Checked), cl::values(clEnumValN(EnforceExclusivityMode::Unchecked, "unchecked", "Static checking only."), clEnumValN(EnforceExclusivityMode::Checked, "checked", "Static and dynamic checking."), clEnumValN(EnforceExclusivityMode::DynamicOnly, "dynamic-only", "Dynamic checking only."), clEnumValN(EnforceExclusivityMode::None, "none", "No exclusivity checking."))); llvm::cl::opt ResourceDir = llvm::cl::opt("resource-dir", llvm::cl::desc("The directory that holds the compiler resource files")); llvm::cl::opt SDKPath = llvm::cl::opt("sdk", llvm::cl::desc("The path to the SDK for use with the clang " "importer."), llvm::cl::init("")); llvm::cl::opt Target = llvm::cl::opt("target", llvm::cl::desc("target triple"), llvm::cl::init(llvm::sys::getDefaultTargetTriple())); // This primarily determines semantics of debug information. The compiler does // not directly expose a "preserve debug info mode". It is derived from the // optimization level. At -Onone, all debug info must be preserved. At higher // levels, debug info cannot change the compiler output. // // Diagnostics should be "equivalent" at all levels. For example, programs that // compile at -Onone should compile at -O. However, it is difficult to guarantee // identical diagnostic output given the changes in SIL caused by debug info // preservation. llvm::cl::opt OptModeFlag = llvm::cl::opt( "opt-mode", llvm::cl::desc("optimization mode"), llvm::cl::values(clEnumValN(OptimizationMode::NoOptimization, "none", "preserve debug info"), clEnumValN(OptimizationMode::ForSize, "size", "ignore debug info, reduce size"), clEnumValN(OptimizationMode::ForSpeed, "speed", "ignore debug info, reduce runtime")), llvm::cl::init(OptimizationMode::NotSet)); llvm::cl::opt IRGenDebugInfoLevelArg = llvm::cl::opt( "irgen-debuginfo-level", llvm::cl::desc("IRGen debug info level"), llvm::cl::values(clEnumValN(IRGenDebugInfoLevel::None, "none", "No debug info"), clEnumValN(IRGenDebugInfoLevel::LineTables, "line-tables", "Line tables only"), clEnumValN(IRGenDebugInfoLevel::ASTTypes, "ast-types", "Line tables + AST type references"), clEnumValN(IRGenDebugInfoLevel::DwarfTypes, "dwarf-types", "Line tables + AST type refs + Dwarf types")), llvm::cl::init(IRGenDebugInfoLevel::ASTTypes)); llvm::cl::opt OptimizationGroup = llvm::cl::opt( llvm::cl::desc("Predefined optimization groups:"), llvm::cl::values( clEnumValN(OptGroup::Diagnostics, "diagnostics", "Run diagnostic passes"), clEnumValN(OptGroup::Performance, "O", "Run performance passes"), clEnumValN(OptGroup::OnonePerformance, "Onone-performance", "Run Onone perf passes"), clEnumValN(OptGroup::Lowering, "lowering", "Run lowering passes")), llvm::cl::init(OptGroup::Unknown)); llvm::cl::list Passes = llvm::cl::list(llvm::cl::desc("Passes:"), llvm::cl::values( #define PASS(ID, TAG, NAME) clEnumValN(PassKind::ID, TAG, NAME), #include "swift/SILOptimizer/PassManager/Passes.def" clEnumValN(0, "", ""))); llvm::cl::opt PrintStats = llvm::cl::opt("print-stats", llvm::cl::desc("Print various statistics")); llvm::cl::opt VerifyMode = llvm::cl::opt("verify", llvm::cl::desc("verify diagnostics against expected-" "{error|warning|note} annotations")); llvm::cl::opt AssertConfId = llvm::cl::opt("assert-conf-id", llvm::cl::Hidden, llvm::cl::init(0)); llvm::cl::opt SILInlineThreshold = llvm::cl::opt("sil-inline-threshold", llvm::cl::Hidden, llvm::cl::init(-1)); // Legacy option name still in use. The frontend uses -sil-verify-all. llvm::cl::opt EnableSILVerifyAll = llvm::cl::opt("enable-sil-verify-all", llvm::cl::Hidden, llvm::cl::init(true), llvm::cl::desc("Run sil verifications after every pass.")); llvm::cl::opt SILVerifyAll = llvm::cl::opt("sil-verify-all", llvm::cl::Hidden, llvm::cl::init(true), llvm::cl::desc("Run sil verifications after every pass.")); llvm::cl::opt SILVerifyNone = llvm::cl::opt("sil-verify-none", llvm::cl::Hidden, llvm::cl::init(false), llvm::cl::desc("Completely disable SIL verification")); /// Customize the default behavior llvm::cl::opt EnableASTVerifier = llvm::cl::opt( "enable-ast-verifier", llvm::cl::Hidden, llvm::cl::init(false), llvm::cl::desc("Override the default behavior and Enable the ASTVerifier")); llvm::cl::opt DisableASTVerifier = llvm::cl::opt( "disable-ast-verifier", llvm::cl::Hidden, llvm::cl::init(false), llvm::cl::desc( "Override the default behavior and force disable the ASTVerifier")); llvm::cl::opt RemoveRuntimeAsserts = llvm::cl::opt("remove-runtime-asserts", llvm::cl::Hidden, llvm::cl::init(false), llvm::cl::desc("Remove runtime assertions (cond_fail).")); llvm::cl::opt EmitVerboseSIL = llvm::cl::opt("emit-verbose-sil", llvm::cl::desc("Emit locations during sil emission.")); llvm::cl::opt EmitSIB = llvm::cl::opt("emit-sib", llvm::cl::desc("Emit serialized AST + SIL file(s)")); llvm::cl::opt Serialize = llvm::cl::opt("serialize", llvm::cl::desc("Emit serialized AST + SIL file(s)")); llvm::cl::opt ModuleCachePath = llvm::cl::opt("module-cache-path", llvm::cl::desc("Clang module cache path")); llvm::cl::opt EmitSortedSIL = llvm::cl::opt("emit-sorted-sil", llvm::cl::Hidden, llvm::cl::init(false), llvm::cl::desc("Sort Functions, VTables, Globals, " "WitnessTables by name to ease diffing.")); llvm::cl::opt DisableASTDump = llvm::cl::opt("sil-disable-ast-dump", llvm::cl::Hidden, llvm::cl::init(false), llvm::cl::desc("Do not dump AST.")); llvm::cl::opt PerformWMO = llvm::cl::opt("wmo", llvm::cl::desc("Enable whole-module optimizations")); llvm::cl::opt EnableExperimentalStaticAssert = llvm::cl::opt( "enable-experimental-static-assert", llvm::cl::Hidden, llvm::cl::init(false), llvm::cl::desc("Enable experimental #assert")); llvm::cl::opt EnableExperimentalDifferentiableProgramming = llvm::cl::opt( "enable-experimental-differentiable-programming", llvm::cl::Hidden, llvm::cl::init(false), llvm::cl::desc("Enable experimental differentiable programming")); cl::opt PassRemarksPassed = cl::opt( "sil-remarks", cl::value_desc("pattern"), cl::desc( "Enable performed optimization remarks from passes whose name match " "the given regular expression"), cl::Hidden); cl::opt PassRemarksMissed = cl::opt( "sil-remarks-missed", cl::value_desc("pattern"), cl::desc("Enable missed optimization remarks from passes whose name match " "the given regular expression"), cl::Hidden); cl::opt RemarksFilename = cl::opt("save-optimization-record-path", cl::desc("YAML output filename for pass remarks"), cl::value_desc("filename")); cl::opt RemarksPasses = cl::opt( "save-optimization-record-passes", cl::desc("Only include passes which match a specified regular expression " "in the generated optimization record (by default, include all " "passes)"), cl::value_desc("regex")); // sil-opt doesn't have the equivalent of -save-optimization-record=. // Instead, use -save-optimization-record-format . cl::opt RemarksFormat = cl::opt( "save-optimization-record-format", cl::desc("The format used for serializing remarks (default: YAML)"), cl::value_desc("format"), cl::init("yaml")); // Strict Concurrency llvm::cl::opt StrictConcurrencyLevel = llvm::cl::opt( "strict-concurrency", cl::desc("strict concurrency level"), llvm::cl::values(clEnumValN(StrictConcurrency::Complete, "complete", "Enable complete strict concurrency"), clEnumValN(StrictConcurrency::Targeted, "targeted", "Enable targeted strict concurrency"), clEnumValN(StrictConcurrency::Minimal, "minimal", "Enable minimal strict concurrency"))); llvm::cl::opt EnableCxxInterop = llvm::cl::opt("enable-experimental-cxx-interop", llvm::cl::desc("Enable C++ interop."), llvm::cl::init(false)); llvm::cl::opt IgnoreAlwaysInline = llvm::cl::opt("ignore-always-inline", llvm::cl::desc("Ignore [always_inline] attribute."), llvm::cl::init(false)); using CPStateOpt = llvm::cl::opt, /*ExternalStorage*/ false, llvm::cl::parser>>; CPStateOpt CopyPropagationState = CPStateOpt( "enable-copy-propagation", llvm::cl::desc("Whether to run the copy propagation pass: " "'true', 'false', or 'requested-passes-only'.")); llvm::cl::opt BypassResilienceChecks = llvm::cl::opt( "bypass-resilience-checks", llvm::cl::desc("Ignore all checks for module resilience.")); llvm::cl::opt DebugDiagnosticNames = llvm::cl::opt( "debug-diagnostic-names", llvm::cl::desc("Include diagnostic names when printing")); llvm::cl::opt UnavailableDeclOptimization = llvm::cl::opt( "unavailable-decl-optimization", llvm::cl::desc("Optimization mode for unavailable declarations"), llvm::cl::values( clEnumValN(swift::UnavailableDeclOptimization::None, "none", "Don't optimize unavailable decls"), clEnumValN(swift::UnavailableDeclOptimization::Stub, "stub", "Lower unavailable functions to stubs"), clEnumValN( swift::UnavailableDeclOptimization::Complete, "complete", "Eliminate unavailable decls from lowered SIL/IR")), llvm::cl::init(swift::UnavailableDeclOptimization::None)); llvm::cl::list ClangXCC = llvm::cl::list( "Xcc", llvm::cl::desc("option to pass to clang")); }; /// Regular expression corresponding to the value given in one of the /// -pass-remarks* command line flags. Passes whose name matches this regexp /// will emit a diagnostic. static std::shared_ptr createOptRemarkRegex(StringRef Val) { std::shared_ptr Pattern = std::make_shared(Val); if (!Val.empty()) { std::string RegexError; if (!Pattern->isValid(RegexError)) llvm::report_fatal_error("Invalid regular expression '" + Val + "' in -sil-remarks: " + RegexError, false); } return Pattern; } static void runCommandLineSelectedPasses(SILModule *Module, irgen::IRGenModule *IRGenMod, const SILOptOptions &options) { const SILOptions &opts = Module->getOptions(); // If a specific pass was requested with -opt-mode=None, run the pass as a // mandatory pass. bool isMandatory = opts.OptMode == OptimizationMode::NoOptimization; executePassPipelinePlan( Module, SILPassPipelinePlan::getPassPipelineForKinds(opts, options.Passes), isMandatory, IRGenMod); if (Module->getOptions().VerifyAll) Module->verify(); } namespace { using ASTVerifierOverrideKind = LangOptions::ASTVerifierOverrideKind; } // end anonymous namespace static llvm::Optional getASTOverrideKind(const SILOptOptions &options) { assert(!(options.EnableASTVerifier && options.DisableASTVerifier) && "Can only set one of EnableASTVerifier/DisableASTVerifier?!"); if (options.EnableASTVerifier) return ASTVerifierOverrideKind::EnableVerifier; if (options.DisableASTVerifier) return ASTVerifierOverrideKind::DisableVerifier; return llvm::None; } int sil_opt_main(ArrayRef argv, void *MainAddr) { INITIALIZE_LLVM(); llvm::setBugReportMsg(SWIFT_CRASH_BUG_REPORT_MESSAGE "\n"); llvm::EnablePrettyStackTraceOnSigInfoForThisThread(); SILOptOptions options; llvm::cl::ParseCommandLineOptions(argv.size(), argv.data(), "Swift SIL optimizer\n"); if (options.PrintStats) llvm::EnableStatistics(); CompilerInvocation Invocation; Invocation.setMainExecutablePath( llvm::sys::fs::getMainExecutable(argv[0], MainAddr)); // Give the context the list of search paths to use for modules. Invocation.setImportSearchPaths(options.ImportPaths); std::vector FramePaths; for (const auto &path : options.FrameworkPaths) { FramePaths.push_back({path, /*isSystem=*/false}); } Invocation.setFrameworkSearchPaths(FramePaths); Invocation.setVFSOverlays(options.VFSOverlays); // Set the SDK path and target if given. if (options.SDKPath.getNumOccurrences() == 0) { const char *SDKROOT = getenv("SDKROOT"); if (SDKROOT) options.SDKPath = SDKROOT; } if (!options.SDKPath.empty()) Invocation.setSDKPath(options.SDKPath); if (!options.Target.empty()) Invocation.setTargetTriple(options.Target); if (!options.ResourceDir.empty()) Invocation.setRuntimeResourcePath(options.ResourceDir); Invocation.getFrontendOptions().EnableLibraryEvolution = options.EnableLibraryEvolution; Invocation.getFrontendOptions().StrictImplicitModuleContext = options.StrictImplicitModuleContext; // Set the module cache path. If not passed in we use the default swift module // cache. Invocation.getClangImporterOptions().ModuleCachePath = options.ModuleCachePath; Invocation.setParseStdlib(); Invocation.getLangOptions().DisableAvailabilityChecking = true; Invocation.getLangOptions().EnableAccessControl = false; Invocation.getLangOptions().EnableObjCAttrRequiresFoundation = false; Invocation.getLangOptions().EnableDeserializationSafety = false; if (auto overrideKind = getASTOverrideKind(options)) { Invocation.getLangOptions().ASTVerifierOverride = *overrideKind; } Invocation.getLangOptions().EnableExperimentalConcurrency = options.EnableExperimentalConcurrency; llvm::Optional enableExperimentalMoveOnly = toOptionalBool(options.EnableExperimentalMoveOnly); if (enableExperimentalMoveOnly && *enableExperimentalMoveOnly) { // FIXME: drop addition of Feature::MoveOnly once its queries are gone. Invocation.getLangOptions().enableFeature(Feature::MoveOnly); Invocation.getLangOptions().enableFeature(Feature::NoImplicitCopy); Invocation.getLangOptions().enableFeature( Feature::OldOwnershipOperatorSpellings); } Invocation.getLangOptions().BypassResilienceChecks = options.BypassResilienceChecks; Invocation.getDiagnosticOptions().PrintDiagnosticNames = options.DebugDiagnosticNames; for (auto &featureName : options.ExperimentalFeatures) { if (auto feature = getExperimentalFeature(featureName)) { Invocation.getLangOptions().enableFeature(*feature); } else { llvm::errs() << "error: unknown feature " << QuotedString(featureName) << "\n"; exit(-1); } } Invocation.getLangOptions().EnableObjCInterop = options.EnableObjCInterop ? true : options.DisableObjCInterop ? false : llvm::Triple(options.Target).isOSDarwin(); Invocation.getLangOptions().enableFeature(Feature::LayoutPrespecialization); Invocation.getLangOptions().OptimizationRemarkPassedPattern = createOptRemarkRegex(options.PassRemarksPassed); Invocation.getLangOptions().OptimizationRemarkMissedPattern = createOptRemarkRegex(options.PassRemarksMissed); if (options.EnableExperimentalStaticAssert) Invocation.getLangOptions().enableFeature(Feature::StaticAssert); if (options.EnableExperimentalDifferentiableProgramming) { Invocation.getLangOptions().enableFeature( Feature::DifferentiableProgramming); } Invocation.getLangOptions().EnableCXXInterop = options.EnableCxxInterop; Invocation.getLangOptions().UnavailableDeclOptimizationMode = options.UnavailableDeclOptimization; if (options.StrictConcurrencyLevel.hasArgStr()) Invocation.getLangOptions().StrictConcurrencyLevel = options.StrictConcurrencyLevel; Invocation.getDiagnosticOptions().VerifyMode = options.VerifyMode ? DiagnosticOptions::Verify : DiagnosticOptions::NoVerify; ClangImporterOptions &clangImporterOptions = Invocation.getClangImporterOptions(); for (const auto &xcc : options.ClangXCC) { clangImporterOptions.ExtraArgs.push_back(xcc); } // Setup the SIL Options. SILOptions &SILOpts = Invocation.getSILOptions(); SILOpts.InlineThreshold = options.SILInlineThreshold; SILOpts.VerifyAll = options.SILVerifyAll || options.EnableSILVerifyAll; SILOpts.VerifyNone = options.SILVerifyNone; SILOpts.RemoveRuntimeAsserts = options.RemoveRuntimeAsserts; SILOpts.AssertConfig = options.AssertConfId; SILOpts.VerifySILOwnership = !options.DisableSILOwnershipVerifier; SILOpts.OptRecordFile = options.RemarksFilename; SILOpts.OptRecordPasses = options.RemarksPasses; SILOpts.checkSILModuleLeaks = true; SILOpts.EnableStackProtection = true; SILOpts.EnableMoveInoutStackProtection = options.EnableMoveInoutStackProtection; SILOpts.VerifyExclusivity = options.VerifyExclusivity; if (options.EnforceExclusivity.getNumOccurrences() != 0) { switch (options.EnforceExclusivity) { case EnforceExclusivityMode::Unchecked: // This option is analogous to the -Ounchecked optimization setting. // It will disable dynamic checking but still diagnose statically. SILOpts.EnforceExclusivityStatic = true; SILOpts.EnforceExclusivityDynamic = false; break; case EnforceExclusivityMode::Checked: SILOpts.EnforceExclusivityStatic = true; SILOpts.EnforceExclusivityDynamic = true; break; case EnforceExclusivityMode::DynamicOnly: // This option is intended for staging purposes. The intent is that // it will eventually be removed. SILOpts.EnforceExclusivityStatic = false; SILOpts.EnforceExclusivityDynamic = true; break; case EnforceExclusivityMode::None: // This option is for staging purposes. SILOpts.EnforceExclusivityStatic = false; SILOpts.EnforceExclusivityDynamic = false; break; } } SILOpts.EmitVerboseSIL |= options.EmitVerboseSIL; SILOpts.EmitSortedSIL |= options.EmitSortedSIL; SILOpts.EnableSpeculativeDevirtualization = options.EnableSpeculativeDevirtualization; SILOpts.EnableAsyncDemotion = options.EnableAsyncDemotion; SILOpts.IgnoreAlwaysInline = options.IgnoreAlwaysInline; SILOpts.EnableOSSAModules = options.EnableOSSAModules; SILOpts.EnableSILOpaqueValues = options.EnableSILOpaqueValues; SILOpts.OSSACompleteLifetimes = options.EnableOSSACompleteLifetimes; if (options.CopyPropagationState) { SILOpts.CopyPropagation = *options.CopyPropagationState; } // Unless overridden below, enabling copy propagation means enabling lexical // lifetimes. if (SILOpts.CopyPropagation == CopyPropagationOption::On) SILOpts.LexicalLifetimes = LexicalLifetimesOption::On; // Unless overridden below, disable copy propagation means disabling lexical // lifetimes. if (SILOpts.CopyPropagation == CopyPropagationOption::Off) SILOpts.LexicalLifetimes = LexicalLifetimesOption::DiagnosticMarkersOnly; llvm::Optional enableLexicalLifetimes = toOptionalBool(options.EnableLexicalLifetimes); llvm::Optional enableLexicalBorrowScopes = toOptionalBool(options.EnableLexicalBorrowScopes); // Enable lexical lifetimes if it is set or if experimental move only is // enabled. This is because move only depends on lexical lifetimes being // enabled and it saved some typing ; ). bool specifiedLexicalLifetimesEnabled = enableExperimentalMoveOnly && *enableExperimentalMoveOnly && enableLexicalLifetimes && *enableLexicalLifetimes; if (specifiedLexicalLifetimesEnabled && enableLexicalBorrowScopes && !*enableLexicalBorrowScopes) { fprintf( stderr, "Error! Cannot specify both -enable-lexical-borrow-scopes=false and " "either -enable-lexical-lifetimes or -enable-experimental-move-only."); exit(-1); } if (enableLexicalLifetimes) SILOpts.LexicalLifetimes = *enableLexicalLifetimes ? LexicalLifetimesOption::On : LexicalLifetimesOption::DiagnosticMarkersOnly; if (enableLexicalBorrowScopes) SILOpts.LexicalLifetimes = *enableLexicalBorrowScopes ? LexicalLifetimesOption::DiagnosticMarkersOnly : LexicalLifetimesOption::Off; SILOpts.EnablePackMetadataStackPromotion = options.EnablePackMetadataStackPromotion; if (options.OptModeFlag == OptimizationMode::NotSet) { if (options.OptimizationGroup == OptGroup::Diagnostics) SILOpts.OptMode = OptimizationMode::NoOptimization; else SILOpts.OptMode = OptimizationMode::ForSpeed; } else { SILOpts.OptMode = options.OptModeFlag; } auto &IRGenOpts = Invocation.getIRGenOptions(); if (options.OptModeFlag == OptimizationMode::NotSet) { if (options.OptimizationGroup == OptGroup::Diagnostics) IRGenOpts.OptMode = OptimizationMode::NoOptimization; else IRGenOpts.OptMode = OptimizationMode::ForSpeed; } else { IRGenOpts.OptMode = options.OptModeFlag; } IRGenOpts.DebugInfoLevel = options.IRGenDebugInfoLevelArg; // Note: SILOpts, LangOpts, and IRGenOpts must be set before the // CompilerInstance is initializer below based on Invocation. serialization::ExtendedValidationInfo extendedInfo; llvm::ErrorOr> FileBufOrErr = Invocation.setUpInputForSILTool(options.InputFilename, options.ModuleName, /*alwaysSetModuleToMain*/ false, /*bePrimary*/ !options.PerformWMO, extendedInfo); if (!FileBufOrErr) { fprintf(stderr, "Error! Failed to open file: %s\n", options.InputFilename.c_str()); exit(-1); } CompilerInstance CI; PrintingDiagnosticConsumer PrintDiags; CI.addDiagnosticConsumer(&PrintDiags); if (options.VerifyMode) PrintDiags.setSuppressOutput(true); struct FinishDiagProcessingCheckRAII { bool CalledFinishDiagProcessing = false; ~FinishDiagProcessingCheckRAII() { assert(CalledFinishDiagProcessing && "returned from the function " "without calling finishDiagProcessing"); } } FinishDiagProcessingCheckRAII; auto finishDiagProcessing = [&](int retValue) -> int { FinishDiagProcessingCheckRAII.CalledFinishDiagProcessing = true; PrintDiags.setSuppressOutput(false); bool diagnosticsError = CI.getDiags().finishProcessing(); // If the verifier is enabled and did not encounter any verification errors, // return 0 even if the compile failed. This behavior isn't ideal, but large // parts of the test suite are reliant on it. if (options.VerifyMode && !diagnosticsError) { return 0; } return retValue ? retValue : diagnosticsError; }; std::string InstanceSetupError; if (CI.setup(Invocation, InstanceSetupError)) { llvm::errs() << InstanceSetupError << '\n'; return finishDiagProcessing(1); } CI.performSema(); // If parsing produced an error, don't run any passes. bool HadError = CI.getASTContext().hadError(); if (HadError) return finishDiagProcessing(1); auto *mod = CI.getMainModule(); assert(mod->getFiles().size() == 1); std::unique_ptr SILMod; if (options.PerformWMO) { SILMod = performASTLowering(mod, CI.getSILTypes(), CI.getSILOptions()); } else { SILMod = performASTLowering(*mod->getFiles()[0], CI.getSILTypes(), CI.getSILOptions()); } SILMod->setSerializeSILAction([]{}); if (!options.RemarksFilename.empty()) { llvm::Expected formatOrErr = llvm::remarks::parseFormat(options.RemarksFormat); if (llvm::Error E = formatOrErr.takeError()) { CI.getDiags().diagnose(SourceLoc(), diag::error_creating_remark_serializer, toString(std::move(E))); HadError = true; SILOpts.OptRecordFormat = llvm::remarks::Format::YAML; } else { SILOpts.OptRecordFormat = *formatOrErr; } SILMod->installSILRemarkStreamer(); } switch (options.OptimizationGroup) { case OptGroup::Diagnostics: runSILDiagnosticPasses(*SILMod.get()); break; case OptGroup::Performance: runSILOptimizationPasses(*SILMod.get()); break; case OptGroup::Lowering: runSILLoweringPasses(*SILMod.get()); break; case OptGroup::OnonePerformance: runSILPassesForOnone(*SILMod.get()); break; case OptGroup::Unknown: { auto T = irgen::createIRGenModule( SILMod.get(), Invocation.getOutputFilenameForAtMostOnePrimary(), Invocation.getMainInputFilenameForDebugInfoForAtMostOnePrimary(), "", IRGenOpts); runCommandLineSelectedPasses(SILMod.get(), T.second, options); irgen::deleteIRGenModule(T); break; } } if (options.EmitSIB || options.Serialize) { llvm::SmallString<128> OutputFile; if (options.OutputFilename.size()) { OutputFile = options.OutputFilename; } else if (options.ModuleName.size()) { OutputFile = options.ModuleName; llvm::sys::path::replace_extension( OutputFile, file_types::getExtension(file_types::TY_SIB)); } else { OutputFile = CI.getMainModule()->getName().str(); llvm::sys::path::replace_extension( OutputFile, file_types::getExtension(file_types::TY_SIB)); } SerializationOptions serializationOpts; serializationOpts.OutputPath = OutputFile; serializationOpts.SerializeAllSIL = options.EmitSIB; serializationOpts.IsSIB = options.EmitSIB; symbolgraphgen::SymbolGraphOptions symbolGraphOptions; serialize(CI.getMainModule(), serializationOpts, symbolGraphOptions, SILMod.get()); } else { const StringRef OutputFile = options.OutputFilename.size() ? StringRef(options.OutputFilename) : "-"; auto SILOpts = SILOptions(); SILOpts.EmitVerboseSIL = options.EmitVerboseSIL; SILOpts.EmitSortedSIL = options.EmitSortedSIL; if (OutputFile == "-") { SILMod->print(llvm::outs(), CI.getMainModule(), SILOpts, !options.DisableASTDump); } else { std::error_code EC; llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_None); if (EC) { llvm::errs() << "while opening '" << OutputFile << "': " << EC.message() << '\n'; return finishDiagProcessing(1); } SILMod->print(OS, CI.getMainModule(), SILOpts, !options.DisableASTDump); } } HadError |= CI.getASTContext().hadError(); if (options.VerifyMode) { DiagnosticEngine &diags = CI.getDiags(); if (diags.hasFatalErrorOccurred() && !Invocation.getDiagnosticOptions().ShowDiagnosticsAfterFatalError) { diags.resetHadAnyError(); diags.diagnose(SourceLoc(), diag::verify_encountered_fatal); HadError = true; } } return finishDiagProcessing(HadError); }