diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index d9ac7cf63e0fc..c165497078c45 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -491,6 +491,15 @@ class IRGenOptions { /// The calling convention used to perform non-swift calls. llvm::CallingConv::ID PlatformCCallingConvention; + /// Use CAS based object format as the output. + bool UseCASBackend; + + /// The output mode for the CAS Backend. + llvm::CASBackendMode CASObjMode; + + /// Emit a .casid file next to the object file if CAS Backend is used. + bool EmitCASIDFile; + IRGenOptions() : DWARFVersion(2), OutputKind(IRGenOutputKind::LLVMAssemblyAfterOptimization), @@ -502,9 +511,9 @@ class IRGenOptions { DebugInfoFormat(IRGenDebugInfoFormat::None), DisableClangModuleSkeletonCUs(false), UseJIT(false), DisableLLVMOptzns(false), DisableSwiftSpecificLLVMOptzns(false), - Playground(false), - EmitStackPromotionChecks(false), UseSingleModuleLLVMEmission(false), - FunctionSections(false), PrintInlineTree(false), AlwaysCompile(false), + Playground(false), EmitStackPromotionChecks(false), + UseSingleModuleLLVMEmission(false), FunctionSections(false), + PrintInlineTree(false), AlwaysCompile(false), EmbedMode(IRGenEmbedMode::None), LLVMLTOKind(IRGenLLVMLTOKind::None), SwiftAsyncFramePointer(SwiftAsyncFramePointerKind::Auto), HasValueNamesSetting(false), ValueNames(false), @@ -526,13 +535,12 @@ class IRGenOptions { WitnessMethodElimination(false), ConditionalRuntimeRecords(false), InternalizeAtLink(false), InternalizeSymbols(false), EmitGenericRODatas(false), NoPreallocatedInstantiationCaches(false), - DisableReadonlyStaticObjects(false), - CollocatedMetadataFunctions(false), - ColocateTypeDescriptors(true), - UseRelativeProtocolWitnessTables(false), CmdArgs(), - SanitizeCoverage(llvm::SanitizerCoverageOptions()), + DisableReadonlyStaticObjects(false), CollocatedMetadataFunctions(false), + ColocateTypeDescriptors(true), UseRelativeProtocolWitnessTables(false), + CmdArgs(), SanitizeCoverage(llvm::SanitizerCoverageOptions()), TypeInfoFilter(TypeInfoDumpFilter::All), - PlatformCCallingConvention(llvm::CallingConv::C) { + PlatformCCallingConvention(llvm::CallingConv::C), UseCASBackend(false), + CASObjMode(llvm::CASBackendMode::Native) { #ifndef NDEBUG DisableRoundTripDebugTypes = false; #else diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index d6e99cbece74b..0f5aa5bd25de7 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -164,6 +164,10 @@ class CompilerInvocation { return LangOpts.Target.str(); } + bool requiresCAS() const { + return FrontendOpts.EnableCaching || FrontendOpts.UseCASBackend; + } + void setClangModuleCachePath(StringRef Path) { ClangImporterOpts.ModuleCachePath = Path.str(); } diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 51b704159f345..b940842c93278 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -14,14 +14,15 @@ #define SWIFT_FRONTEND_FRONTENDOPTIONS_H #include "swift/Basic/FileTypes.h" -#include "swift/Basic/Version.h" #include "swift/Basic/PathRemapper.h" +#include "swift/Basic/Version.h" #include "swift/Frontend/FrontendInputsAndOutputs.h" #include "swift/Frontend/InputFile.h" +#include "clang/CAS/CASOptions.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringMap.h" -#include "clang/CAS/CASOptions.h" +#include "llvm/MC/MCTargetOptions.h" #include #include @@ -149,6 +150,15 @@ class FrontendOptions { /// CacheKey for input file. std::string InputFileKey; + /// Enable using the LLVM MCCAS backend for object file output. + bool UseCASBackend = false; + + /// The output mode for the CAS Backend. + llvm::CASBackendMode CASObjMode; + + /// Emit a .casid file next to the object file if CAS Backend is used. + bool EmitCASIDFile = false; + /// Number of retry opening an input file if the previous opening returns /// bad file descriptor error. unsigned BadFileDescriptorRetryCount = 0; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index a6faf8336f371..d8084460b9892 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -1858,6 +1858,19 @@ def external_plugin_path : Separate<["-"], "external-plugin-path">, Group, HelpText<"Add directory to the plugin search path with a plugin server executable">, MetaVarName<"#">; + +def cas_backend: Flag<["-"], "cas-backend">, + Flags<[FrontendOption, NoDriverOption]>, + HelpText<"Enable using CASBackend for object file output">; + +def cas_backend_mode: Joined<["-"], "cas-backend-mode=">, + Flags<[FrontendOption, NoDriverOption]>, + HelpText<"CASBackendMode for output kind">, + MetaVarName<"native|casid|verify">; + +def cas_emit_casid_file: Flag<["-"], "cas-emit-casid-file">, + Flags<[FrontendOption, NoDriverOption]>, + HelpText<"Emit .casid file next to object file when CAS Backend is enabled">; def load_plugin_library: Separate<["-"], "load-plugin-library">, Group, diff --git a/include/swift/Subsystems.h b/include/swift/Subsystems.h index 2ce46a717e76c..86f742d0515a9 100644 --- a/include/swift/Subsystems.h +++ b/include/swift/Subsystems.h @@ -263,7 +263,8 @@ namespace swift { const IRGenOptions &opts, UnifiedStatsReporter *stats, DiagnosticEngine &diags, llvm::raw_pwrite_stream &out, - llvm::sys::Mutex *diagMutex = nullptr); + 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, diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 3e51a0c44dda9..7d3dbfea90080 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -380,6 +380,17 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.BlocklistConfigFilePaths.push_back(A); } + if (Arg *A = Args.getLastArg(OPT_cas_backend_mode)) { + Opts.CASObjMode = llvm::StringSwitch(A->getValue()) + .Case("native", llvm::CASBackendMode::Native) + .Case("casid", llvm::CASBackendMode::CASID) + .Case("verify", llvm::CASBackendMode::Verify) + .Default(llvm::CASBackendMode::Native); + } + + Opts.UseCASBackend = Args.hasArg(OPT_cas_backend); + Opts.EmitCASIDFile = Args.hasArg(OPT_cas_emit_casid_file); + return false; } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 1e693ad9583cf..0c76ee6efd132 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -266,6 +266,10 @@ setIRGenOutputOptsFromFrontendOptions(IRGenOptions &IRGenOpts, } }(FrontendOpts.RequestedAction); + IRGenOpts.UseCASBackend = FrontendOpts.UseCASBackend; + IRGenOpts.CASObjMode = FrontendOpts.CASObjMode; + IRGenOpts.EmitCASIDFile = FrontendOpts.EmitCASIDFile; + // If we're in JIT mode, set the requisite flags. if (FrontendOpts.RequestedAction == FrontendOptions::ActionType::Immediate) { IRGenOpts.UseJIT = true; @@ -1440,7 +1444,8 @@ static bool ParseClangImporterArgs(ClangImporterOptions &Opts, DiagnosticEngine &Diags, StringRef workingDirectory, const LangOptions &LangOpts, - const FrontendOptions &FrontendOpts) { + const FrontendOptions &FrontendOpts, + bool RequiresCAS) { using namespace options; if (const Arg *a = Args.getLastArg(OPT_tools_directory)) { @@ -1568,7 +1573,7 @@ static bool ParseClangImporterArgs(ClangImporterOptions &Opts, // Forward the FrontendOptions to clang importer option so it can be // accessed when creating clang module compilation invocation. - if (FrontendOpts.EnableCaching) + if (RequiresCAS) Opts.CASOpts = FrontendOpts.CASOpts; return false; @@ -3025,7 +3030,7 @@ bool CompilerInvocation::parseArgs( } if (ParseClangImporterArgs(ClangImporterOpts, ParsedArgs, Diags, - workingDirectory, LangOpts, FrontendOpts)) { + workingDirectory, LangOpts, FrontendOpts, requiresCAS())) { return true; } diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 9e153fe1c3047..8a5523cb46466 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -407,7 +407,7 @@ void CompilerInstance::setupDependencyTrackerIfNeeded() { bool CompilerInstance::setupCASIfNeeded(ArrayRef Args) { const auto &Opts = getInvocation().getFrontendOptions(); - if (!Opts.EnableCaching) + if (!getInvocation().requiresCAS()) return false; auto MaybeDB= Opts.CASOpts.getOrCreateDatabases(); diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index b846a16457a90..59b21e01e5617 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1672,6 +1672,7 @@ static bool generateCode(CompilerInstance &Instance, StringRef OutputFilename, std::unique_ptr TargetMachine = createTargetMachine(opts, Instance.getASTContext()); + TargetMachine->Options.MCOptions.CAS = Instance.getSharedCASInstance(); // Free up some compiler resources now that we have an IRModule. freeASTContextIfPossible(Instance); diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index 37680fd6e8164..fbb9ac97c4704 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -128,6 +128,12 @@ swift::getIRTargetOptions(const IRGenOptions &Opts, ASTContext &Ctx) { TargetOpts.DebuggerTuning = llvm::DebuggerKind::LLDB; TargetOpts.FunctionSections = Opts.FunctionSections; + // Set option to UseCASBackend if CAS was enabled on the command line. + TargetOpts.UseCASBackend = Opts.UseCASBackend; + + // Set option to select the CASBackendMode. + TargetOpts.MCOptions.CASObjMode = Opts.CASObjMode; + auto *Clang = static_cast(Ctx.getClangModuleLoader()); // WebAssembly doesn't support atomics yet, see @@ -605,17 +611,31 @@ bool swift::performLLVM(const IRGenOptions &Opts, if (OutputFilename.empty()) return false; + std::unique_ptr CASIDFile; + if (Opts.UseCASBackend && Opts.EmitCASIDFile && + Opts.CASObjMode != llvm::CASBackendMode::CASID && + Opts.OutputKind == IRGenOutputKind::ObjectFile && OutputFilename != "-") { + std::string OutputFilenameCASID = std::string(OutputFilename); + OutputFilenameCASID.append(".casid"); + std::error_code EC; + CASIDFile = std::make_unique(OutputFilenameCASID, EC); + if (EC) { + diagnoseSync(Diags, DiagMutex, SourceLoc(), diag::error_opening_output, + OutputFilename, std::move(EC.message())); + return true; + } + } + return compileAndWriteLLVM(Module, TargetMachine, Opts, Stats, Diags, - *OutputFile, DiagMutex); + *OutputFile, DiagMutex, + CASIDFile ? CASIDFile.get() : nullptr); } -bool swift::compileAndWriteLLVM(llvm::Module *module, - llvm::TargetMachine *targetMachine, - const IRGenOptions &opts, - UnifiedStatsReporter *stats, - DiagnosticEngine &diags, - llvm::raw_pwrite_stream &out, - llvm::sys::Mutex *diagMutex) { +bool swift::compileAndWriteLLVM( + llvm::Module *module, llvm::TargetMachine *targetMachine, + const IRGenOptions &opts, UnifiedStatsReporter *stats, + DiagnosticEngine &diags, llvm::raw_pwrite_stream &out, + llvm::sys::Mutex *diagMutex, llvm::raw_pwrite_stream *casid) { // Set up the final code emission pass. Bitcode/LLVM IR is emitted as part of // the optimization pass pipeline. @@ -639,8 +659,8 @@ bool swift::compileAndWriteLLVM(llvm::Module *module, EmitPasses.add(createTargetTransformInfoWrapperPass( targetMachine->getTargetIRAnalysis())); - bool fail = targetMachine->addPassesToEmitFile(EmitPasses, out, nullptr, - FileType, !opts.Verify); + bool fail = targetMachine->addPassesToEmitFile( + EmitPasses, out, nullptr, FileType, !opts.Verify, nullptr, casid); if (fail) { diagnoseSync(diags, diagMutex, SourceLoc(), diag::error_codegen_init_fail); diff --git a/test/CAS/mccas.swift b/test/CAS/mccas.swift new file mode 100644 index 0000000000000..0bcfc1412aa20 --- /dev/null +++ b/test/CAS/mccas.swift @@ -0,0 +1,25 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -c %s -target arm64-apple-darwin23.0.0 -g -cas-backend -cas-backend-mode=verify -cas-path %t/cas -o %t/test-verify.o +// RUN: %llvm-dwarfdump %t/test-verify.o | %FileCheck %s --check-prefix=VERIFY-FILE +// VERIFY-FILE: .debug_info + +// RUN: %target-swift-frontend -c %s -target arm64-apple-darwin23.0.0 -g -cas-backend -cas-backend-mode=native -cas-path %t/cas -o %t/test-native.o +// RUN: %llvm-dwarfdump %t/test-native.o | %FileCheck %s --check-prefix=NATIVE-FILE +// NATIVE-FILE: .debug_info + +// RUN: %target-swift-frontend -c %s -target arm64-apple-darwin23.0.0 -g -cas-backend -cas-backend-mode=casid -cas-path %t/cas -o %t/test-casid.id +// RUN: cat %t/test-casid.id | %FileCheck %s --check-prefix=CASID-FILE +// CASID-FILE: CASID:Jllvmcas://{{.*}} + +// RUN: %target-swift-frontend -c %s -target arm64-apple-darwin23.0.0 -g -cas-backend -cas-emit-casid-file -cas-backend-mode=verify -cas-path %t/cas -o %t/test-verify-emit.o +// RUN: cat %t/test-verify-emit.o.casid | %FileCheck %s --check-prefix=VERIFY-EMIT +// VERIFY-EMIT: CASID:Jllvmcas://{{.*}} + +// RUN: %target-swift-frontend -c %s -target arm64-apple-darwin23.0.0 -g -cas-backend -cas-emit-casid-file -cas-backend-mode=native -cas-path %t/cas -o %t/test-native-emit.o +// RUN: cat %t/test-native-emit.o.casid | %FileCheck %s --check-prefix=NATIVE-EMIT +// NATIVE-EMIT: CASID:Jllvmcas://{{.*}} + +// RUN: %target-swift-frontend -c %s -target arm64-apple-darwin23.0.0 -g -cas-backend -cas-emit-casid-file -cas-backend-mode=casid -cas-path %t/cas -o %t/test.id +// RUN: not cat %t/test.id.casid + +func testFunc() {} \ No newline at end of file