/// \returns true if an error occurred. static bool emitDataForSwiftSerializedModule(ModuleDecl *module, StringRef indexStorePath, bool indexSystemModules, StringRef targetTriple, const clang::CompilerInstance &clangCI, DiagnosticEngine &diags, IndexUnitWriter &parentUnitWriter) { StringRef filename = module->getModuleFilename(); std::string moduleName = module->getNameStr(); std::string error; auto isUptodateOpt = parentUnitWriter.isUnitUpToDateForOutputFile(/*FilePath=*/filename, /*TimeCompareFilePath=*/filename, error); if (!isUptodateOpt.hasValue()) { diags.diagnose(SourceLoc(), diag::error_index_failed_status_check, error); return true; } if (*isUptodateOpt) return false; // FIXME: Would be useful for testing if swift had clang's -Rremark system so // we could output a remark here that we are going to create index data for // a module file. // Pairs of (recordFile, groupName). std::vector<std::pair<std::string, std::string>> records; if (!module->isStdlibModule()) { std::string recordFile; bool failed = false; auto consumer = makeRecordingConsumer(filename, indexStorePath, &diags, &recordFile, &failed); indexModule(module, /*Hash=*/"", *consumer); if (failed) return true; records.emplace_back(recordFile, moduleName); } else { // Record stdlib groups as if they were submodules. auto makeSubmoduleNameFromGroupName = [](StringRef groupName, SmallString<128> &buf) { buf += "Swift"; if (groupName.empty()) return; buf += '.'; for (char ch : groupName) { if (ch == '/') buf += '.'; else if (ch == ' ' || ch == '-') buf += '_'; else buf += ch; } }; auto appendGroupNameForFilename = [](StringRef groupName, SmallString<256> &buf) { if (groupName.empty()) return; buf += '_'; for (char ch : groupName) { if (ch == '/' || ch ==' ') buf += '_'; else buf += ch; } }; bool failed = false; StdlibGroupsIndexRecordingConsumer groupIndexConsumer([&](StringRef groupName, SymbolTracker &tracker) -> bool { SmallString<128> moduleName; makeSubmoduleNameFromGroupName(groupName, moduleName); SmallString<256> fileNameWithGroup = filename; appendGroupNameForFilename(groupName, fileNameWithGroup); std::string outRecordFile; failed = failed || writeRecord(tracker, fileNameWithGroup.str(), indexStorePath, &diags, outRecordFile); if (failed) return false; records.emplace_back(outRecordFile, moduleName.str()); return true; }); indexModule(module, /*Hash=*/"", groupIndexConsumer); if (failed) return true; } auto &fileMgr = clangCI.getFileManager(); bool isSystem = module->isSystemModule(); // FIXME: Get real values for the following. StringRef swiftVersion; StringRef sysrootPath = clangCI.getHeaderSearchOpts().Sysroot; std::string indexUnitToken = module->getModuleFilename(); // For indexing serialized modules 'debug compilation' is irrelevant, so // set it to true by default. bool isDebugCompilation = true; IndexUnitWriter unitWriter(fileMgr, indexStorePath, "swift", swiftVersion, indexUnitToken, moduleName, /*MainFile=*/nullptr, isSystem, /*IsModuleUnit=*/true, isDebugCompilation, targetTriple, sysrootPath, getModuleInfoFromOpaqueModule); const clang::FileEntry *FE = fileMgr.getFile(filename); bool isSystemModule = module->isSystemModule(); for (auto &pair : records) { std::string &recordFile = pair.first; std::string &groupName = pair.second; if (recordFile.empty()) continue; clang::index::writer::OpaqueModule mod = &groupName; unitWriter.addRecordFile(recordFile, FE, isSystemModule, mod); } SmallVector<ModuleDecl::ImportedModule, 8> imports; module->getImportedModules(imports, ModuleDecl::ImportFilter::All); StringScratchSpace moduleNameScratch; addModuleDependencies(imports, indexStorePath, indexSystemModules, targetTriple, clangCI, diags, unitWriter, moduleNameScratch); if (unitWriter.write(error)) { diags.diagnose(SourceLoc(), diag::error_write_index_unit, error); return true; } return false; }
/// Run the LLVM passes. In multi-threaded compilation this will be done for /// multiple LLVM modules in parallel. static bool performLLVM(IRGenOptions &Opts, DiagnosticEngine &Diags, llvm::sys::Mutex *DiagMutex, llvm::Module *Module, llvm::TargetMachine *TargetMachine, StringRef OutputFilename) { llvm::SmallString<0> Buffer; std::unique_ptr<raw_pwrite_stream> RawOS; if (!OutputFilename.empty()) { // Try to open the output file. Clobbering an existing file is fine. // Open in binary mode if we're doing binary output. llvm::sys::fs::OpenFlags OSFlags = llvm::sys::fs::F_None; std::error_code EC; auto *FDOS = new raw_fd_ostream(OutputFilename, EC, OSFlags); RawOS.reset(FDOS); if (FDOS->has_error() || EC) { if (DiagMutex) DiagMutex->lock(); Diags.diagnose(SourceLoc(), diag::error_opening_output, OutputFilename, EC.message()); if (DiagMutex) DiagMutex->unlock(); FDOS->clear_error(); return true; } // Most output kinds want a formatted output stream. It's not clear // why writing an object file does. //if (Opts.OutputKind != IRGenOutputKind::LLVMBitcode) // FormattedOS.setStream(*RawOS, formatted_raw_ostream::PRESERVE_STREAM); } else { RawOS.reset(new raw_svector_ostream(Buffer)); } performLLVMOptimizations(Opts, Module, TargetMachine); legacy::PassManager EmitPasses; // Set up the final emission passes. switch (Opts.OutputKind) { case IRGenOutputKind::Module: break; case IRGenOutputKind::LLVMAssembly: EmitPasses.add(createPrintModulePass(*RawOS)); break; case IRGenOutputKind::LLVMBitcode: EmitPasses.add(createBitcodeWriterPass(*RawOS)); break; case IRGenOutputKind::NativeAssembly: case IRGenOutputKind::ObjectFile: { llvm::TargetMachine::CodeGenFileType FileType; FileType = (Opts.OutputKind == IRGenOutputKind::NativeAssembly ? llvm::TargetMachine::CGFT_AssemblyFile : llvm::TargetMachine::CGFT_ObjectFile); EmitPasses.add(createTargetTransformInfoWrapperPass( TargetMachine->getTargetIRAnalysis())); // 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. if (Opts.Optimize) EmitPasses.add(createObjCARCContractPass()); bool fail = TargetMachine->addPassesToEmitFile(EmitPasses, *RawOS, FileType, !Opts.Verify); if (fail) { if (DiagMutex) DiagMutex->lock(); Diags.diagnose(SourceLoc(), diag::error_codegen_init_fail); if (DiagMutex) DiagMutex->unlock(); return true; } break; } } EmitPasses.run(*Module); return false; }