diff --git a/lib/DriverTool/sil_llvm_gen_main.cpp b/lib/DriverTool/sil_llvm_gen_main.cpp index 9bc9a2debe961..6acb9fd1d9fee 100644 --- a/lib/DriverTool/sil_llvm_gen_main.cpp +++ b/lib/DriverTool/sil_llvm_gen_main.cpp @@ -22,6 +22,7 @@ #include "swift/AST/SILOptions.h" #include "swift/Basic/Assertions.h" #include "swift/Basic/LLVMInitialize.h" +#include "swift/Basic/QuotedString.h" #include "swift/Frontend/DiagnosticVerifier.h" #include "swift/Frontend/Frontend.h" #include "swift/Frontend/PrintingDiagnosticConsumer.h" @@ -49,6 +50,29 @@ #include using namespace swift; +namespace { +enum class SILOptStrictConcurrency { + None = 0, + Complete, + Targeted, + Minimal, +}; +} + +static std::optional +convertSILOptToRawStrictConcurrencyLevel(SILOptStrictConcurrency level) { + switch (level) { + case SILOptStrictConcurrency::None: + return {}; + case SILOptStrictConcurrency::Complete: + return StrictConcurrency::Complete; + case SILOptStrictConcurrency::Targeted: + return StrictConcurrency::Targeted; + case SILOptStrictConcurrency::Minimal: + return StrictConcurrency::Minimal; + } +} + struct SILLLVMGenOptions { llvm::cl::opt InputFilename = llvm::cl::opt(llvm::cl::desc("input file"), @@ -66,12 +90,29 @@ struct SILLLVMGenOptions { 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 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 DisableImplicitModules = + llvm::cl::opt("disable-implicit-swift-modules", + llvm::cl::desc("Disable implicit swift modules.")); + + llvm::cl::opt ExplicitSwiftModuleMapPath = + llvm::cl::opt( + "explicit-swift-module-map-file", + llvm::cl::desc("Explict swift module map file path")); + llvm::cl::opt ResourceDir = llvm::cl::opt( "resource-dir", @@ -96,27 +137,94 @@ struct SILLLVMGenOptions { llvm::cl::opt PerformWMO = llvm::cl::opt("wmo", llvm::cl::desc("Enable whole-module optimizations")); - llvm::cl::opt - OutputKind = llvm::cl::opt( + llvm::cl::opt OutputKind = llvm::cl::opt( "output-kind", llvm::cl::desc("Type of output to produce"), - llvm::cl::values(clEnumValN(IRGenOutputKind::LLVMAssemblyAfterOptimization, - "llvm-as", "Emit llvm assembly"), - clEnumValN(IRGenOutputKind::LLVMBitcode, "llvm-bc", - "Emit llvm bitcode"), - clEnumValN(IRGenOutputKind::NativeAssembly, "as", - "Emit native assembly"), - clEnumValN(IRGenOutputKind::ObjectFile, "object", - "Emit an object file")), + llvm::cl::values( + clEnumValN(IRGenOutputKind::LLVMAssemblyBeforeOptimization, "llvm-as", + "Emit llvm assembly before optimization"), + clEnumValN(IRGenOutputKind::LLVMAssemblyAfterOptimization, + "llvm-as-opt", "Emit llvm assembly after optimization"), + clEnumValN(IRGenOutputKind::LLVMBitcode, "llvm-bc", + "Emit llvm bitcode"), + clEnumValN(IRGenOutputKind::NativeAssembly, "as", + "Emit native assembly"), + clEnumValN(IRGenOutputKind::ObjectFile, "object", + "Emit an object file")), llvm::cl::init(IRGenOutputKind::ObjectFile)); llvm::cl::opt DisableLegacyTypeInfo = llvm::cl::opt("disable-legacy-type-info", llvm::cl::desc("Don't try to load backward deployment layouts")); + + llvm::cl::opt SwiftVersionString = llvm::cl::opt( + "swift-version", + llvm::cl::desc( + "The swift version to assume AST declarations correspond to")); + + llvm::cl::opt EnableExperimentalConcurrency = llvm::cl::opt( + "enable-experimental-concurrency", + llvm::cl::desc("Enable experimental concurrency model.")); + + 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::list ExperimentalFeatures = + llvm::cl::list( + "enable-experimental-feature", + llvm::cl::desc("Enable the given experimental feature.")); + + llvm::cl::list UpcomingFeatures = llvm::cl::list( + "enable-upcoming-feature", + llvm::cl::desc("Enable the given upcoming feature.")); + + llvm::cl::opt EnableCxxInterop = llvm::cl::opt( + "enable-experimental-cxx-interop", llvm::cl::desc("Enable C++ interop."), + llvm::cl::init(false)); + + 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.")); + + // Strict Concurrency + llvm::cl::opt StrictConcurrencyLevel = + llvm::cl::opt( + "strict-concurrency", llvm::cl::desc("strict concurrency level"), + llvm::cl::init(SILOptStrictConcurrency::None), + llvm::cl::values( + clEnumValN(SILOptStrictConcurrency::Complete, "complete", + "Enable complete strict concurrency"), + clEnumValN(SILOptStrictConcurrency::Targeted, "targeted", + "Enable targeted strict concurrency"), + clEnumValN(SILOptStrictConcurrency::Minimal, "minimal", + "Enable minimal strict concurrency"), + clEnumValN(SILOptStrictConcurrency::None, "disabled", + "Strict concurrency disabled"))); }; +static std::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 std::nullopt; + } + llvm_unreachable("Bad case for llvm::cl::boolOrDefault!"); +} + int sil_llvm_gen_main(ArrayRef argv, void *MainAddr) { INITIALIZE_LLVM(); + llvm::setBugReportMsg(SWIFT_CRASH_BUG_REPORT_MESSAGE "\n"); + llvm::EnablePrettyStackTraceOnSigInfoForThisThread(); + SILLLVMGenOptions options; llvm::cl::ParseCommandLineOptions(argv.size(), argv.data(), "Swift LLVM IR Generator\n"); @@ -139,6 +247,9 @@ int sil_llvm_gen_main(ArrayRef argv, void *MainAddr) { 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"); @@ -151,17 +262,110 @@ int sil_llvm_gen_main(ArrayRef argv, void *MainAddr) { Invocation.setTargetTriple(options.Target); if (!options.ResourceDir.empty()) Invocation.setRuntimeResourcePath(options.ResourceDir); + + Invocation.getFrontendOptions().StrictImplicitModuleContext = + options.StrictImplicitModuleContext; + + Invocation.getFrontendOptions().DisableImplicitModules = + options.DisableImplicitModules; + Invocation.getSearchPathOptions().ExplicitSwiftModuleMapPath = + options.ExplicitSwiftModuleMapPath; + // Set the module cache path. If not passed in we use the default swift module // cache. Invocation.getClangImporterOptions().ModuleCachePath = options.ModuleCachePath; Invocation.setParseStdlib(); // Setup the language options - auto &LangOpts = Invocation.getLangOptions(); - LangOpts.DisableAvailabilityChecking = true; - LangOpts.EnableAccessControl = false; - LangOpts.EnableObjCAttrRequiresFoundation = false; - LangOpts.EnableObjCInterop = LangOpts.Target.isOSDarwin(); + if (options.SwiftVersionString.size()) { + auto vers = VersionParser::parseVersionString(options.SwiftVersionString, + SourceLoc(), nullptr); + bool isValid = false; + if (vers.has_value()) { + if (auto effectiveVers = vers.value().getEffectiveLanguageVersion()) { + Invocation.getLangOptions().EffectiveLanguageVersion = + effectiveVers.value(); + isValid = true; + } + } + if (!isValid) { + llvm::errs() << "error: invalid swift version " + << options.SwiftVersionString << '\n'; + exit(-1); + } + } + Invocation.getLangOptions().DisableAvailabilityChecking = true; + Invocation.getLangOptions().EnableAccessControl = false; + Invocation.getLangOptions().EnableObjCAttrRequiresFoundation = false; + Invocation.getLangOptions().EnableDeserializationSafety = false; + Invocation.getLangOptions().EnableExperimentalConcurrency = + options.EnableExperimentalConcurrency; + std::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); + } + + for (auto &featureName : options.UpcomingFeatures) { + auto feature = Feature::getUpcomingFeature(featureName); + if (!feature) { + llvm::errs() << "error: unknown upcoming feature " + << QuotedString(featureName) << "\n"; + exit(-1); + } + + if (auto firstVersion = feature->getLanguageVersion()) { + if (Invocation.getLangOptions().isSwiftVersionAtLeast(*firstVersion)) { + llvm::errs() << "error: upcoming feature " << QuotedString(featureName) + << " is already enabled as of Swift version " + << *firstVersion << '\n'; + exit(-1); + } + } + Invocation.getLangOptions().enableFeature(*feature); + } + + for (auto &featureName : options.ExperimentalFeatures) { + if (auto feature = Feature::getExperimentalFeature(featureName)) { + Invocation.getLangOptions().enableFeature(*feature); + } else { + llvm::errs() << "error: unknown experimental feature " + << QuotedString(featureName) << "\n"; + exit(-1); + } + } + + // Enable strict concurrency if we have the feature specified or if it was + // specified via a command line option to sil-opt. + if (Invocation.getLangOptions().hasFeature(Feature::StrictConcurrency)) { + Invocation.getLangOptions().StrictConcurrencyLevel = + StrictConcurrency::Complete; + } else if (auto level = convertSILOptToRawStrictConcurrencyLevel( + options.StrictConcurrencyLevel)) { + // If strict concurrency was enabled from the cmdline so the feature flag as + // well. + if (*level == StrictConcurrency::Complete) + Invocation.getLangOptions().enableFeature(Feature::StrictConcurrency); + Invocation.getLangOptions().StrictConcurrencyLevel = *level; + } + + // If we have strict concurrency set as a feature and were told to turn off + // region-based isolation... do so now. + if (Invocation.getLangOptions().hasFeature(Feature::StrictConcurrency)) { + Invocation.getLangOptions().enableFeature(Feature::RegionBasedIsolation); + } + + Invocation.getLangOptions().EnableObjCInterop = + options.EnableObjCInterop ? true + : options.DisableObjCInterop ? false + : llvm::Triple(options.Target).isOSDarwin(); + + Invocation.getLangOptions().EnableCXXInterop = options.EnableCxxInterop; + Invocation.computeCXXStdlibOptions(); // Setup the IRGen Options. IRGenOptions &Opts = Invocation.getIRGenOptions(); @@ -216,16 +420,26 @@ int sil_llvm_gen_main(ArrayRef argv, void *MainAddr) { return IRGenDescriptor::forWholeModule( mod, Opts, TBDOpts, SILOpts, SILTypes, /*SILMod*/ nullptr, moduleName, PSPs); - } else { - return IRGenDescriptor::forFile( - mod->getFiles()[0], Opts, TBDOpts, SILOpts, SILTypes, - /*SILMod*/ nullptr, moduleName, PSPs, /*discriminator*/ ""); } + + return IRGenDescriptor::forFile( + mod->getFiles()[0], Opts, TBDOpts, SILOpts, SILTypes, + /*SILMod*/ nullptr, moduleName, PSPs, /*discriminator*/ ""); }; auto &eval = CI.getASTContext().evaluator; auto desc = getDescriptor(); desc.out = &outFile->getOS(); + + if (options.OutputKind == IRGenOutputKind::LLVMAssemblyBeforeOptimization) { + auto generatedMod = evaluateOrFatal(eval, IRGenRequest{desc}); + if (!generatedMod) + return 1; + + generatedMod.getModule()->print(*outFile, nullptr); + return 0; + } + auto generatedMod = evaluateOrFatal(eval, OptimizedIRRequest{desc}); if (!generatedMod) return 1; diff --git a/test/sil-llvm-gen/alloc.sil b/test/sil-llvm-gen/alloc.sil index b39802a90cfea..385ee8ee9780c 100644 --- a/test/sil-llvm-gen/alloc.sil +++ b/test/sil-llvm-gen/alloc.sil @@ -1,12 +1,12 @@ -// RUN: %sil-llvm-gen -disable-legacy-type-info -output-kind=llvm-as -target x86_64-apple-macosx10.9 -module-name main %s -o - | %FileCheck %s -// RUN: %sil-llvm-gen -disable-legacy-type-info -output-kind=llvm-as -target i386-apple-ios7.0 %s -module-name main -o - | %FileCheck %s -// RUN: %sil-llvm-gen -disable-legacy-type-info -output-kind=llvm-as -target x86_64-apple-ios7.0 %s -module-name main -o - | %FileCheck %s -// RUN: %sil-llvm-gen -disable-legacy-type-info -output-kind=llvm-as -target armv7-apple-ios7.0 %s -module-name main -o - | %FileCheck %s -// RUN: %sil-llvm-gen -disable-legacy-type-info -output-kind=llvm-as -target arm64-apple-ios7.0 %s -module-name main -o - | %FileCheck %s -// RUN: %sil-llvm-gen -disable-legacy-type-info -output-kind=llvm-as -target x86_64-unknown-linux-gnu %s -module-name main -o - | %FileCheck %s +// RUN: %sil-llvm-gen -disable-legacy-type-info -output-kind=llvm-as-opt -target x86_64-apple-macosx10.9 -module-name main %s -o - | %FileCheck %s +// RUN: %sil-llvm-gen -disable-legacy-type-info -output-kind=llvm-as-opt -target i386-apple-ios7.0 %s -module-name main -o - | %FileCheck %s +// RUN: %sil-llvm-gen -disable-legacy-type-info -output-kind=llvm-as-opt -target x86_64-apple-ios7.0 %s -module-name main -o - | %FileCheck %s +// RUN: %sil-llvm-gen -disable-legacy-type-info -output-kind=llvm-as-opt -target armv7-apple-ios7.0 %s -module-name main -o - | %FileCheck %s +// RUN: %sil-llvm-gen -disable-legacy-type-info -output-kind=llvm-as-opt -target arm64-apple-ios7.0 %s -module-name main -o - | %FileCheck %s +// RUN: %sil-llvm-gen -disable-legacy-type-info -output-kind=llvm-as-opt -target x86_64-unknown-linux-gnu %s -module-name main -o - | %FileCheck %s // Use this testfile to check if the `swift-frontend -sil-llvm-gen` option works. -// RUN: %swift_frontend_plain -sil-llvm-gen -disable-legacy-type-info -output-kind=llvm-as -target x86_64-apple-macosx10.9 -module-name main %s -o - | %FileCheck %s +// RUN: %swift_frontend_plain -sil-llvm-gen -disable-legacy-type-info -output-kind=llvm-as-opt -target x86_64-apple-macosx10.9 -module-name main %s -o - | %FileCheck %s // REQUIRES: CODEGENERATOR=X86 // REQUIRES: CODEGENERATOR=ARM