diff --git a/include/swift/AST/IRGenRequests.h b/include/swift/AST/IRGenRequests.h index 67d3117e36215..1202364104519 100644 --- a/include/swift/AST/IRGenRequests.h +++ b/include/swift/AST/IRGenRequests.h @@ -22,11 +22,13 @@ #include "swift/AST/SimpleRequest.h" #include "swift/Basic/PrimarySpecificPaths.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Target/TargetMachine.h" namespace swift { class SourceFile; class IRGenOptions; class SILModule; +class SILOptions; struct TBDGenOptions; namespace irgen { @@ -39,6 +41,7 @@ namespace llvm { class GlobalVariable; class LLVMContext; class Module; +class TargetMachine; namespace orc { class ThreadSafeModule; @@ -58,8 +61,9 @@ class GeneratedModule final { private: std::unique_ptr Context; std::unique_ptr Module; + std::unique_ptr Target; - GeneratedModule() : Context(nullptr), Module(nullptr) {} + GeneratedModule() : Context(nullptr), Module(nullptr), Target(nullptr) {} GeneratedModule(GeneratedModule const &) = delete; GeneratedModule &operator=(GeneratedModule const &) = delete; @@ -70,10 +74,13 @@ class GeneratedModule final { /// The given pointers must not be null. If a null \c GeneratedModule is /// needed, use \c GeneratedModule::null() instead. explicit GeneratedModule(std::unique_ptr &&Context, - std::unique_ptr &&Module) - : Context(std::move(Context)), Module(std::move(Module)) { + std::unique_ptr &&Module, + std::unique_ptr &&Target) + : Context(std::move(Context)), Module(std::move(Module)), + Target(std::move(Target)) { assert(getModule() && "Use GeneratedModule::null() instead"); assert(getContext() && "Use GeneratedModule::null() instead"); + assert(getTargetMachine() && "Use GeneratedModule::null() instead"); } GeneratedModule(GeneratedModule &&) = default; @@ -97,6 +104,9 @@ class GeneratedModule final { const llvm::LLVMContext *getContext() const { return Context.get(); } llvm::LLVMContext *getContext() { return Context.get(); } + const llvm::TargetMachine *getTargetMachine() const { return Target.get(); } + llvm::TargetMachine *getTargetMachine() { return Target.get(); } + public: /// Release ownership of the context and module to the caller, consuming /// this value in the process. @@ -114,12 +124,15 @@ class GeneratedModule final { }; struct IRGenDescriptor { - llvm::PointerUnion Ctx; + llvm::PointerUnion Ctx; const IRGenOptions &Opts; const TBDGenOptions &TBDOpts; + const SILOptions &SILOpts; + Lowering::TypeConverter &Conv; SILModule *SILMod; + StringRef ModuleName; const PrimarySpecificPaths &PSPs; StringRef PrivateDiscriminator; @@ -142,14 +155,17 @@ struct IRGenDescriptor { public: static IRGenDescriptor - forFile(SourceFile &SF, const IRGenOptions &Opts, - const TBDGenOptions &TBDOpts, std::unique_ptr &&SILMod, + forFile(FileUnit *file, const IRGenOptions &Opts, + const TBDGenOptions &TBDOpts, const SILOptions &SILOpts, + Lowering::TypeConverter &Conv, std::unique_ptr &&SILMod, StringRef ModuleName, const PrimarySpecificPaths &PSPs, StringRef PrivateDiscriminator, - llvm::GlobalVariable **outModuleHash) { - return IRGenDescriptor{&SF, + llvm::GlobalVariable **outModuleHash = nullptr) { + return IRGenDescriptor{file, Opts, TBDOpts, + SILOpts, + Conv, SILMod.release(), ModuleName, PSPs, @@ -160,14 +176,17 @@ struct IRGenDescriptor { static IRGenDescriptor forWholeModule(ModuleDecl *M, const IRGenOptions &Opts, - const TBDGenOptions &TBDOpts, + const TBDGenOptions &TBDOpts, const SILOptions &SILOpts, + Lowering::TypeConverter &Conv, std::unique_ptr &&SILMod, StringRef ModuleName, const PrimarySpecificPaths &PSPs, - ArrayRef parallelOutputFilenames, - llvm::GlobalVariable **outModuleHash) { + ArrayRef parallelOutputFilenames = {}, + llvm::GlobalVariable **outModuleHash = nullptr) { return IRGenDescriptor{M, Opts, TBDOpts, + SILOpts, + Conv, SILMod.release(), ModuleName, PSPs, @@ -217,6 +236,21 @@ void simple_display(llvm::raw_ostream &out, const IRGenDescriptor &d); SourceLoc extractNearestSourceLoc(const IRGenDescriptor &desc); +/// Returns the optimized IR for a given file or module. Note this runs the +/// entire compiler pipeline and ignores the passed SILModule. +class OptimizedIRRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + GeneratedModule evaluate(Evaluator &evaluator, IRGenDescriptor desc) const; +}; + /// The zone number for IRGen. #define SWIFT_TYPEID_ZONE IRGen #define SWIFT_TYPEID_HEADER "swift/AST/IRGenTypeIDZone.def" diff --git a/include/swift/AST/IRGenTypeIDZone.def b/include/swift/AST/IRGenTypeIDZone.def index e3f2ff3fba08a..d8dbbb770ce88 100644 --- a/include/swift/AST/IRGenTypeIDZone.def +++ b/include/swift/AST/IRGenTypeIDZone.def @@ -17,3 +17,6 @@ SWIFT_REQUEST(IRGen, IRGenRequest, GeneratedModule(IRGenDescriptor), Uncached, NoLocationInfo) +SWIFT_REQUEST(IRGen, OptimizedIRRequest, + GeneratedModule(IRGenDescriptor), + Uncached, NoLocationInfo) diff --git a/include/swift/Subsystems.h b/include/swift/Subsystems.h index 2275e8735f938..de92b63e176d9 100644 --- a/include/swift/Subsystems.h +++ b/include/swift/Subsystems.h @@ -204,9 +204,8 @@ namespace swift { std::string> getIRTargetOptions(const 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. + /// 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, @@ -215,11 +214,10 @@ namespace swift { ArrayRef parallelOutputFilenames, 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. + /// 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(SourceFile &SF, const IRGenOptions &Opts, + performIRGeneration(FileUnit *file, const IRGenOptions &Opts, const TBDGenOptions &TBDOpts, std::unique_ptr SILMod, StringRef ModuleName, const PrimarySpecificPaths &PSPs, @@ -232,6 +230,15 @@ namespace swift { void performLLVMOptimizations(const IRGenOptions &Opts, llvm::Module *Module, llvm::TargetMachine *TargetMachine); + /// 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); + /// Wrap a serialized module inside a swift AST section in an object file. void createSwiftModuleObjectFile(SILModule &SILMod, StringRef Buffer, StringRef OutputPath); @@ -251,7 +258,6 @@ namespace swift { /// 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(const IRGenOptions &Opts, DiagnosticEngine &Diags, @@ -259,7 +265,6 @@ namespace swift { llvm::GlobalVariable *HashGlobal, llvm::Module *Module, llvm::TargetMachine *TargetMachine, - const version::Version &effectiveLanguageVersion, StringRef OutputFilename, UnifiedStatsReporter *Stats); diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index 37ccda1de0bce..6ab89f46fd310 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -405,7 +405,7 @@ std::string getSwiftFullVersion(Version effectiveVersion) { OS << "-dev"; #endif - if (!(effectiveVersion == Version::getCurrentLanguageVersion())) { + if (effectiveVersion != Version::getCurrentLanguageVersion()) { OS << " effective-" << effectiveVersion; } diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 077846c61eacc..21f4779fadad7 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1508,7 +1508,7 @@ generateIR(const IRGenOptions &IRGenOpts, const TBDGenOptions &TBDOpts, llvm::GlobalVariable *&HashGlobal, ArrayRef parallelOutputFilenames) { if (auto *SF = MSF.dyn_cast()) { - return performIRGeneration(*SF, IRGenOpts, TBDOpts, + return performIRGeneration(SF, IRGenOpts, TBDOpts, std::move(SM), OutputFilename, PSPs, SF->getPrivateDiscriminator().str(), &HashGlobal); @@ -1648,16 +1648,14 @@ static bool generateCode(CompilerInstance &Instance, StringRef OutputFilename, const auto &opts = Instance.getInvocation().getIRGenOptions(); std::unique_ptr TargetMachine = createTargetMachine(opts, Instance.getASTContext()); - version::Version EffectiveLanguageVersion = - Instance.getASTContext().LangOpts.EffectiveLanguageVersion; // Free up some compiler resources now that we have an IRModule. freeASTContextIfPossible(Instance); // Now that we have a single IR Module, hand it over to performLLVM. return performLLVM(opts, Instance.getDiags(), nullptr, HashGlobal, IRModule, - TargetMachine.get(), EffectiveLanguageVersion, - OutputFilename, Instance.getStatsReporter()); + TargetMachine.get(), OutputFilename, + Instance.getStatsReporter()); } static bool performCompileStepsPostSILGen(CompilerInstance &Instance, diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index 7d292c1ef2969..0d56d89c28c10 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -21,6 +21,7 @@ #include "swift/AST/IRGenRequests.h" #include "swift/AST/LinkLibrary.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SILGenRequests.h" #include "swift/Basic/Defer.h" #include "swift/Basic/Dwarf.h" #include "swift/Basic/Platform.h" @@ -309,6 +310,13 @@ void swift::performLLVMOptimizations(const IRGenOptions &Opts, if (Opts.PrintInlineTree) ModulePasses.add(createInlineTreePrinterPass()); + // Make sure we do ARC contraction under optimization. We don't + // rely on any other LLVM ARC transformations, but we do need ARC + // contraction to add the objc_retainAutoreleasedReturnValue + // assembly markers and remove clang.arc.used. + if (Opts.shouldOptimize() && !DisableObjCARCContract) + ModulePasses.add(createObjCARCContractPass()); + // Do it. ModulePasses.run(*Module); @@ -356,23 +364,23 @@ class MD5Stream : public llvm::raw_ostream { /// Computes the MD5 hash of the llvm \p Module including the compiler version /// and options which influence the compilation. -static void getHashOfModule(MD5::MD5Result &Result, const IRGenOptions &Opts, - const llvm::Module *Module, - llvm::TargetMachine *TargetMachine, - version::Version const& effectiveLanguageVersion) { +static MD5::MD5Result getHashOfModule(const IRGenOptions &Opts, + const llvm::Module *Module) { // Calculate the hash of the whole llvm module. MD5Stream HashStream; llvm::WriteBitcodeToFile(*Module, HashStream); // Update the hash with the compiler version. We want to recompile if the // llvm pipeline of the compiler changed. - HashStream << version::getSwiftFullVersion(effectiveLanguageVersion); + HashStream << version::getSwiftFullVersion(); // Add all options which influence the llvm compilation but are not yet // reflected in the llvm module itself. Opts.writeLLVMCodeGenOptionsTo(HashStream); - HashStream.final(Result); + MD5::MD5Result result; + HashStream.final(result); + return result; } /// Returns false if the hash of the current module \p HashData matches the @@ -477,27 +485,24 @@ bool swift::performLLVM(const IRGenOptions &Opts, llvm::GlobalVariable *HashGlobal, llvm::Module *Module, llvm::TargetMachine *TargetMachine, - const version::Version &effectiveLanguageVersion, StringRef OutputFilename, UnifiedStatsReporter *Stats) { if (Opts.UseIncrementalLLVMCodeGen && HashGlobal) { // Check if we can skip the llvm part of the compilation if we have an // existing object file which was generated from the same llvm IR. - MD5::MD5Result Result; - getHashOfModule(Result, Opts, Module, TargetMachine, - effectiveLanguageVersion); + auto hash = getHashOfModule(Opts, Module); LLVM_DEBUG( if (DiagMutex) DiagMutex->lock(); SmallString<32> ResultStr; - MD5::stringifyResult(Result, ResultStr); + MD5::stringifyResult(hash, ResultStr); llvm::dbgs() << OutputFilename << ": MD5=" << ResultStr << '\n'; if (DiagMutex) DiagMutex->unlock(); ); - ArrayRef HashData(reinterpret_cast(&Result), - sizeof(Result)); + ArrayRef HashData(reinterpret_cast(&hash), + sizeof(hash)); if (Opts.OutputKind == IRGenOutputKind::ObjectFile && !Opts.PrintInlineTree && !needsRecompile(OutputFilename, HashData, HashGlobal, DiagMutex)) { @@ -532,69 +537,74 @@ bool swift::performLLVM(const IRGenOptions &Opts, performLLVMOptimizations(Opts, Module, TargetMachine); - legacy::PassManager EmitPasses; + if (Stats) { + if (DiagMutex) + DiagMutex->lock(); + countStatsPostIRGen(*Stats, *Module); + if (DiagMutex) + DiagMutex->unlock(); + } - // Make sure we do ARC contraction under optimization. We don't - // rely on any other LLVM ARC transformations, but we do need ARC - // contraction to add the objc_retainAutoreleasedReturnValue - // assembly markers and remove clang.arc.used. - if (Opts.shouldOptimize() && !DisableObjCARCContract) - EmitPasses.add(createObjCARCContractPass()); + if (!RawOS) + return false; + + return compileAndWriteLLVM(Module, TargetMachine, Opts, Stats, Diags, *RawOS, + 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) { + legacy::PassManager EmitPasses; // Set up the final emission passes. - switch (Opts.OutputKind) { + switch (opts.OutputKind) { case IRGenOutputKind::Module: break; case IRGenOutputKind::LLVMAssembly: - EmitPasses.add(createPrintModulePass(*RawOS)); + EmitPasses.add(createPrintModulePass(out)); break; case IRGenOutputKind::LLVMBitcode: { - if (Opts.LLVMLTOKind == IRGenLLVMLTOKind::Thin) { - EmitPasses.add(createWriteThinLTOBitcodePass(*RawOS)); + if (opts.LLVMLTOKind == IRGenLLVMLTOKind::Thin) { + EmitPasses.add(createWriteThinLTOBitcodePass(out)); } else { - EmitPasses.add(createBitcodeWriterPass(*RawOS)); + EmitPasses.add(createBitcodeWriterPass(out)); } break; } case IRGenOutputKind::NativeAssembly: case IRGenOutputKind::ObjectFile: { CodeGenFileType FileType; - FileType = (Opts.OutputKind == IRGenOutputKind::NativeAssembly - ? CGFT_AssemblyFile - : CGFT_ObjectFile); - + FileType = + (opts.OutputKind == IRGenOutputKind::NativeAssembly ? CGFT_AssemblyFile + : CGFT_ObjectFile); EmitPasses.add(createTargetTransformInfoWrapperPass( - TargetMachine->getTargetIRAnalysis())); + targetMachine->getTargetIRAnalysis())); - bool fail = TargetMachine->addPassesToEmitFile(EmitPasses, *RawOS, nullptr, - FileType, !Opts.Verify); + bool fail = targetMachine->addPassesToEmitFile(EmitPasses, out, nullptr, + FileType, !opts.Verify); if (fail) { - diagnoseSync(Diags, DiagMutex, - SourceLoc(), diag::error_codegen_init_fail); + diagnoseSync(diags, diagMutex, SourceLoc(), + diag::error_codegen_init_fail); return true; } break; } } - if (Stats) { - if (DiagMutex) - DiagMutex->lock(); - countStatsPostIRGen(*Stats, *Module); - if (DiagMutex) - DiagMutex->unlock(); - } - - EmitPasses.run(*Module); + EmitPasses.run(*module); - if (Stats && RawOS.hasValue()) { - if (DiagMutex) - DiagMutex->lock(); - Stats->getFrontendCounters().NumLLVMBytesOutput += RawOS->tell(); - if (DiagMutex) - DiagMutex->unlock(); + if (stats) { + if (diagMutex) + diagMutex->lock(); + stats->getFrontendCounters().NumLLVMBytesOutput += out.tell(); + if (diagMutex) + diagMutex->unlock(); } - return false; } @@ -907,7 +917,8 @@ GeneratedModule IRGenRequest::evaluate(Evaluator &evaluator, auto SILMod = std::unique_ptr(desc.SILMod); auto *M = desc.getParentModule(); auto filesToEmit = desc.getFiles(); - auto *primaryFile = desc.Ctx.dyn_cast(); + auto *primaryFile = + dyn_cast_or_null(desc.Ctx.dyn_cast()); auto &Ctx = M->getASTContext(); assert(!Ctx.hadError()); @@ -986,7 +997,7 @@ GeneratedModule IRGenRequest::evaluate(Evaluator &evaluator, if (Ctx.hadError()) return GeneratedModule::null(); // Free the memory occupied by the SILModule. - // Execute this task in parallel to the LLVM compilation. + // Execute this task in parallel to the embedding of bitcode. auto SILModuleRelease = [&SILMod]() { SILMod.reset(nullptr); }; auto Thread = std::thread(SILModuleRelease); // Wait for the thread to terminate. @@ -994,19 +1005,10 @@ GeneratedModule IRGenRequest::evaluate(Evaluator &evaluator, embedBitcode(IGM.getModule(), Opts); + // TODO: Turn the module hash into an actual output. if (auto **outModuleHash = desc.outModuleHash) { *outModuleHash = IGM.ModuleHash; - } else { - FrontendStatsTracer tracer(Ctx.Stats, "LLVM pipeline"); - - // Since no out module hash was set, we need to performLLVM. - if (performLLVM(Opts, IGM.Context.Diags, nullptr, IGM.ModuleHash, - IGM.getModule(), IGM.TargetMachine.get(), - IGM.Context.LangOpts.EffectiveLanguageVersion, - IGM.OutputFilename, IGM.Context.Stats)) - return GeneratedModule::null(); } - return std::move(IGM).intoGeneratedModule(); } @@ -1037,7 +1039,6 @@ struct LLVMCodeGenThreads { embedBitcode(IGM->getModule(), parent.irgen->Opts); performLLVM(parent.irgen->Opts, IGM->Context.Diags, diagMutex, IGM->ModuleHash, IGM->getModule(), IGM->TargetMachine.get(), - IGM->Context.LangOpts.EffectiveLanguageVersion, IGM->OutputFilename, IGM->Context.Stats); if (IGM->Context.Diags.hadAnyError()) return; @@ -1311,9 +1312,12 @@ GeneratedModule swift::performIRGeneration( StringRef ModuleName, const PrimarySpecificPaths &PSPs, ArrayRef parallelOutputFilenames, llvm::GlobalVariable **outModuleHash) { + // Get a pointer to the SILModule to avoid a potential use-after-move. + const auto *SILModPtr = SILMod.get(); + const auto &SILOpts = SILModPtr->getOptions(); auto desc = IRGenDescriptor::forWholeModule( - M, Opts, TBDOpts, std::move(SILMod), ModuleName, PSPs, - parallelOutputFilenames, outModuleHash); + M, Opts, TBDOpts, SILOpts, SILModPtr->Types, std::move(SILMod), + ModuleName, PSPs, parallelOutputFilenames, outModuleHash); if (Opts.shouldPerformIRGenerationInParallel() && !parallelOutputFilenames.empty()) { @@ -1326,16 +1330,19 @@ GeneratedModule swift::performIRGeneration( } GeneratedModule swift:: -performIRGeneration(SourceFile &SF, const IRGenOptions &Opts, +performIRGeneration(FileUnit *file, const IRGenOptions &Opts, const TBDGenOptions &TBDOpts, std::unique_ptr SILMod, StringRef ModuleName, const PrimarySpecificPaths &PSPs, StringRef PrivateDiscriminator, llvm::GlobalVariable **outModuleHash) { - auto desc = IRGenDescriptor::forFile(SF, Opts, TBDOpts, std::move(SILMod), - ModuleName, PSPs, PrivateDiscriminator, - outModuleHash); - return llvm::cantFail(SF.getASTContext().evaluator(IRGenRequest{desc})); + // Get a pointer to the SILModule to avoid a potential use-after-move. + const auto *SILModPtr = SILMod.get(); + const auto &SILOpts = SILModPtr->getOptions(); + auto desc = IRGenDescriptor::forFile( + file, Opts, TBDOpts, SILOpts, SILModPtr->Types, std::move(SILMod), + ModuleName, PSPs, PrivateDiscriminator, outModuleHash); + return llvm::cantFail(file->getASTContext().evaluator(IRGenRequest{desc})); } void @@ -1388,7 +1395,6 @@ swift::createSwiftModuleObjectFile(SILModule &SILMod, StringRef Buffer, ASTSym->setAlignment(llvm::MaybeAlign(serialization::SWIFTMODULE_ALIGNMENT)); ::performLLVM(Opts, Ctx.Diags, nullptr, nullptr, IGM.getModule(), IGM.TargetMachine.get(), - Ctx.LangOpts.EffectiveLanguageVersion, OutputPath, Ctx.Stats); } @@ -1406,8 +1412,58 @@ bool swift::performLLVM(const IRGenOptions &Opts, ASTContext &Ctx, embedBitcode(Module, Opts); if (::performLLVM(Opts, Ctx.Diags, nullptr, nullptr, Module, TargetMachine.get(), - Ctx.LangOpts.EffectiveLanguageVersion, OutputFilename, Ctx.Stats)) return true; return false; } + +GeneratedModule OptimizedIRRequest::evaluate(Evaluator &evaluator, + IRGenDescriptor desc) const { + auto *parentMod = desc.getParentModule(); + auto &ctx = parentMod->getASTContext(); + + // Resolve imports for all the source files. + for (auto *file : parentMod->getFiles()) { + if (auto *SF = dyn_cast(file)) + performImportResolution(*SF); + } + + bindExtensions(*parentMod); + + // Type-check the files that need lowering to SIL. + auto loweringDesc = ASTLoweringDescriptor{desc.Ctx, desc.Conv, desc.SILOpts}; + for (auto *file : loweringDesc.getFiles()) { + if (auto *SF = dyn_cast(file)) + performTypeChecking(*SF); + } + + if (ctx.hadError()) + return GeneratedModule::null(); + + auto silMod = llvm::cantFail(evaluator(ASTLoweringRequest{loweringDesc})); + silMod->installSILRemarkStreamer(); + silMod->setSerializeSILAction([](){}); + + // Run SIL passes. + runSILDiagnosticPasses(*silMod); + runSILOptimizationPasses(*silMod); + silMod->verify(); + + if (ctx.hadError()) + return GeneratedModule::null(); + + runSILLoweringPasses(*silMod); + + if (ctx.hadError()) + return GeneratedModule::null(); + + // Perform IRGen with the generated SILModule. + desc.SILMod = silMod.release(); + auto irMod = llvm::cantFail(evaluator(IRGenRequest{desc})); + if (!irMod) + return irMod; + + performLLVMOptimizations(desc.Opts, irMod.getModule(), + irMod.getTargetMachine()); + return irMod; +} diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index f9545f7c9a366..c11bcbae11950 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -934,6 +934,7 @@ GeneratedModule IRGenModule::intoGeneratedModule() && { return GeneratedModule{ std::move(LLVMContext), std::unique_ptr{ClangCodeGen->ReleaseModule()}, + std::move(TargetMachine) }; } diff --git a/lib/IRGen/IRGenRequests.cpp b/lib/IRGen/IRGenRequests.cpp index 5e9f9a7c81851..7cff6f7782837 100644 --- a/lib/IRGen/IRGenRequests.cpp +++ b/lib/IRGen/IRGenRequests.cpp @@ -39,13 +39,12 @@ llvm::orc::ThreadSafeModule GeneratedModule::intoThreadSafeContext() && { void swift::simple_display(llvm::raw_ostream &out, const IRGenDescriptor &desc) { auto *MD = desc.Ctx.dyn_cast(); - auto *SF = desc.Ctx.dyn_cast(); if (MD) { out << "IR Generation for module " << MD->getName(); } else { - assert(SF); + auto *file = desc.Ctx.get(); out << "IR Generation for file "; - out << '\"' << SF->getFilename() << '\"'; + simple_display(out, file); } } @@ -58,29 +57,30 @@ TinyPtrVector IRGenDescriptor::getFiles() const { if (auto *mod = Ctx.dyn_cast()) return TinyPtrVector(mod->getFiles()); - // For a primary source file, we emit IR for both it and potentially its + // For a primary file, we emit IR for both it and potentially its // SynthesizedFileUnit. - auto *SF = Ctx.get(); + auto *primary = Ctx.get(); TinyPtrVector files; - files.push_back(SF); - - if (auto *synthesizedFile = SF->getSynthesizedFile()) - files.push_back(synthesizedFile); + files.push_back(primary); + if (auto *SF = dyn_cast(primary)) { + if (auto *synthesizedFile = SF->getSynthesizedFile()) + files.push_back(synthesizedFile); + } return files; } ModuleDecl *IRGenDescriptor::getParentModule() const { - if (auto *SF = Ctx.dyn_cast()) - return SF->getParentModule(); + if (auto *file = Ctx.dyn_cast()) + return file->getParentModule(); return Ctx.get(); } std::vector IRGenDescriptor::getLinkerDirectives() const { auto opts = TBDOpts; opts.LinkerDirectivesOnly = true; - if (auto *SF = Ctx.dyn_cast()) { - return getPublicSymbols(TBDGenDescriptor::forFile(SF, opts)); + if (auto *file = Ctx.dyn_cast()) { + return getPublicSymbols(TBDGenDescriptor::forFile(file, opts)); } else { auto *M = Ctx.get(); return getPublicSymbols(TBDGenDescriptor::forModule(M, opts)); @@ -96,8 +96,8 @@ evaluator::DependencySource IRGenRequest::readDependencySource( return {nullptr, e.getActiveSourceScope()}; } - auto *SF = desc.Ctx.get(); - return {SF, evaluator::DependencyScope::Cascading}; + auto *primary = desc.Ctx.get(); + return {dyn_cast(primary), evaluator::DependencyScope::Cascading}; } // Define request evaluation functions for each of the IRGen requests. diff --git a/lib/Immediate/Immediate.cpp b/lib/Immediate/Immediate.cpp index a2cead40c0707..5ac87f6f42397 100644 --- a/lib/Immediate/Immediate.cpp +++ b/lib/Immediate/Immediate.cpp @@ -196,6 +196,7 @@ int swift::RunImmediately(CompilerInstance &CI, const IRGenOptions &IRGenOpts, const SILOptions &SILOpts, std::unique_ptr &&SM) { + // TODO: Use OptimizedIRRequest for this. ASTContext &Context = CI.getASTContext(); // IRGen the main module. @@ -211,6 +212,13 @@ int swift::RunImmediately(CompilerInstance &CI, assert(GenModule && "Emitted no diagnostics but IR generation failed?"); + performLLVM(IRGenOpts, Context.Diags, /*diagMutex*/ nullptr, /*hash*/ nullptr, + GenModule.getModule(), GenModule.getTargetMachine(), + PSPs.OutputFilename, Context.Stats); + + if (Context.hadError()) + return -1; + // Load libSwiftCore to setup process arguments. // // This must be done here, before any library loading has been done, to avoid diff --git a/tools/sil-llvm-gen/SILLLVMGen.cpp b/tools/sil-llvm-gen/SILLLVMGen.cpp index 04b505c904b62..3778cedc37842 100644 --- a/tools/sil-llvm-gen/SILLLVMGen.cpp +++ b/tools/sil-llvm-gen/SILLLVMGen.cpp @@ -178,28 +178,42 @@ int main(int argc, char **argv) { if (CI.setup(Invocation)) return 1; - CI.performSema(); - - // If parsing produced an error, don't run any passes. - if (CI.getASTContext().hadError()) + std::error_code EC; + llvm::raw_fd_ostream outStream(OutputFilename, EC, llvm::sys::fs::F_None); + if (outStream.has_error() || EC) { + CI.getDiags().diagnose(SourceLoc(), diag::error_opening_output, + OutputFilename, EC.message()); + outStream.clear_error(); return 1; + } auto *mod = CI.getMainModule(); assert(mod->getFiles().size() == 1); - std::unique_ptr SILMod; - if (PerformWMO) { - SILMod = performASTLowering(mod, CI.getSILTypes(), CI.getSILOptions()); - } else { - SILMod = performASTLowering(*mod->getFiles()[0], CI.getSILTypes(), - CI.getSILOptions()); - } + auto getDescriptor = [&]() -> IRGenDescriptor { + const auto &TBDOpts = Invocation.getTBDGenOptions(); + const auto &SILOpts = Invocation.getSILOptions(); + auto &SILTypes = CI.getSILTypes(); + auto moduleName = CI.getMainModule()->getName().str(); + const PrimarySpecificPaths PSPs(OutputFilename, InputFilename); + + if (PerformWMO) { + 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*/ ""); + } + }; + + auto &eval = CI.getASTContext().evaluator; + auto generatedMod = llvm::cantFail(eval(OptimizedIRRequest{getDescriptor()})); + if (!generatedMod) + return 1; - const PrimarySpecificPaths PSPs(OutputFilename, InputFilename); - auto Mod = performIRGeneration(CI.getMainModule(), Opts, - CI.getInvocation().getTBDGenOptions(), - std::move(SILMod), - CI.getMainModule()->getName().str(), PSPs, - ArrayRef()); - return CI.getASTContext().hadError(); + return compileAndWriteLLVM(generatedMod.getModule(), + generatedMod.getTargetMachine(), Opts, + CI.getStatsReporter(), CI.getDiags(), outStream); }