/// Bundle the files. Return true if an error was found. static bool BundleFiles() { std::error_code EC; // Create output file. raw_fd_ostream OutputFile(OutputFileNames.front(), EC, sys::fs::F_None); if (EC) { errs() << "error: Can't open file " << OutputFileNames.front() << ".\n"; return true; } // Open input files. std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers( InputFileNames.size()); unsigned Idx = 0; for (auto &I : InputFileNames) { ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = MemoryBuffer::getFileOrSTDIN(I); if (std::error_code EC = CodeOrErr.getError()) { errs() << "error: Can't open file " << I << ": " << EC.message() << "\n"; return true; } InputBuffers[Idx++] = std::move(CodeOrErr.get()); } // Get the file handler. We use the host buffer as reference. assert(HostInputIndex != ~0u && "Host input index undefined??"); std::unique_ptr<FileHandler> FH; FH.reset(CreateFileHandler(*InputBuffers[HostInputIndex].get())); // Quit if we don't have a handler. if (!FH.get()) return true; // Write header. FH.get()->WriteHeader(OutputFile, InputBuffers); // Write all bundles along with the start/end markers. If an error was found // writing the end of the bundle component, abort the bundle writing. auto Input = InputBuffers.begin(); for (auto &Triple : TargetNames) { FH.get()->WriteBundleStart(OutputFile, Triple); FH.get()->WriteBundle(OutputFile, *Input->get()); if (FH.get()->WriteBundleEnd(OutputFile, Triple)) return true; ++Input; } return false; }
// main - Entry point for the llc compiler. // int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); // Enable debug stream buffering. EnableDebugBuffering = true; LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. // Initialize targets first, so that --version shows registered targets. InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); InitializeAllAsmParsers(); // Initialize codegen and IR passes used by llc so that the -print-after, // -print-before, and -stop-after options work. PassRegistry *Registry = PassRegistry::getPassRegistry(); initializeCore(*Registry); initializeCodeGen(*Registry); initializeLoopStrengthReducePass(*Registry); initializeLowerIntrinsicsPass(*Registry); initializeUnreachableBlockElimPass(*Registry); // Register the target printer for --version. cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n"); // Load the module to be compiled... SMDiagnostic Err; std::auto_ptr<Module> M; Module *mod = 0; Triple TheTriple; bool SkipModule = MCPU == "help" || (!MAttrs.empty() && MAttrs.front() == "help"); // If user just wants to list available options, skip module loading if (!SkipModule) { M.reset(ParseIRFile(InputFilename, Err, Context)); mod = M.get(); if (mod == 0) { Err.print(argv[0], errs()); return 1; } // If we are supposed to override the target triple, do so now. if (!TargetTriple.empty()) mod->setTargetTriple(Triple::normalize(TargetTriple)); TheTriple = Triple(mod->getTargetTriple()); } else { TheTriple = Triple(Triple::normalize(TargetTriple)); } if (TheTriple.getTriple().empty()) TheTriple.setTriple(sys::getDefaultTargetTriple()); // Get the target specific parser. std::string Error; const Target *TheTarget = TargetRegistry::lookupTarget(MArch, TheTriple, Error); if (!TheTarget) { errs() << argv[0] << ": " << Error; return 1; } // Package up features to be passed to target/subtarget std::string FeaturesStr; if (MAttrs.size()) { SubtargetFeatures Features; for (unsigned i = 0; i != MAttrs.size(); ++i) Features.AddFeature(MAttrs[i]); FeaturesStr = Features.getString(); } CodeGenOpt::Level OLvl = CodeGenOpt::Default; switch (OptLevel) { default: errs() << argv[0] << ": invalid optimization level.\n"; return 1; case ' ': break; case '0': OLvl = CodeGenOpt::None; break; case '1': OLvl = CodeGenOpt::Less; break; case '2': OLvl = CodeGenOpt::Default; break; case '3': OLvl = CodeGenOpt::Aggressive; break; } TargetOptions Options; Options.LessPreciseFPMADOption = EnableFPMAD; Options.NoFramePointerElim = DisableFPElim; Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf; Options.AllowFPOpFusion = FuseFPOps; Options.UnsafeFPMath = EnableUnsafeFPMath; Options.NoInfsFPMath = EnableNoInfsFPMath; Options.NoNaNsFPMath = EnableNoNaNsFPMath; Options.HonorSignDependentRoundingFPMathOption = EnableHonorSignDependentRoundingFPMath; Options.UseSoftFloat = GenerateSoftFloatCalls; if (FloatABIForCalls != FloatABI::Default) Options.FloatABIType = FloatABIForCalls; Options.NoZerosInBSS = DontPlaceZerosInBSS; Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; Options.DisableTailCalls = DisableTailCalls; Options.StackAlignmentOverride = OverrideStackAlignment; Options.RealignStack = EnableRealignStack; Options.TrapFuncName = TrapFuncName; Options.PositionIndependentExecutable = EnablePIE; Options.EnableSegmentedStacks = SegmentedStacks; Options.UseInitArray = UseInitArray; std::auto_ptr<TargetMachine> target(TheTarget->createTargetMachine(TheTriple.getTriple(), MCPU, FeaturesStr, Options, RelocModel, CMModel, OLvl)); assert(target.get() && "Could not allocate target machine!"); assert(mod && "Should have exited after outputting help!"); TargetMachine &Target = *target.get(); if (DisableDotLoc) Target.setMCUseLoc(false); if (DisableCFI) Target.setMCUseCFI(false); if (EnableDwarfDirectory) Target.setMCUseDwarfDirectory(true); if (GenerateSoftFloatCalls) FloatABIForCalls = FloatABI::Soft; // Disable .loc support for older OS X versions. if (TheTriple.isMacOSX() && TheTriple.isMacOSXVersionLT(10, 6)) Target.setMCUseLoc(false); // Figure out where we are going to send the output. OwningPtr<tool_output_file> Out (GetOutputStream(TheTarget->getName(), TheTriple.getOS(), argv[0])); if (!Out) return 1; // Build up all of the passes that we want to do to the module. PassManager PM; // Add an appropriate TargetLibraryInfo pass for the module's triple. TargetLibraryInfo *TLI = new TargetLibraryInfo(TheTriple); if (DisableSimplifyLibCalls) TLI->disableAllFunctions(); PM.add(TLI); // Add the target data from the target machine, if it exists, or the module. if (const TargetData *TD = Target.getTargetData()) PM.add(new TargetData(*TD)); else PM.add(new TargetData(mod)); // Override default to generate verbose assembly. Target.setAsmVerbosityDefault(true); if (RelaxAll) { if (FileType != TargetMachine::CGFT_ObjectFile) errs() << argv[0] << ": warning: ignoring -mc-relax-all because filetype != obj"; else Target.setMCRelaxAll(true); } { formatted_raw_ostream FOS(Out->os()); AnalysisID StartAfterID = 0; AnalysisID StopAfterID = 0; const PassRegistry *PR = PassRegistry::getPassRegistry(); if (!StartAfter.empty()) { const PassInfo *PI = PR->getPassInfo(StartAfter); if (!PI) { errs() << argv[0] << ": start-after pass is not registered.\n"; return 1; } StartAfterID = PI->getTypeInfo(); } if (!StopAfter.empty()) { const PassInfo *PI = PR->getPassInfo(StopAfter); if (!PI) { errs() << argv[0] << ": stop-after pass is not registered.\n"; return 1; } StopAfterID = PI->getTypeInfo(); } // Ask the target to add backend passes as necessary. if (Target.addPassesToEmitFile(PM, FOS, FileType, NoVerify, StartAfterID, StopAfterID)) { errs() << argv[0] << ": target does not support generation of this" << " file type!\n"; return 1; } // Before executing passes, print the final values of the LLVM options. cl::PrintOptionValues(); PM.run(*mod); } // Declare success. Out->keep(); return 0; }
// Unbundle the files. Return true if an error was found. static bool UnbundleFiles() { // Open Input file. ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = MemoryBuffer::getFileOrSTDIN(InputFileNames.front()); if (std::error_code EC = CodeOrErr.getError()) { errs() << "error: Can't open file " << InputFileNames.front() << ": " << EC.message() << "\n"; return true; } MemoryBuffer &Input = *CodeOrErr.get(); // Select the right files handler. std::unique_ptr<FileHandler> FH; FH.reset(CreateFileHandler(Input)); // Quit if we don't have a handler. if (!FH.get()) return true; // Read the header of the bundled file. FH.get()->ReadHeader(Input); // Create a work list that consist of the map triple/output file. StringMap<StringRef> Worklist; auto Output = OutputFileNames.begin(); for (auto &Triple : TargetNames) { Worklist[Triple] = *Output; ++Output; } // Read all the bundles that are in the work list. If we find no bundles we // assume the file is meant for the host target. bool FoundHostBundle = false; while (!Worklist.empty()) { StringRef CurTriple = FH.get()->ReadBundleStart(Input); // We don't have more bundles. if (CurTriple.empty()) break; auto Output = Worklist.find(CurTriple); // The file may have more bundles for other targets, that we don't care // about. Therefore, move on to the next triple if (Output == Worklist.end()) { continue; } // Check if the output file can be opened and copy the bundle to it. std::error_code EC; raw_fd_ostream OutputFile(Output->second, EC, sys::fs::F_None); if (EC) { errs() << "error: Can't open file " << Output->second << ": " << EC.message() << "\n"; return true; } FH.get()->ReadBundle(OutputFile, Input); FH.get()->ReadBundleEnd(Input); Worklist.erase(Output); // Record if we found the host bundle. if (hasHostKind(CurTriple)) FoundHostBundle = true; } // If no bundles were found, assume the input file is the host bundle and // create empty files for the remaining targets. if (Worklist.size() == TargetNames.size()) { for (auto &E : Worklist) { std::error_code EC; raw_fd_ostream OutputFile(E.second, EC, sys::fs::F_None); if (EC) { errs() << "error: Can't open file " << E.second << ": " << EC.message() << "\n"; return true; } // If this entry has a host kind, copy the input file to the output file. if (hasHostKind(E.first())) OutputFile.write(Input.getBufferStart(), Input.getBufferSize()); } return false; } // If we found elements, we emit an error if none of those were for the host. if (!FoundHostBundle) { errs() << "error: Can't find bundle for the host target\n"; return true; } // If we still have any elements in the worklist, create empty files for them. for (auto &E : Worklist) { std::error_code EC; raw_fd_ostream OutputFile(E.second, EC, sys::fs::F_None); if (EC) { errs() << "error: Can't open file " << E.second << ": " << EC.message() << "\n"; return true; } } return false; }
bool WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final { assert(NumberOfProcessedInputs <= NumberOfInputs && "Processing more inputs that actually exist!"); assert(HostInputIndex != ~0u && "Host input index not defined."); // If this is not the last output, we don't have to do anything. if (NumberOfProcessedInputs != NumberOfInputs) return false; // Create the bitcode file name to write the resulting code to. Keep it if // save-temps is active. SmallString<128> BitcodeFileName; if (sys::fs::createTemporaryFile("clang-offload-bundler", "bc", BitcodeFileName)) { errs() << "error: unable to create temporary file.\n"; return true; } // Dump the contents of the temporary file if that was requested. if (DumpTemporaryFiles) { errs() << ";\n; Object file bundler IR file.\n;\n"; AuxModule.get()->print(errs(), nullptr, /*ShouldPreserveUseListOrder=*/false, /*IsForDebug=*/true); errs() << '\n'; } // Find clang in order to create the bundle binary. StringRef Dir = sys::path::parent_path(BundlerExecutable); auto ClangBinary = sys::findProgramByName("clang", Dir); if (ClangBinary.getError()) { // Remove bitcode file. sys::fs::remove(BitcodeFileName); errs() << "error: unable to find 'clang' in path.\n"; return true; } // Do the incremental linking. We write to the output file directly. So, we // close it and use the name to pass down to clang. OS.close(); SmallString<128> TargetName = getTriple(TargetNames[HostInputIndex]); std::vector<StringRef> ClangArgs = {"clang", "-r", "-target", TargetName.c_str(), "-o", OutputFileNames.front().c_str(), InputFileNames[HostInputIndex].c_str(), BitcodeFileName.c_str(), "-nostdlib"}; // If the user asked for the commands to be printed out, we do that instead // of executing it. if (PrintExternalCommands) { errs() << "\"" << ClangBinary.get() << "\""; for (StringRef Arg : ClangArgs) errs() << " \"" << Arg << "\""; errs() << "\n"; } else { // Write the bitcode contents to the temporary file. { std::error_code EC; raw_fd_ostream BitcodeFile(BitcodeFileName, EC, sys::fs::F_None); if (EC) { errs() << "error: unable to open temporary file.\n"; return true; } WriteBitcodeToFile(*AuxModule, BitcodeFile); } bool Failed = sys::ExecuteAndWait(ClangBinary.get(), ClangArgs); // Remove bitcode file. sys::fs::remove(BitcodeFileName); if (Failed) { errs() << "error: incremental linking by external tool failed.\n"; return true; } } return false; }