/// Performs the compile requested by the user. /// \returns true on error static bool performCompile(CompilerInstance &Instance, CompilerInvocation &Invocation, ArrayRef<const char *> Args, int &ReturnValue) { FrontendOptions opts = Invocation.getFrontendOptions(); FrontendOptions::ActionType Action = opts.RequestedAction; IRGenOptions &IRGenOpts = Invocation.getIRGenOptions(); bool inputIsLLVMIr = Invocation.getInputKind() == InputFileKind::IFK_LLVM_IR; if (inputIsLLVMIr) { auto &LLVMContext = llvm::getGlobalContext(); // Load in bitcode file. assert(Invocation.getInputFilenames().size() == 1 && "We expect a single input for bitcode input!"); llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr = llvm::MemoryBuffer::getFileOrSTDIN(Invocation.getInputFilenames()[0]); if (!FileBufOrErr) { Instance.getASTContext().Diags.diagnose(SourceLoc(), diag::error_open_input_file, Invocation.getInputFilenames()[0], FileBufOrErr.getError().message()); return true; } llvm::MemoryBuffer *MainFile = FileBufOrErr.get().get(); llvm::SMDiagnostic Err; std::unique_ptr<llvm::Module> Module = llvm::parseIR( MainFile->getMemBufferRef(), Err, LLVMContext); if (!Module) { // TODO: Translate from the diagnostic info to the SourceManager location // if available. Instance.getASTContext().Diags.diagnose(SourceLoc(), diag::error_parse_input_file, Invocation.getInputFilenames()[0], Err.getMessage()); return true; } // TODO: remove once the frontend understands what action it should perform IRGenOpts.OutputKind = getOutputKind(Action); return performLLVM(IRGenOpts, Instance.getASTContext(), Module.get()); } ReferencedNameTracker nameTracker; bool shouldTrackReferences = !opts.ReferenceDependenciesFilePath.empty(); if (shouldTrackReferences) Instance.setReferencedNameTracker(&nameTracker); if (Action == FrontendOptions::DumpParse || Action == FrontendOptions::DumpInterfaceHash) Instance.performParseOnly(); else Instance.performSema(); FrontendOptions::DebugCrashMode CrashMode = opts.CrashMode; if (CrashMode == FrontendOptions::DebugCrashMode::AssertAfterParse) debugFailWithAssertion(); else if (CrashMode == FrontendOptions::DebugCrashMode::CrashAfterParse) debugFailWithCrash(); ASTContext &Context = Instance.getASTContext(); if (Action == FrontendOptions::REPL) { runREPL(Instance, ProcessCmdLine(Args.begin(), Args.end()), Invocation.getParseStdlib()); return false; } SourceFile *PrimarySourceFile = Instance.getPrimarySourceFile(); // We've been told to dump the AST (either after parsing or type-checking, // which is already differentiated in CompilerInstance::performSema()), // so dump or print the main source file and return. if (Action == FrontendOptions::DumpParse || Action == FrontendOptions::DumpAST || Action == FrontendOptions::PrintAST || Action == FrontendOptions::DumpTypeRefinementContexts || Action == FrontendOptions::DumpInterfaceHash) { SourceFile *SF = PrimarySourceFile; if (!SF) { SourceFileKind Kind = Invocation.getSourceFileKind(); SF = &Instance.getMainModule()->getMainSourceFile(Kind); } if (Action == FrontendOptions::PrintAST) SF->print(llvm::outs(), PrintOptions::printEverything()); else if (Action == FrontendOptions::DumpTypeRefinementContexts) SF->getTypeRefinementContext()->dump(llvm::errs(), Context.SourceMgr); else if (Action == FrontendOptions::DumpInterfaceHash) SF->dumpInterfaceHash(llvm::errs()); else SF->dump(); return false; } // If we were asked to print Clang stats, do so. if (opts.PrintClangStats && Context.getClangModuleLoader()) Context.getClangModuleLoader()->printStatistics(); if (!opts.DependenciesFilePath.empty()) (void)emitMakeDependencies(Context.Diags, *Instance.getDependencyTracker(), opts); if (shouldTrackReferences) emitReferenceDependencies(Context.Diags, Instance.getPrimarySourceFile(), *Instance.getDependencyTracker(), opts); if (Context.hadError()) return true; // FIXME: This is still a lousy approximation of whether the module file will // be externally consumed. bool moduleIsPublic = !Instance.getMainModule()->hasEntryPoint() && opts.ImplicitObjCHeaderPath.empty() && !Context.LangOpts.EnableAppExtensionRestrictions; // We've just been told to perform a parse, so we can return now. if (Action == FrontendOptions::Parse) { if (!opts.ObjCHeaderOutputPath.empty()) return printAsObjC(opts.ObjCHeaderOutputPath, Instance.getMainModule(), opts.ImplicitObjCHeaderPath, moduleIsPublic); return false; } assert(Action >= FrontendOptions::EmitSILGen && "All actions not requiring SILGen must have been handled!"); std::unique_ptr<SILModule> SM = Instance.takeSILModule(); if (!SM) { if (opts.PrimaryInput.hasValue() && opts.PrimaryInput.getValue().isFilename()) { FileUnit *PrimaryFile = PrimarySourceFile; if (!PrimaryFile) { auto Index = opts.PrimaryInput.getValue().Index; PrimaryFile = Instance.getMainModule()->getFiles()[Index]; } SM = performSILGeneration(*PrimaryFile, Invocation.getSILOptions(), None, opts.SILSerializeAll); } else { SM = performSILGeneration(Instance.getMainModule(), Invocation.getSILOptions(), opts.SILSerializeAll, true); } } // We've been told to emit SIL after SILGen, so write it now. if (Action == FrontendOptions::EmitSILGen) { // If we are asked to link all, link all. if (Invocation.getSILOptions().LinkMode == SILOptions::LinkAll) performSILLinking(SM.get(), true); return writeSIL(*SM, Instance.getMainModule(), opts.EmitVerboseSIL, opts.getSingleOutputFilename(), opts.EmitSortedSIL); } if (Action == FrontendOptions::EmitSIBGen) { // If we are asked to link all, link all. if (Invocation.getSILOptions().LinkMode == SILOptions::LinkAll) performSILLinking(SM.get(), true); auto DC = PrimarySourceFile ? ModuleOrSourceFile(PrimarySourceFile) : Instance.getMainModule(); if (!opts.ModuleOutputPath.empty()) { SerializationOptions serializationOpts; serializationOpts.OutputPath = opts.ModuleOutputPath.c_str(); serializationOpts.SerializeAllSIL = true; serializationOpts.IsSIB = true; serialize(DC, serializationOpts, SM.get()); } return false; } // Perform "stable" optimizations that are invariant across compiler versions. if (!Invocation.getDiagnosticOptions().SkipDiagnosticPasses && runSILDiagnosticPasses(*SM)) return true; // Now if we are asked to link all, link all. if (Invocation.getSILOptions().LinkMode == SILOptions::LinkAll) performSILLinking(SM.get(), true); SM->verify(); // Perform SIL optimization passes if optimizations haven't been disabled. // These may change across compiler versions. if (IRGenOpts.Optimize) { StringRef CustomPipelinePath = Invocation.getSILOptions().ExternalPassPipelineFilename; if (!CustomPipelinePath.empty()) { runSILOptimizationPassesWithFileSpecification(*SM, CustomPipelinePath); } else { runSILOptimizationPasses(*SM); } } else { runSILPassesForOnone(*SM); } SM->verify(); // Gather instruction counts if we are asked to do so. if (SM->getOptions().PrintInstCounts) { performSILInstCount(&*SM); } // Get the main source file's private discriminator and attach it to // the compile unit's flags. if (PrimarySourceFile) { Identifier PD = PrimarySourceFile->getPrivateDiscriminator(); if (!PD.empty()) IRGenOpts.DWARFDebugFlags += (" -private-discriminator "+PD.str()).str(); } if (!opts.ObjCHeaderOutputPath.empty()) { (void)printAsObjC(opts.ObjCHeaderOutputPath, Instance.getMainModule(), opts.ImplicitObjCHeaderPath, moduleIsPublic); } if (Action == FrontendOptions::EmitSIB) { auto DC = PrimarySourceFile ? ModuleOrSourceFile(PrimarySourceFile) : Instance.getMainModule(); if (!opts.ModuleOutputPath.empty()) { SerializationOptions serializationOpts; serializationOpts.OutputPath = opts.ModuleOutputPath.c_str(); serializationOpts.SerializeAllSIL = true; serializationOpts.IsSIB = true; serialize(DC, serializationOpts, SM.get()); } return false; } if (!opts.ModuleOutputPath.empty() || !opts.ModuleDocOutputPath.empty()) { auto DC = PrimarySourceFile ? ModuleOrSourceFile(PrimarySourceFile) : Instance.getMainModule(); if (!opts.ModuleOutputPath.empty()) { SerializationOptions serializationOpts; serializationOpts.OutputPath = opts.ModuleOutputPath.c_str(); serializationOpts.DocOutputPath = opts.ModuleDocOutputPath.c_str(); serializationOpts.SerializeAllSIL = opts.SILSerializeAll; if (opts.SerializeBridgingHeader) serializationOpts.ImportedHeader = opts.ImplicitObjCHeaderPath; serializationOpts.ModuleLinkName = opts.ModuleLinkName; serializationOpts.ExtraClangOptions = Invocation.getClangImporterOptions().ExtraArgs; if (!IRGenOpts.ForceLoadSymbolName.empty()) serializationOpts.AutolinkForceLoad = true; // Options contain information about the developer's computer, // so only serialize them if the module isn't going to be shipped to // the public. serializationOpts.SerializeOptionsForDebugging = !moduleIsPublic || opts.AlwaysSerializeDebuggingOptions; serialize(DC, serializationOpts, SM.get()); } if (Action == FrontendOptions::EmitModuleOnly) return false; } assert(Action >= FrontendOptions::EmitSIL && "All actions not requiring SILPasses must have been handled!"); // We've been told to write canonical SIL, so write it now. if (Action == FrontendOptions::EmitSIL) { return writeSIL(*SM, Instance.getMainModule(), opts.EmitVerboseSIL, opts.getSingleOutputFilename(), opts.EmitSortedSIL); } assert(Action >= FrontendOptions::Immediate && "All actions not requiring IRGen must have been handled!"); assert(Action != FrontendOptions::REPL && "REPL mode must be handled immediately after Instance.performSema()"); // Check if we had any errors; if we did, don't proceed to IRGen. if (Context.hadError()) return true; // Cleanup instructions/builtin calls not suitable for IRGen. performSILCleanup(SM.get()); // TODO: remove once the frontend understands what action it should perform IRGenOpts.OutputKind = getOutputKind(Action); if (Action == FrontendOptions::Immediate) { assert(!PrimarySourceFile && "-i doesn't work in -primary-file mode"); IRGenOpts.UseJIT = true; IRGenOpts.DebugInfoKind = IRGenDebugInfoKind::Normal; const ProcessCmdLine &CmdLine = ProcessCmdLine(opts.ImmediateArgv.begin(), opts.ImmediateArgv.end()); Instance.setSILModule(std::move(SM)); ReturnValue = RunImmediately(Instance, CmdLine, IRGenOpts, Invocation.getSILOptions()); return false; } // FIXME: We shouldn't need to use the global context here, but // something is persisting across calls to performIRGeneration. auto &LLVMContext = llvm::getGlobalContext(); if (PrimarySourceFile) { performIRGeneration(IRGenOpts, *PrimarySourceFile, SM.get(), opts.getSingleOutputFilename(), LLVMContext); } else { performIRGeneration(IRGenOpts, Instance.getMainModule(), SM.get(), opts.getSingleOutputFilename(), LLVMContext); } return false; }
int main(int argc, char **argv) { INITIALIZE_LLVM(argc, argv); llvm::cl::ParseCommandLineOptions(argc, argv, "Swift LLVM IR Generator\n"); if (PrintStats) llvm::EnableStatistics(); CompilerInvocation Invocation; Invocation.setMainExecutablePath(llvm::sys::fs::getMainExecutable( argv[0], reinterpret_cast<void *>(&anchorForGetMainExecutable))); // Give the context the list of search paths to use for modules. Invocation.setImportSearchPaths(ImportPaths); Invocation.setFrameworkSearchPaths(FrameworkPaths); // Set the SDK path and target if given. if (SDKPath.getNumOccurrences() == 0) { const char *SDKROOT = getenv("SDKROOT"); if (SDKROOT) SDKPath = SDKROOT; } if (!SDKPath.empty()) Invocation.setSDKPath(SDKPath); if (!Target.empty()) Invocation.setTargetTriple(Target); if (!ResourceDir.empty()) Invocation.setRuntimeResourcePath(ResourceDir); // Set the module cache path. If not passed in we use the default swift module // cache. Invocation.getClangImporterOptions().ModuleCachePath = 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(); // Setup the SIL Options. SILOptions &SILOpts = Invocation.getSILOptions(); SILOpts.AssumeUnqualifiedOwnershipWhenParsing = AssumeUnqualifiedOwnershipWhenParsing; // Setup the IRGen Options. IRGenOptions &Opts = Invocation.getIRGenOptions(); Opts.MainInputFilename = InputFilename; Opts.OutputFilenames.push_back(OutputFilename); Opts.OutputKind = OutputKind; // Load the input file. llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr = llvm::MemoryBuffer::getFileOrSTDIN(InputFilename); if (!FileBufOrErr) { fprintf(stderr, "Error! Failed to open file: %s\n", InputFilename.c_str()); exit(-1); } // If it looks like we have an AST, set the source file kind to SIL and the // name of the module to the file's name. Invocation.addInputBuffer(FileBufOrErr.get().get()); serialization::ExtendedValidationInfo extendedInfo; auto result = serialization::validateSerializedAST( FileBufOrErr.get()->getBuffer(), &extendedInfo); bool HasSerializedAST = result.status == serialization::Status::Valid; if (HasSerializedAST) { const StringRef Stem = ModuleName.size() ? StringRef(ModuleName) : llvm::sys::path::stem(InputFilename); Invocation.setModuleName(Stem); Invocation.setInputKind(InputFileKind::IFK_Swift_Library); } else { const StringRef Name = ModuleName.size() ? StringRef(ModuleName) : "main"; Invocation.setModuleName(Name); Invocation.setInputKind(InputFileKind::IFK_SIL); } CompilerInstance CI; PrintingDiagnosticConsumer PrintDiags; CI.addDiagnosticConsumer(&PrintDiags); if (!PerformWMO) { auto &FrontendOpts = Invocation.getFrontendOptions(); if (!InputFilename.empty() && InputFilename != "-") { FrontendOpts.PrimaryInput = SelectedInput(FrontendOpts.InputFilenames.size()); } else { FrontendOpts.PrimaryInput = SelectedInput( FrontendOpts.InputBuffers.size(), SelectedInput::InputKind::Buffer); } } if (CI.setup(Invocation)) return 1; CI.performSema(); // If parsing produced an error, don't run any passes. if (CI.getASTContext().hadError()) return 1; // Load the SIL if we have a module. We have to do this after SILParse // creating the unfortunate double if statement. if (HasSerializedAST) { assert(!CI.hasSILModule() && "performSema() should not create a SILModule."); CI.setSILModule(SILModule::createEmptyModule( CI.getMainModule(), CI.getSILOptions(), PerformWMO)); std::unique_ptr<SerializedSILLoader> SL = SerializedSILLoader::create( CI.getASTContext(), CI.getSILModule(), nullptr); if (extendedInfo.isSIB()) SL->getAllForModule(CI.getMainModule()->getName(), nullptr); else SL->getAll(); } std::unique_ptr<llvm::Module> Mod = performIRGeneration( Opts, CI.getMainModule(), CI.takeSILModule(), CI.getMainModule()->getName().str(), getGlobalLLVMContext()); return CI.getASTContext().hadError(); }
int swift::performFrontend(ArrayRef<const char *> Args, const char *Argv0, void *MainAddr, FrontendObserver *observer) { llvm::InitializeAllTargets(); llvm::InitializeAllTargetMCs(); llvm::InitializeAllAsmPrinters(); llvm::InitializeAllAsmParsers(); std::unique_ptr<CompilerInstance> Instance = llvm::make_unique<CompilerInstance>(); PrintingDiagnosticConsumer PDC; Instance->addDiagnosticConsumer(&PDC); if (Args.empty()) { Instance->getDiags().diagnose(SourceLoc(), diag::error_no_frontend_args); return 1; } CompilerInvocation Invocation; std::string MainExecutablePath = llvm::sys::fs::getMainExecutable(Argv0, MainAddr); Invocation.setMainExecutablePath(MainExecutablePath); SmallString<128> workingDirectory; llvm::sys::fs::current_path(workingDirectory); // Parse arguments. if (Invocation.parseArgs(Args, Instance->getDiags(), workingDirectory)) { return 1; } // Setting DWARF Version depend on platform IRGenOptions &IRGenOpts = Invocation.getIRGenOptions(); IRGenOpts.DWARFVersion = swift::DWARFVersion; // The compiler invocation is now fully configured; notify our observer. if (observer) { observer->parsedArgs(Invocation); } if (Invocation.getFrontendOptions().PrintHelp || Invocation.getFrontendOptions().PrintHelpHidden) { unsigned IncludedFlagsBitmask = options::FrontendOption; unsigned ExcludedFlagsBitmask = Invocation.getFrontendOptions().PrintHelpHidden ? 0 : llvm::opt::HelpHidden; std::unique_ptr<llvm::opt::OptTable> Options(createSwiftOptTable()); Options->PrintHelp(llvm::outs(), displayName(MainExecutablePath).c_str(), "Swift frontend", IncludedFlagsBitmask, ExcludedFlagsBitmask); return 0; } if (Invocation.getFrontendOptions().RequestedAction == FrontendOptions::NoneAction) { Instance->getDiags().diagnose(SourceLoc(), diag::error_missing_frontend_action); return 1; } // Because the serialized diagnostics consumer is initialized here, // diagnostics emitted above, within CompilerInvocation::parseArgs, are never // serialized. This is a non-issue because, in nearly all cases, frontend // arguments are generated by the driver, not directly by a user. The driver // is responsible for emitting diagnostics for its own errors. See SR-2683 // for details. std::unique_ptr<DiagnosticConsumer> SerializedConsumer; { const std::string &SerializedDiagnosticsPath = Invocation.getFrontendOptions().SerializedDiagnosticsPath; if (!SerializedDiagnosticsPath.empty()) { std::error_code EC; std::unique_ptr<llvm::raw_fd_ostream> OS; OS.reset(new llvm::raw_fd_ostream(SerializedDiagnosticsPath, EC, llvm::sys::fs::F_None)); if (EC) { Instance->getDiags().diagnose(SourceLoc(), diag::cannot_open_serialized_file, SerializedDiagnosticsPath, EC.message()); return 1; } SerializedConsumer.reset( serialized_diagnostics::createConsumer(std::move(OS))); Instance->addDiagnosticConsumer(SerializedConsumer.get()); } } std::unique_ptr<DiagnosticConsumer> FixitsConsumer; { const std::string &FixitsOutputPath = Invocation.getFrontendOptions().FixitsOutputPath; if (!FixitsOutputPath.empty()) { std::error_code EC; std::unique_ptr<llvm::raw_fd_ostream> OS; OS.reset(new llvm::raw_fd_ostream(FixitsOutputPath, EC, llvm::sys::fs::F_None)); if (EC) { Instance->getDiags().diagnose(SourceLoc(), diag::cannot_open_file, FixitsOutputPath, EC.message()); return 1; } FixitsConsumer.reset(new JSONFixitWriter(std::move(OS), Invocation.getDiagnosticOptions())); Instance->addDiagnosticConsumer(FixitsConsumer.get()); } } if (Invocation.getDiagnosticOptions().UseColor) PDC.forceColors(); if (Invocation.getFrontendOptions().DebugTimeCompilation) SharedTimer::enableCompilationTimers(); if (Invocation.getFrontendOptions().PrintStats) { llvm::EnableStatistics(); } const DiagnosticOptions &diagOpts = Invocation.getDiagnosticOptions(); if (diagOpts.VerifyMode != DiagnosticOptions::NoVerify) { enableDiagnosticVerifier(Instance->getSourceMgr()); } DependencyTracker depTracker; if (!Invocation.getFrontendOptions().DependenciesFilePath.empty() || !Invocation.getFrontendOptions().ReferenceDependenciesFilePath.empty()) { Instance->setDependencyTracker(&depTracker); } if (Instance->setup(Invocation)) { return 1; } // The compiler instance has been configured; notify our observer. if (observer) { observer->configuredCompiler(*Instance); } int ReturnValue = 0; bool HadError = performCompile(Instance, Invocation, Args, ReturnValue, observer); if (!HadError) { NewMangling::printManglingStats(); } if (!HadError && !Invocation.getFrontendOptions().DumpAPIPath.empty()) { HadError = dumpAPI(Instance->getMainModule(), Invocation.getFrontendOptions().DumpAPIPath); } if (diagOpts.VerifyMode != DiagnosticOptions::NoVerify) { HadError = verifyDiagnostics( Instance->getSourceMgr(), Instance->getInputBufferIDs(), diagOpts.VerifyMode == DiagnosticOptions::VerifyAndApplyFixes); DiagnosticEngine &diags = Instance->getDiags(); if (diags.hasFatalErrorOccurred() && !Invocation.getDiagnosticOptions().ShowDiagnosticsAfterFatalError) { diags.resetHadAnyError(); diags.diagnose(SourceLoc(), diag::verify_encountered_fatal); HadError = true; } } return (HadError ? 1 : ReturnValue); }
int swift::performFrontend(ArrayRef<const char *> Args, const char *Argv0, void *MainAddr, FrontendObserver *observer) { llvm::InitializeAllTargets(); llvm::InitializeAllTargetMCs(); llvm::InitializeAllAsmPrinters(); llvm::InitializeAllAsmParsers(); CompilerInstance Instance; PrintingDiagnosticConsumer PDC; Instance.addDiagnosticConsumer(&PDC); if (Args.empty()) { Instance.getDiags().diagnose(SourceLoc(), diag::error_no_frontend_args); return 1; } CompilerInvocation Invocation; std::string MainExecutablePath = llvm::sys::fs::getMainExecutable(Argv0, MainAddr); Invocation.setMainExecutablePath(MainExecutablePath); SmallString<128> workingDirectory; llvm::sys::fs::current_path(workingDirectory); // Parse arguments. if (Invocation.parseArgs(Args, Instance.getDiags(), workingDirectory)) { return 1; } // Setting DWARF Version depend on platform IRGenOptions &IRGenOpts = Invocation.getIRGenOptions(); IRGenOpts.DWARFVersion = swift::GenericDWARFVersion; if (Invocation.getLangOptions().Target.isWindowsCygwinEnvironment()) IRGenOpts.DWARFVersion = swift::CygwinDWARFVersion; // The compiler invocation is now fully configured; notify our observer. if (observer) { observer->parsedArgs(Invocation); } if (Invocation.getFrontendOptions().PrintHelp || Invocation.getFrontendOptions().PrintHelpHidden) { unsigned IncludedFlagsBitmask = options::FrontendOption; unsigned ExcludedFlagsBitmask = Invocation.getFrontendOptions().PrintHelpHidden ? 0 : llvm::opt::HelpHidden; std::unique_ptr<llvm::opt::OptTable> Options(createSwiftOptTable()); Options->PrintHelp(llvm::outs(), displayName(MainExecutablePath).c_str(), "Swift frontend", IncludedFlagsBitmask, ExcludedFlagsBitmask); return 0; } if (Invocation.getFrontendOptions().RequestedAction == FrontendOptions::NoneAction) { Instance.getDiags().diagnose(SourceLoc(), diag::error_missing_frontend_action); return 1; } // TODO: reorder, if possible, so that diagnostics emitted during // CompilerInvocation::parseArgs are included in the serialized file. std::unique_ptr<DiagnosticConsumer> SerializedConsumer; { const std::string &SerializedDiagnosticsPath = Invocation.getFrontendOptions().SerializedDiagnosticsPath; if (!SerializedDiagnosticsPath.empty()) { std::error_code EC; std::unique_ptr<llvm::raw_fd_ostream> OS; OS.reset(new llvm::raw_fd_ostream(SerializedDiagnosticsPath, EC, llvm::sys::fs::F_None)); if (EC) { Instance.getDiags().diagnose(SourceLoc(), diag::cannot_open_serialized_file, SerializedDiagnosticsPath, EC.message()); return 1; } SerializedConsumer.reset( serialized_diagnostics::createConsumer(std::move(OS))); Instance.addDiagnosticConsumer(SerializedConsumer.get()); } } std::unique_ptr<DiagnosticConsumer> FixitsConsumer; { const std::string &FixitsOutputPath = Invocation.getFrontendOptions().FixitsOutputPath; if (!FixitsOutputPath.empty()) { std::error_code EC; std::unique_ptr<llvm::raw_fd_ostream> OS; OS.reset(new llvm::raw_fd_ostream(FixitsOutputPath, EC, llvm::sys::fs::F_None)); if (EC) { Instance.getDiags().diagnose(SourceLoc(), diag::cannot_open_file, FixitsOutputPath, EC.message()); return 1; } FixitsConsumer.reset(new JSONFixitWriter(std::move(OS), Invocation.getDiagnosticOptions())); Instance.addDiagnosticConsumer(FixitsConsumer.get()); } } if (Invocation.getDiagnosticOptions().UseColor) PDC.forceColors(); if (Invocation.getFrontendOptions().DebugTimeCompilation) SharedTimer::enableCompilationTimers(); if (Invocation.getFrontendOptions().PrintStats) { llvm::EnableStatistics(); } if (Invocation.getDiagnosticOptions().VerifyDiagnostics) { enableDiagnosticVerifier(Instance.getSourceMgr()); } DependencyTracker depTracker; if (!Invocation.getFrontendOptions().DependenciesFilePath.empty() || !Invocation.getFrontendOptions().ReferenceDependenciesFilePath.empty()) { Instance.setDependencyTracker(&depTracker); } if (Instance.setup(Invocation)) { return 1; } // The compiler instance has been configured; notify our observer. if (observer) { observer->configuredCompiler(Instance); } int ReturnValue = 0; bool HadError = performCompile(Instance, Invocation, Args, ReturnValue, observer) || Instance.getASTContext().hadError(); if (!HadError && !Invocation.getFrontendOptions().DumpAPIPath.empty()) { HadError = dumpAPI(Instance.getMainModule(), Invocation.getFrontendOptions().DumpAPIPath); } if (Invocation.getDiagnosticOptions().VerifyDiagnostics) { HadError = verifyDiagnostics(Instance.getSourceMgr(), Instance.getInputBufferIDs()); DiagnosticEngine &diags = Instance.getDiags(); if (diags.hasFatalErrorOccurred() && !Invocation.getDiagnosticOptions().ShowDiagnosticsAfterFatalError) { diags.resetHadAnyError(); diags.diagnose(SourceLoc(), diag::verify_encountered_fatal); HadError = true; } } return (HadError ? 1 : ReturnValue); }
/// Performs the compile requested by the user. /// \param Instance Will be reset after performIRGeneration when the verifier /// mode is NoVerify and there were no errors. /// \returns true on error static bool performCompile(std::unique_ptr<CompilerInstance> &Instance, CompilerInvocation &Invocation, ArrayRef<const char *> Args, int &ReturnValue, FrontendObserver *observer) { FrontendOptions opts = Invocation.getFrontendOptions(); FrontendOptions::ActionType Action = opts.RequestedAction; IRGenOptions &IRGenOpts = Invocation.getIRGenOptions(); bool inputIsLLVMIr = Invocation.getInputKind() == InputFileKind::IFK_LLVM_IR; if (inputIsLLVMIr) { auto &LLVMContext = getGlobalLLVMContext(); // Load in bitcode file. assert(Invocation.getInputFilenames().size() == 1 && "We expect a single input for bitcode input!"); llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr = llvm::MemoryBuffer::getFileOrSTDIN(Invocation.getInputFilenames()[0]); if (!FileBufOrErr) { Instance->getASTContext().Diags.diagnose(SourceLoc(), diag::error_open_input_file, Invocation.getInputFilenames()[0], FileBufOrErr.getError().message()); return true; } llvm::MemoryBuffer *MainFile = FileBufOrErr.get().get(); llvm::SMDiagnostic Err; std::unique_ptr<llvm::Module> Module = llvm::parseIR( MainFile->getMemBufferRef(), Err, LLVMContext); if (!Module) { // TODO: Translate from the diagnostic info to the SourceManager location // if available. Instance->getASTContext().Diags.diagnose(SourceLoc(), diag::error_parse_input_file, Invocation.getInputFilenames()[0], Err.getMessage()); return true; } // TODO: remove once the frontend understands what action it should perform IRGenOpts.OutputKind = getOutputKind(Action); return performLLVM(IRGenOpts, Instance->getASTContext(), Module.get()); } ReferencedNameTracker nameTracker; bool shouldTrackReferences = !opts.ReferenceDependenciesFilePath.empty(); if (shouldTrackReferences) Instance->setReferencedNameTracker(&nameTracker); if (Action == FrontendOptions::Parse || Action == FrontendOptions::DumpParse || Action == FrontendOptions::DumpInterfaceHash) Instance->performParseOnly(); else Instance->performSema(); if (Action == FrontendOptions::Parse) return Instance->getASTContext().hadError(); if (observer) { observer->performedSemanticAnalysis(*Instance); } FrontendOptions::DebugCrashMode CrashMode = opts.CrashMode; if (CrashMode == FrontendOptions::DebugCrashMode::AssertAfterParse) debugFailWithAssertion(); else if (CrashMode == FrontendOptions::DebugCrashMode::CrashAfterParse) debugFailWithCrash(); ASTContext &Context = Instance->getASTContext(); if (Action == FrontendOptions::REPL) { runREPL(*Instance, ProcessCmdLine(Args.begin(), Args.end()), Invocation.getParseStdlib()); return Context.hadError(); } SourceFile *PrimarySourceFile = Instance->getPrimarySourceFile(); // We've been told to dump the AST (either after parsing or type-checking, // which is already differentiated in CompilerInstance::performSema()), // so dump or print the main source file and return. if (Action == FrontendOptions::DumpParse || Action == FrontendOptions::DumpAST || Action == FrontendOptions::PrintAST || Action == FrontendOptions::DumpScopeMaps || Action == FrontendOptions::DumpTypeRefinementContexts || Action == FrontendOptions::DumpInterfaceHash) { SourceFile *SF = PrimarySourceFile; if (!SF) { SourceFileKind Kind = Invocation.getSourceFileKind(); SF = &Instance->getMainModule()->getMainSourceFile(Kind); } if (Action == FrontendOptions::PrintAST) SF->print(llvm::outs(), PrintOptions::printEverything()); else if (Action == FrontendOptions::DumpScopeMaps) { ASTScope &scope = SF->getScope(); if (opts.DumpScopeMapLocations.empty()) { scope.expandAll(); } else if (auto bufferID = SF->getBufferID()) { SourceManager &sourceMgr = Instance->getSourceMgr(); // Probe each of the locations, and dump what we find. for (auto lineColumn : opts.DumpScopeMapLocations) { SourceLoc loc = sourceMgr.getLocForLineCol(*bufferID, lineColumn.first, lineColumn.second); if (loc.isInvalid()) continue; llvm::errs() << "***Scope at " << lineColumn.first << ":" << lineColumn.second << "***\n"; auto locScope = scope.findInnermostEnclosingScope(loc); locScope->print(llvm::errs(), 0, false, false); // Dump the AST context, too. if (auto dc = locScope->getDeclContext()) { dc->printContext(llvm::errs()); } // Grab the local bindings introduced by this scope. auto localBindings = locScope->getLocalBindings(); if (!localBindings.empty()) { llvm::errs() << "Local bindings: "; interleave(localBindings.begin(), localBindings.end(), [&](ValueDecl *value) { llvm::errs() << value->getFullName(); }, [&]() { llvm::errs() << " "; }); llvm::errs() << "\n"; } } llvm::errs() << "***Complete scope map***\n"; } // Print the resulting map. scope.print(llvm::errs()); } else if (Action == FrontendOptions::DumpTypeRefinementContexts) SF->getTypeRefinementContext()->dump(llvm::errs(), Context.SourceMgr); else if (Action == FrontendOptions::DumpInterfaceHash) SF->dumpInterfaceHash(llvm::errs()); else SF->dump(); return Context.hadError(); } // If we were asked to print Clang stats, do so. if (opts.PrintClangStats && Context.getClangModuleLoader()) Context.getClangModuleLoader()->printStatistics(); if (!opts.DependenciesFilePath.empty()) (void)emitMakeDependencies(Context.Diags, *Instance->getDependencyTracker(), opts); if (shouldTrackReferences) emitReferenceDependencies(Context.Diags, Instance->getPrimarySourceFile(), *Instance->getDependencyTracker(), opts); if (Context.hadError()) return true; // FIXME: This is still a lousy approximation of whether the module file will // be externally consumed. bool moduleIsPublic = !Instance->getMainModule()->hasEntryPoint() && opts.ImplicitObjCHeaderPath.empty() && !Context.LangOpts.EnableAppExtensionRestrictions; // We've just been told to perform a typecheck, so we can return now. if (Action == FrontendOptions::Typecheck) { if (!opts.ObjCHeaderOutputPath.empty()) return printAsObjC(opts.ObjCHeaderOutputPath, Instance->getMainModule(), opts.ImplicitObjCHeaderPath, moduleIsPublic); return Context.hadError(); } assert(Action >= FrontendOptions::EmitSILGen && "All actions not requiring SILGen must have been handled!"); std::unique_ptr<SILModule> SM = Instance->takeSILModule(); if (!SM) { if (opts.PrimaryInput.hasValue() && opts.PrimaryInput.getValue().isFilename()) { FileUnit *PrimaryFile = PrimarySourceFile; if (!PrimaryFile) { auto Index = opts.PrimaryInput.getValue().Index; PrimaryFile = Instance->getMainModule()->getFiles()[Index]; } SM = performSILGeneration(*PrimaryFile, Invocation.getSILOptions(), None, opts.SILSerializeAll); } else { SM = performSILGeneration(Instance->getMainModule(), Invocation.getSILOptions(), opts.SILSerializeAll, true); } } if (observer) { observer->performedSILGeneration(*SM); } // We've been told to emit SIL after SILGen, so write it now. if (Action == FrontendOptions::EmitSILGen) { // If we are asked to link all, link all. if (Invocation.getSILOptions().LinkMode == SILOptions::LinkAll) performSILLinking(SM.get(), true); return writeSIL(*SM, Instance->getMainModule(), opts.EmitVerboseSIL, opts.getSingleOutputFilename(), opts.EmitSortedSIL); } if (Action == FrontendOptions::EmitSIBGen) { // If we are asked to link all, link all. if (Invocation.getSILOptions().LinkMode == SILOptions::LinkAll) performSILLinking(SM.get(), true); auto DC = PrimarySourceFile ? ModuleOrSourceFile(PrimarySourceFile) : Instance->getMainModule(); if (!opts.ModuleOutputPath.empty()) { SerializationOptions serializationOpts; serializationOpts.OutputPath = opts.ModuleOutputPath.c_str(); serializationOpts.SerializeAllSIL = true; serializationOpts.IsSIB = true; serialize(DC, serializationOpts, SM.get()); } return Context.hadError(); } // Perform "stable" optimizations that are invariant across compiler versions. if (!Invocation.getDiagnosticOptions().SkipDiagnosticPasses) { if (runSILDiagnosticPasses(*SM)) return true; if (observer) { observer->performedSILDiagnostics(*SM); } } else { // Even if we are not supposed to run the diagnostic passes, we still need // to run the ownership evaluator. if (runSILOwnershipEliminatorPass(*SM)) return true; } // Now if we are asked to link all, link all. if (Invocation.getSILOptions().LinkMode == SILOptions::LinkAll) performSILLinking(SM.get(), true); { SharedTimer timer("SIL verification (pre-optimization)"); SM->verify(); } // Perform SIL optimization passes if optimizations haven't been disabled. // These may change across compiler versions. { SharedTimer timer("SIL optimization"); if (Invocation.getSILOptions().Optimization > SILOptions::SILOptMode::None) { StringRef CustomPipelinePath = Invocation.getSILOptions().ExternalPassPipelineFilename; if (!CustomPipelinePath.empty()) { runSILOptimizationPassesWithFileSpecification(*SM, CustomPipelinePath); } else { runSILOptimizationPasses(*SM); } } else { runSILPassesForOnone(*SM); } } if (observer) { observer->performedSILOptimization(*SM); } { SharedTimer timer("SIL verification (post-optimization)"); SM->verify(); } // Gather instruction counts if we are asked to do so. if (SM->getOptions().PrintInstCounts) { performSILInstCount(&*SM); } // Get the main source file's private discriminator and attach it to // the compile unit's flags. if (PrimarySourceFile) { Identifier PD = PrimarySourceFile->getPrivateDiscriminator(); if (!PD.empty()) IRGenOpts.DWARFDebugFlags += (" -private-discriminator "+PD.str()).str(); } if (!opts.ObjCHeaderOutputPath.empty()) { (void)printAsObjC(opts.ObjCHeaderOutputPath, Instance->getMainModule(), opts.ImplicitObjCHeaderPath, moduleIsPublic); } if (Action == FrontendOptions::EmitSIB) { auto DC = PrimarySourceFile ? ModuleOrSourceFile(PrimarySourceFile) : Instance->getMainModule(); if (!opts.ModuleOutputPath.empty()) { SerializationOptions serializationOpts; serializationOpts.OutputPath = opts.ModuleOutputPath.c_str(); serializationOpts.SerializeAllSIL = true; serializationOpts.IsSIB = true; serialize(DC, serializationOpts, SM.get()); } return Context.hadError(); } if (!opts.ModuleOutputPath.empty() || !opts.ModuleDocOutputPath.empty()) { auto DC = PrimarySourceFile ? ModuleOrSourceFile(PrimarySourceFile) : Instance->getMainModule(); if (!opts.ModuleOutputPath.empty()) { SerializationOptions serializationOpts; serializationOpts.OutputPath = opts.ModuleOutputPath.c_str(); serializationOpts.DocOutputPath = opts.ModuleDocOutputPath.c_str(); serializationOpts.GroupInfoPath = opts.GroupInfoPath.c_str(); serializationOpts.SerializeAllSIL = opts.SILSerializeAll; if (opts.SerializeBridgingHeader) serializationOpts.ImportedHeader = opts.ImplicitObjCHeaderPath; serializationOpts.ModuleLinkName = opts.ModuleLinkName; serializationOpts.ExtraClangOptions = Invocation.getClangImporterOptions().ExtraArgs; if (!IRGenOpts.ForceLoadSymbolName.empty()) serializationOpts.AutolinkForceLoad = true; // Options contain information about the developer's computer, // so only serialize them if the module isn't going to be shipped to // the public. serializationOpts.SerializeOptionsForDebugging = !moduleIsPublic || opts.AlwaysSerializeDebuggingOptions; serialize(DC, serializationOpts, SM.get()); } if (Action == FrontendOptions::EmitModuleOnly) return Context.hadError(); } assert(Action >= FrontendOptions::EmitSIL && "All actions not requiring SILPasses must have been handled!"); // We've been told to write canonical SIL, so write it now. if (Action == FrontendOptions::EmitSIL) { return writeSIL(*SM, Instance->getMainModule(), opts.EmitVerboseSIL, opts.getSingleOutputFilename(), opts.EmitSortedSIL); } assert(Action >= FrontendOptions::Immediate && "All actions not requiring IRGen must have been handled!"); assert(Action != FrontendOptions::REPL && "REPL mode must be handled immediately after Instance->performSema()"); // Check if we had any errors; if we did, don't proceed to IRGen. if (Context.hadError()) return true; // Cleanup instructions/builtin calls not suitable for IRGen. performSILCleanup(SM.get()); // TODO: remove once the frontend understands what action it should perform IRGenOpts.OutputKind = getOutputKind(Action); if (Action == FrontendOptions::Immediate) { assert(!PrimarySourceFile && "-i doesn't work in -primary-file mode"); IRGenOpts.UseJIT = true; IRGenOpts.DebugInfoKind = IRGenDebugInfoKind::Normal; const ProcessCmdLine &CmdLine = ProcessCmdLine(opts.ImmediateArgv.begin(), opts.ImmediateArgv.end()); Instance->setSILModule(std::move(SM)); if (observer) { observer->aboutToRunImmediately(*Instance); } ReturnValue = RunImmediately(*Instance, CmdLine, IRGenOpts, Invocation.getSILOptions()); return Context.hadError(); } // FIXME: We shouldn't need to use the global context here, but // something is persisting across calls to performIRGeneration. auto &LLVMContext = getGlobalLLVMContext(); std::unique_ptr<llvm::Module> IRModule; llvm::GlobalVariable *HashGlobal; if (PrimarySourceFile) { IRModule = performIRGeneration(IRGenOpts, *PrimarySourceFile, std::move(SM), opts.getSingleOutputFilename(), LLVMContext, 0, &HashGlobal); } else { IRModule = performIRGeneration(IRGenOpts, Instance->getMainModule(), std::move(SM), opts.getSingleOutputFilename(), LLVMContext, &HashGlobal); } // Just because we had an AST error it doesn't mean we can't performLLVM. bool HadError = Instance->getASTContext().hadError(); // If the AST Context has no errors but no IRModule is available, // parallelIRGen happened correctly, since parallel IRGen produces multiple // modules. if (!IRModule) { return HadError; } std::unique_ptr<llvm::TargetMachine> TargetMachine = createTargetMachine(IRGenOpts, Context); version::Version EffectiveLanguageVersion = Context.LangOpts.EffectiveLanguageVersion; DiagnosticEngine &Diags = Context.Diags; const DiagnosticOptions &DiagOpts = Invocation.getDiagnosticOptions(); // Delete the compiler instance now that we have an IRModule. if (DiagOpts.VerifyMode == DiagnosticOptions::NoVerify) { SM.reset(); Instance.reset(); } // Now that we have a single IR Module, hand it over to performLLVM. return performLLVM(IRGenOpts, &Diags, nullptr, HashGlobal, IRModule.get(), TargetMachine.get(), EffectiveLanguageVersion, opts.getSingleOutputFilename()) || HadError; }