10b57cec5SDimitry Andric //===- opt.cpp - The LLVM Modular Optimizer -------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // Optimizations may be specified an arbitrary number of times on the command 100b57cec5SDimitry Andric // line, They are run in the order specified. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "BreakpointPrinter.h" 150b57cec5SDimitry Andric #include "NewPMDriver.h" 160b57cec5SDimitry Andric #include "PassPrinters.h" 170b57cec5SDimitry Andric #include "llvm/ADT/Triple.h" 180b57cec5SDimitry Andric #include "llvm/Analysis/CallGraph.h" 190b57cec5SDimitry Andric #include "llvm/Analysis/CallGraphSCCPass.h" 200b57cec5SDimitry Andric #include "llvm/Analysis/LoopPass.h" 210b57cec5SDimitry Andric #include "llvm/Analysis/RegionPass.h" 220b57cec5SDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h" 230b57cec5SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h" 24*5ffd83dbSDimitry Andric #include "llvm/AsmParser/Parser.h" 250b57cec5SDimitry Andric #include "llvm/Bitcode/BitcodeWriterPass.h" 26*5ffd83dbSDimitry Andric #include "llvm/CodeGen/CommandFlags.h" 270b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 280b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h" 290b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 300b57cec5SDimitry Andric #include "llvm/IR/DebugInfo.h" 310b57cec5SDimitry Andric #include "llvm/IR/IRPrintingPasses.h" 320b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h" 33*5ffd83dbSDimitry Andric #include "llvm/IR/LLVMRemarkStreamer.h" 340b57cec5SDimitry Andric #include "llvm/IR/LegacyPassManager.h" 350b57cec5SDimitry Andric #include "llvm/IR/LegacyPassNameParser.h" 360b57cec5SDimitry Andric #include "llvm/IR/Module.h" 370b57cec5SDimitry Andric #include "llvm/IR/Verifier.h" 380b57cec5SDimitry Andric #include "llvm/IRReader/IRReader.h" 390b57cec5SDimitry Andric #include "llvm/InitializePasses.h" 400b57cec5SDimitry Andric #include "llvm/LinkAllIR.h" 410b57cec5SDimitry Andric #include "llvm/LinkAllPasses.h" 420b57cec5SDimitry Andric #include "llvm/MC/SubtargetFeature.h" 430b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 440b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 450b57cec5SDimitry Andric #include "llvm/Support/Host.h" 460b57cec5SDimitry Andric #include "llvm/Support/InitLLVM.h" 470b57cec5SDimitry Andric #include "llvm/Support/PluginLoader.h" 480b57cec5SDimitry Andric #include "llvm/Support/SourceMgr.h" 490b57cec5SDimitry Andric #include "llvm/Support/SystemUtils.h" 500b57cec5SDimitry Andric #include "llvm/Support/TargetRegistry.h" 510b57cec5SDimitry Andric #include "llvm/Support/TargetSelect.h" 520b57cec5SDimitry Andric #include "llvm/Support/ToolOutputFile.h" 530b57cec5SDimitry Andric #include "llvm/Support/YAMLTraits.h" 540b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h" 550b57cec5SDimitry Andric #include "llvm/Transforms/Coroutines.h" 560b57cec5SDimitry Andric #include "llvm/Transforms/IPO/AlwaysInliner.h" 570b57cec5SDimitry Andric #include "llvm/Transforms/IPO/PassManagerBuilder.h" 58*5ffd83dbSDimitry Andric #include "llvm/Transforms/IPO/WholeProgramDevirt.h" 590b57cec5SDimitry Andric #include "llvm/Transforms/Utils/Cloning.h" 60480093f4SDimitry Andric #include "llvm/Transforms/Utils/Debugify.h" 610b57cec5SDimitry Andric #include <algorithm> 620b57cec5SDimitry Andric #include <memory> 630b57cec5SDimitry Andric using namespace llvm; 640b57cec5SDimitry Andric using namespace opt_tool; 650b57cec5SDimitry Andric 66*5ffd83dbSDimitry Andric static codegen::RegisterCodeGenFlags CFG; 67*5ffd83dbSDimitry Andric 680b57cec5SDimitry Andric // The OptimizationList is automatically populated with registered Passes by the 690b57cec5SDimitry Andric // PassNameParser. 700b57cec5SDimitry Andric // 710b57cec5SDimitry Andric static cl::list<const PassInfo*, bool, PassNameParser> 720b57cec5SDimitry Andric PassList(cl::desc("Optimizations available:")); 730b57cec5SDimitry Andric 74*5ffd83dbSDimitry Andric static cl::opt<bool> EnableNewPassManager( 75*5ffd83dbSDimitry Andric "enable-new-pm", cl::desc("Enable the new pass manager"), cl::init(false)); 76*5ffd83dbSDimitry Andric 770b57cec5SDimitry Andric // This flag specifies a textual description of the optimization pass pipeline 780b57cec5SDimitry Andric // to run over the module. This flag switches opt to use the new pass manager 790b57cec5SDimitry Andric // infrastructure, completely disabling all of the flags specific to the old 800b57cec5SDimitry Andric // pass management. 810b57cec5SDimitry Andric static cl::opt<std::string> PassPipeline( 820b57cec5SDimitry Andric "passes", 830b57cec5SDimitry Andric cl::desc("A textual description of the pass pipeline for optimizing"), 840b57cec5SDimitry Andric cl::Hidden); 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric // Other command line options... 870b57cec5SDimitry Andric // 880b57cec5SDimitry Andric static cl::opt<std::string> 890b57cec5SDimitry Andric InputFilename(cl::Positional, cl::desc("<input bitcode file>"), 900b57cec5SDimitry Andric cl::init("-"), cl::value_desc("filename")); 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric static cl::opt<std::string> 930b57cec5SDimitry Andric OutputFilename("o", cl::desc("Override output filename"), 940b57cec5SDimitry Andric cl::value_desc("filename")); 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric static cl::opt<bool> 970b57cec5SDimitry Andric Force("f", cl::desc("Enable binary output on terminals")); 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric static cl::opt<bool> 1000b57cec5SDimitry Andric PrintEachXForm("p", cl::desc("Print module after each transformation")); 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric static cl::opt<bool> 1030b57cec5SDimitry Andric NoOutput("disable-output", 1040b57cec5SDimitry Andric cl::desc("Do not write result bitcode file"), cl::Hidden); 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric static cl::opt<bool> 1070b57cec5SDimitry Andric OutputAssembly("S", cl::desc("Write output as LLVM assembly")); 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric static cl::opt<bool> 1100b57cec5SDimitry Andric OutputThinLTOBC("thinlto-bc", 1110b57cec5SDimitry Andric cl::desc("Write output as ThinLTO-ready bitcode")); 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric static cl::opt<bool> 1140b57cec5SDimitry Andric SplitLTOUnit("thinlto-split-lto-unit", 1150b57cec5SDimitry Andric cl::desc("Enable splitting of a ThinLTO LTOUnit")); 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric static cl::opt<std::string> ThinLinkBitcodeFile( 1180b57cec5SDimitry Andric "thin-link-bitcode-file", cl::value_desc("filename"), 1190b57cec5SDimitry Andric cl::desc( 1200b57cec5SDimitry Andric "A file in which to write minimized bitcode for the thin link only")); 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric static cl::opt<bool> 1230b57cec5SDimitry Andric NoVerify("disable-verify", cl::desc("Do not run the verifier"), cl::Hidden); 1240b57cec5SDimitry Andric 125*5ffd83dbSDimitry Andric static cl::opt<bool> NoUpgradeDebugInfo("disable-upgrade-debug-info", 126*5ffd83dbSDimitry Andric cl::desc("Generate invalid output"), 127*5ffd83dbSDimitry Andric cl::ReallyHidden); 128*5ffd83dbSDimitry Andric 129*5ffd83dbSDimitry Andric static cl::opt<bool> VerifyEach("verify-each", 130*5ffd83dbSDimitry Andric cl::desc("Verify after each transform")); 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric static cl::opt<bool> 1330b57cec5SDimitry Andric DisableDITypeMap("disable-debug-info-type-map", 1340b57cec5SDimitry Andric cl::desc("Don't use a uniquing type map for debug info")); 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric static cl::opt<bool> 1370b57cec5SDimitry Andric StripDebug("strip-debug", 1380b57cec5SDimitry Andric cl::desc("Strip debugger symbol info from translation unit")); 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric static cl::opt<bool> 1410b57cec5SDimitry Andric StripNamedMetadata("strip-named-metadata", 1420b57cec5SDimitry Andric cl::desc("Strip module-level named metadata")); 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric static cl::opt<bool> DisableInline("disable-inlining", 1450b57cec5SDimitry Andric cl::desc("Do not run the inliner pass")); 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric static cl::opt<bool> 1480b57cec5SDimitry Andric DisableOptimizations("disable-opt", 1490b57cec5SDimitry Andric cl::desc("Do not run any optimization passes")); 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric static cl::opt<bool> 1520b57cec5SDimitry Andric StandardLinkOpts("std-link-opts", 1530b57cec5SDimitry Andric cl::desc("Include the standard link time optimizations")); 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric static cl::opt<bool> 1560b57cec5SDimitry Andric OptLevelO0("O0", 1570b57cec5SDimitry Andric cl::desc("Optimization level 0. Similar to clang -O0")); 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric static cl::opt<bool> 1600b57cec5SDimitry Andric OptLevelO1("O1", 1610b57cec5SDimitry Andric cl::desc("Optimization level 1. Similar to clang -O1")); 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric static cl::opt<bool> 1640b57cec5SDimitry Andric OptLevelO2("O2", 1650b57cec5SDimitry Andric cl::desc("Optimization level 2. Similar to clang -O2")); 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric static cl::opt<bool> 1680b57cec5SDimitry Andric OptLevelOs("Os", 1690b57cec5SDimitry Andric cl::desc("Like -O2 with extra optimizations for size. Similar to clang -Os")); 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric static cl::opt<bool> 1720b57cec5SDimitry Andric OptLevelOz("Oz", 1730b57cec5SDimitry Andric cl::desc("Like -Os but reduces code size further. Similar to clang -Oz")); 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric static cl::opt<bool> 1760b57cec5SDimitry Andric OptLevelO3("O3", 1770b57cec5SDimitry Andric cl::desc("Optimization level 3. Similar to clang -O3")); 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric static cl::opt<unsigned> 1800b57cec5SDimitry Andric CodeGenOptLevel("codegen-opt-level", 1810b57cec5SDimitry Andric cl::desc("Override optimization level for codegen hooks")); 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric static cl::opt<std::string> 1840b57cec5SDimitry Andric TargetTriple("mtriple", cl::desc("Override target triple for module")); 1850b57cec5SDimitry Andric 186*5ffd83dbSDimitry Andric cl::opt<bool> DisableLoopUnrolling( 187*5ffd83dbSDimitry Andric "disable-loop-unrolling", 188*5ffd83dbSDimitry Andric cl::desc("Disable loop unrolling in all relevant passes"), cl::init(false)); 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric static cl::opt<bool> EmitSummaryIndex("module-summary", 1910b57cec5SDimitry Andric cl::desc("Emit module summary index"), 1920b57cec5SDimitry Andric cl::init(false)); 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric static cl::opt<bool> EmitModuleHash("module-hash", cl::desc("Emit module hash"), 1950b57cec5SDimitry Andric cl::init(false)); 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric static cl::opt<bool> 1980b57cec5SDimitry Andric DisableSimplifyLibCalls("disable-simplify-libcalls", 1990b57cec5SDimitry Andric cl::desc("Disable simplify-libcalls")); 2000b57cec5SDimitry Andric 201480093f4SDimitry Andric static cl::list<std::string> 202480093f4SDimitry Andric DisableBuiltins("disable-builtin", 203480093f4SDimitry Andric cl::desc("Disable specific target library builtin function"), 204480093f4SDimitry Andric cl::ZeroOrMore); 205480093f4SDimitry Andric 2060b57cec5SDimitry Andric static cl::opt<bool> 2070b57cec5SDimitry Andric AnalyzeOnly("analyze", cl::desc("Only perform analysis, no optimization")); 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric static cl::opt<bool> EnableDebugify( 2100b57cec5SDimitry Andric "enable-debugify", 2110b57cec5SDimitry Andric cl::desc( 2120b57cec5SDimitry Andric "Start the pipeline with debugify and end it with check-debugify")); 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric static cl::opt<bool> DebugifyEach( 2150b57cec5SDimitry Andric "debugify-each", 2160b57cec5SDimitry Andric cl::desc( 2170b57cec5SDimitry Andric "Start each pass with debugify and end it with check-debugify")); 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric static cl::opt<std::string> 2200b57cec5SDimitry Andric DebugifyExport("debugify-export", 2210b57cec5SDimitry Andric cl::desc("Export per-pass debugify statistics to this file"), 2220b57cec5SDimitry Andric cl::value_desc("filename"), cl::init("")); 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric static cl::opt<bool> 2250b57cec5SDimitry Andric PrintBreakpoints("print-breakpoints-for-testing", 2260b57cec5SDimitry Andric cl::desc("Print select breakpoints location for testing")); 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric static cl::opt<std::string> ClDataLayout("data-layout", 2290b57cec5SDimitry Andric cl::desc("data layout string to use"), 2300b57cec5SDimitry Andric cl::value_desc("layout-string"), 2310b57cec5SDimitry Andric cl::init("")); 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric static cl::opt<bool> PreserveBitcodeUseListOrder( 2340b57cec5SDimitry Andric "preserve-bc-uselistorder", 2350b57cec5SDimitry Andric cl::desc("Preserve use-list order when writing LLVM bitcode."), 2360b57cec5SDimitry Andric cl::init(true), cl::Hidden); 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric static cl::opt<bool> PreserveAssemblyUseListOrder( 2390b57cec5SDimitry Andric "preserve-ll-uselistorder", 2400b57cec5SDimitry Andric cl::desc("Preserve use-list order when writing LLVM assembly."), 2410b57cec5SDimitry Andric cl::init(false), cl::Hidden); 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric static cl::opt<bool> 2440b57cec5SDimitry Andric RunTwice("run-twice", 2450b57cec5SDimitry Andric cl::desc("Run all passes twice, re-using the same pass manager."), 2460b57cec5SDimitry Andric cl::init(false), cl::Hidden); 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric static cl::opt<bool> DiscardValueNames( 2490b57cec5SDimitry Andric "discard-value-names", 2500b57cec5SDimitry Andric cl::desc("Discard names from Value (other than GlobalValue)."), 2510b57cec5SDimitry Andric cl::init(false), cl::Hidden); 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric static cl::opt<bool> Coroutines( 2540b57cec5SDimitry Andric "enable-coroutines", 2550b57cec5SDimitry Andric cl::desc("Enable coroutine passes."), 2560b57cec5SDimitry Andric cl::init(false), cl::Hidden); 2570b57cec5SDimitry Andric 258*5ffd83dbSDimitry Andric static cl::opt<bool> TimeTrace( 259*5ffd83dbSDimitry Andric "time-trace", 260*5ffd83dbSDimitry Andric cl::desc("Record time trace")); 261*5ffd83dbSDimitry Andric 262*5ffd83dbSDimitry Andric static cl::opt<unsigned> TimeTraceGranularity( 263*5ffd83dbSDimitry Andric "time-trace-granularity", 264*5ffd83dbSDimitry Andric cl::desc("Minimum time granularity (in microseconds) traced by time profiler"), 265*5ffd83dbSDimitry Andric cl::init(500), cl::Hidden); 266*5ffd83dbSDimitry Andric 267*5ffd83dbSDimitry Andric static cl::opt<std::string> 268*5ffd83dbSDimitry Andric TimeTraceFile("time-trace-file", 269*5ffd83dbSDimitry Andric cl::desc("Specify time trace file destination"), 270*5ffd83dbSDimitry Andric cl::value_desc("filename")); 271*5ffd83dbSDimitry Andric 2720b57cec5SDimitry Andric static cl::opt<bool> RemarksWithHotness( 2730b57cec5SDimitry Andric "pass-remarks-with-hotness", 2740b57cec5SDimitry Andric cl::desc("With PGO, include profile count in optimization remarks"), 2750b57cec5SDimitry Andric cl::Hidden); 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric static cl::opt<unsigned> 2780b57cec5SDimitry Andric RemarksHotnessThreshold("pass-remarks-hotness-threshold", 2790b57cec5SDimitry Andric cl::desc("Minimum profile count required for " 2800b57cec5SDimitry Andric "an optimization remark to be output"), 2810b57cec5SDimitry Andric cl::Hidden); 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric static cl::opt<std::string> 2840b57cec5SDimitry Andric RemarksFilename("pass-remarks-output", 2850b57cec5SDimitry Andric cl::desc("Output filename for pass remarks"), 2860b57cec5SDimitry Andric cl::value_desc("filename")); 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric static cl::opt<std::string> 2890b57cec5SDimitry Andric RemarksPasses("pass-remarks-filter", 2900b57cec5SDimitry Andric cl::desc("Only record optimization remarks from passes whose " 2910b57cec5SDimitry Andric "names match the given regular expression"), 2920b57cec5SDimitry Andric cl::value_desc("regex")); 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric static cl::opt<std::string> RemarksFormat( 2950b57cec5SDimitry Andric "pass-remarks-format", 2960b57cec5SDimitry Andric cl::desc("The format used for serializing remarks (default: YAML)"), 2970b57cec5SDimitry Andric cl::value_desc("format"), cl::init("yaml")); 2980b57cec5SDimitry Andric 2990b57cec5SDimitry Andric cl::opt<PGOKind> 3000b57cec5SDimitry Andric PGOKindFlag("pgo-kind", cl::init(NoPGO), cl::Hidden, 3010b57cec5SDimitry Andric cl::desc("The kind of profile guided optimization"), 3020b57cec5SDimitry Andric cl::values(clEnumValN(NoPGO, "nopgo", "Do not use PGO."), 3030b57cec5SDimitry Andric clEnumValN(InstrGen, "pgo-instr-gen-pipeline", 3040b57cec5SDimitry Andric "Instrument the IR to generate profile."), 3050b57cec5SDimitry Andric clEnumValN(InstrUse, "pgo-instr-use-pipeline", 3060b57cec5SDimitry Andric "Use instrumented profile to guide PGO."), 3070b57cec5SDimitry Andric clEnumValN(SampleUse, "pgo-sample-use-pipeline", 3080b57cec5SDimitry Andric "Use sampled profile to guide PGO."))); 3090b57cec5SDimitry Andric cl::opt<std::string> ProfileFile("profile-file", 3100b57cec5SDimitry Andric cl::desc("Path to the profile."), cl::Hidden); 3110b57cec5SDimitry Andric 3120b57cec5SDimitry Andric cl::opt<CSPGOKind> CSPGOKindFlag( 3130b57cec5SDimitry Andric "cspgo-kind", cl::init(NoCSPGO), cl::Hidden, 3140b57cec5SDimitry Andric cl::desc("The kind of context sensitive profile guided optimization"), 3150b57cec5SDimitry Andric cl::values( 3160b57cec5SDimitry Andric clEnumValN(NoCSPGO, "nocspgo", "Do not use CSPGO."), 3170b57cec5SDimitry Andric clEnumValN( 3180b57cec5SDimitry Andric CSInstrGen, "cspgo-instr-gen-pipeline", 3190b57cec5SDimitry Andric "Instrument (context sensitive) the IR to generate profile."), 3200b57cec5SDimitry Andric clEnumValN( 3210b57cec5SDimitry Andric CSInstrUse, "cspgo-instr-use-pipeline", 3220b57cec5SDimitry Andric "Use instrumented (context sensitive) profile to guide PGO."))); 3230b57cec5SDimitry Andric cl::opt<std::string> CSProfileGenFile( 3240b57cec5SDimitry Andric "cs-profilegen-file", 3250b57cec5SDimitry Andric cl::desc("Path to the instrumented context sensitive profile."), 3260b57cec5SDimitry Andric cl::Hidden); 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric class OptCustomPassManager : public legacy::PassManager { 3290b57cec5SDimitry Andric DebugifyStatsMap DIStatsMap; 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric public: 3320b57cec5SDimitry Andric using super = legacy::PassManager; 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric void add(Pass *P) override { 3350b57cec5SDimitry Andric // Wrap each pass with (-check)-debugify passes if requested, making 3360b57cec5SDimitry Andric // exceptions for passes which shouldn't see -debugify instrumentation. 3370b57cec5SDimitry Andric bool WrapWithDebugify = DebugifyEach && !P->getAsImmutablePass() && 3380b57cec5SDimitry Andric !isIRPrintingPass(P) && !isBitcodeWriterPass(P); 3390b57cec5SDimitry Andric if (!WrapWithDebugify) { 3400b57cec5SDimitry Andric super::add(P); 3410b57cec5SDimitry Andric return; 3420b57cec5SDimitry Andric } 3430b57cec5SDimitry Andric 3440b57cec5SDimitry Andric // Apply -debugify/-check-debugify before/after each pass and collect 3450b57cec5SDimitry Andric // debug info loss statistics. 3460b57cec5SDimitry Andric PassKind Kind = P->getPassKind(); 3470b57cec5SDimitry Andric StringRef Name = P->getPassName(); 3480b57cec5SDimitry Andric 349480093f4SDimitry Andric // TODO: Implement Debugify for LoopPass. 3500b57cec5SDimitry Andric switch (Kind) { 3510b57cec5SDimitry Andric case PT_Function: 3520b57cec5SDimitry Andric super::add(createDebugifyFunctionPass()); 3530b57cec5SDimitry Andric super::add(P); 3540b57cec5SDimitry Andric super::add(createCheckDebugifyFunctionPass(true, Name, &DIStatsMap)); 3550b57cec5SDimitry Andric break; 3560b57cec5SDimitry Andric case PT_Module: 3570b57cec5SDimitry Andric super::add(createDebugifyModulePass()); 3580b57cec5SDimitry Andric super::add(P); 3590b57cec5SDimitry Andric super::add(createCheckDebugifyModulePass(true, Name, &DIStatsMap)); 3600b57cec5SDimitry Andric break; 3610b57cec5SDimitry Andric default: 3620b57cec5SDimitry Andric super::add(P); 3630b57cec5SDimitry Andric break; 3640b57cec5SDimitry Andric } 3650b57cec5SDimitry Andric } 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric const DebugifyStatsMap &getDebugifyStatsMap() const { return DIStatsMap; } 3680b57cec5SDimitry Andric }; 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric static inline void addPass(legacy::PassManagerBase &PM, Pass *P) { 3710b57cec5SDimitry Andric // Add the pass to the pass manager... 3720b57cec5SDimitry Andric PM.add(P); 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric // If we are verifying all of the intermediate steps, add the verifier... 3750b57cec5SDimitry Andric if (VerifyEach) 3760b57cec5SDimitry Andric PM.add(createVerifierPass()); 3770b57cec5SDimitry Andric } 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric /// This routine adds optimization passes based on selected optimization level, 3800b57cec5SDimitry Andric /// OptLevel. 3810b57cec5SDimitry Andric /// 3820b57cec5SDimitry Andric /// OptLevel - Optimization Level 3830b57cec5SDimitry Andric static void AddOptimizationPasses(legacy::PassManagerBase &MPM, 3840b57cec5SDimitry Andric legacy::FunctionPassManager &FPM, 3850b57cec5SDimitry Andric TargetMachine *TM, unsigned OptLevel, 3860b57cec5SDimitry Andric unsigned SizeLevel) { 3870b57cec5SDimitry Andric if (!NoVerify || VerifyEach) 3880b57cec5SDimitry Andric FPM.add(createVerifierPass()); // Verify that input is correct 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric PassManagerBuilder Builder; 3910b57cec5SDimitry Andric Builder.OptLevel = OptLevel; 3920b57cec5SDimitry Andric Builder.SizeLevel = SizeLevel; 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric if (DisableInline) { 3950b57cec5SDimitry Andric // No inlining pass 3960b57cec5SDimitry Andric } else if (OptLevel > 1) { 3970b57cec5SDimitry Andric Builder.Inliner = createFunctionInliningPass(OptLevel, SizeLevel, false); 3980b57cec5SDimitry Andric } else { 3990b57cec5SDimitry Andric Builder.Inliner = createAlwaysInlinerLegacyPass(); 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric Builder.DisableUnrollLoops = (DisableLoopUnrolling.getNumOccurrences() > 0) ? 4020b57cec5SDimitry Andric DisableLoopUnrolling : OptLevel == 0; 4030b57cec5SDimitry Andric 4040b57cec5SDimitry Andric Builder.LoopVectorize = OptLevel > 1 && SizeLevel < 2; 4050b57cec5SDimitry Andric 406*5ffd83dbSDimitry Andric Builder.SLPVectorize = OptLevel > 1 && SizeLevel < 2; 4070b57cec5SDimitry Andric 4080b57cec5SDimitry Andric if (TM) 4090b57cec5SDimitry Andric TM->adjustPassManager(Builder); 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric if (Coroutines) 4120b57cec5SDimitry Andric addCoroutinePassesToExtensionPoints(Builder); 4130b57cec5SDimitry Andric 4140b57cec5SDimitry Andric switch (PGOKindFlag) { 4150b57cec5SDimitry Andric case InstrGen: 4160b57cec5SDimitry Andric Builder.EnablePGOInstrGen = true; 4170b57cec5SDimitry Andric Builder.PGOInstrGen = ProfileFile; 4180b57cec5SDimitry Andric break; 4190b57cec5SDimitry Andric case InstrUse: 4200b57cec5SDimitry Andric Builder.PGOInstrUse = ProfileFile; 4210b57cec5SDimitry Andric break; 4220b57cec5SDimitry Andric case SampleUse: 4230b57cec5SDimitry Andric Builder.PGOSampleUse = ProfileFile; 4240b57cec5SDimitry Andric break; 4250b57cec5SDimitry Andric default: 4260b57cec5SDimitry Andric break; 4270b57cec5SDimitry Andric } 4280b57cec5SDimitry Andric 4290b57cec5SDimitry Andric switch (CSPGOKindFlag) { 4300b57cec5SDimitry Andric case CSInstrGen: 4310b57cec5SDimitry Andric Builder.EnablePGOCSInstrGen = true; 4320b57cec5SDimitry Andric break; 4330b57cec5SDimitry Andric case CSInstrUse: 4340b57cec5SDimitry Andric Builder.EnablePGOCSInstrUse = true; 4350b57cec5SDimitry Andric break; 4360b57cec5SDimitry Andric default: 4370b57cec5SDimitry Andric break; 4380b57cec5SDimitry Andric } 4390b57cec5SDimitry Andric 4400b57cec5SDimitry Andric Builder.populateFunctionPassManager(FPM); 4410b57cec5SDimitry Andric Builder.populateModulePassManager(MPM); 4420b57cec5SDimitry Andric } 4430b57cec5SDimitry Andric 4440b57cec5SDimitry Andric static void AddStandardLinkPasses(legacy::PassManagerBase &PM) { 4450b57cec5SDimitry Andric PassManagerBuilder Builder; 4460b57cec5SDimitry Andric Builder.VerifyInput = true; 4470b57cec5SDimitry Andric if (DisableOptimizations) 4480b57cec5SDimitry Andric Builder.OptLevel = 0; 4490b57cec5SDimitry Andric 4500b57cec5SDimitry Andric if (!DisableInline) 4510b57cec5SDimitry Andric Builder.Inliner = createFunctionInliningPass(); 4520b57cec5SDimitry Andric Builder.populateLTOPassManager(PM); 4530b57cec5SDimitry Andric } 4540b57cec5SDimitry Andric 4550b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 4560b57cec5SDimitry Andric // CodeGen-related helper functions. 4570b57cec5SDimitry Andric // 4580b57cec5SDimitry Andric 4590b57cec5SDimitry Andric static CodeGenOpt::Level GetCodeGenOptLevel() { 4600b57cec5SDimitry Andric if (CodeGenOptLevel.getNumOccurrences()) 4610b57cec5SDimitry Andric return static_cast<CodeGenOpt::Level>(unsigned(CodeGenOptLevel)); 4620b57cec5SDimitry Andric if (OptLevelO1) 4630b57cec5SDimitry Andric return CodeGenOpt::Less; 4640b57cec5SDimitry Andric if (OptLevelO2) 4650b57cec5SDimitry Andric return CodeGenOpt::Default; 4660b57cec5SDimitry Andric if (OptLevelO3) 4670b57cec5SDimitry Andric return CodeGenOpt::Aggressive; 4680b57cec5SDimitry Andric return CodeGenOpt::None; 4690b57cec5SDimitry Andric } 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric // Returns the TargetMachine instance or zero if no triple is provided. 4720b57cec5SDimitry Andric static TargetMachine* GetTargetMachine(Triple TheTriple, StringRef CPUStr, 4730b57cec5SDimitry Andric StringRef FeaturesStr, 4740b57cec5SDimitry Andric const TargetOptions &Options) { 4750b57cec5SDimitry Andric std::string Error; 476*5ffd83dbSDimitry Andric const Target *TheTarget = 477*5ffd83dbSDimitry Andric TargetRegistry::lookupTarget(codegen::getMArch(), TheTriple, Error); 4780b57cec5SDimitry Andric // Some modules don't specify a triple, and this is okay. 4790b57cec5SDimitry Andric if (!TheTarget) { 4800b57cec5SDimitry Andric return nullptr; 4810b57cec5SDimitry Andric } 4820b57cec5SDimitry Andric 483*5ffd83dbSDimitry Andric return TheTarget->createTargetMachine( 484*5ffd83dbSDimitry Andric TheTriple.getTriple(), codegen::getCPUStr(), codegen::getFeaturesStr(), 485*5ffd83dbSDimitry Andric Options, codegen::getExplicitRelocModel(), 486*5ffd83dbSDimitry Andric codegen::getExplicitCodeModel(), GetCodeGenOptLevel()); 4870b57cec5SDimitry Andric } 4880b57cec5SDimitry Andric 489480093f4SDimitry Andric #ifdef BUILD_EXAMPLES 490480093f4SDimitry Andric void initializeExampleIRTransforms(llvm::PassRegistry &Registry); 4910b57cec5SDimitry Andric #endif 4920b57cec5SDimitry Andric 493480093f4SDimitry Andric 494480093f4SDimitry Andric void exportDebugifyStats(llvm::StringRef Path, const DebugifyStatsMap &Map) { 495480093f4SDimitry Andric std::error_code EC; 496480093f4SDimitry Andric raw_fd_ostream OS{Path, EC}; 497480093f4SDimitry Andric if (EC) { 498480093f4SDimitry Andric errs() << "Could not open file: " << EC.message() << ", " << Path << '\n'; 499480093f4SDimitry Andric return; 500480093f4SDimitry Andric } 501480093f4SDimitry Andric 502480093f4SDimitry Andric OS << "Pass Name" << ',' << "# of missing debug values" << ',' 503480093f4SDimitry Andric << "# of missing locations" << ',' << "Missing/Expected value ratio" << ',' 504480093f4SDimitry Andric << "Missing/Expected location ratio" << '\n'; 505480093f4SDimitry Andric for (const auto &Entry : Map) { 506480093f4SDimitry Andric StringRef Pass = Entry.first; 507480093f4SDimitry Andric DebugifyStatistics Stats = Entry.second; 508480093f4SDimitry Andric 509480093f4SDimitry Andric OS << Pass << ',' << Stats.NumDbgValuesMissing << ',' 510480093f4SDimitry Andric << Stats.NumDbgLocsMissing << ',' << Stats.getMissingValueRatio() << ',' 511480093f4SDimitry Andric << Stats.getEmptyLocationRatio() << '\n'; 512480093f4SDimitry Andric } 513480093f4SDimitry Andric } 514480093f4SDimitry Andric 515*5ffd83dbSDimitry Andric struct TimeTracerRAII { 516*5ffd83dbSDimitry Andric TimeTracerRAII(StringRef ProgramName) { 517*5ffd83dbSDimitry Andric if (TimeTrace) 518*5ffd83dbSDimitry Andric timeTraceProfilerInitialize(TimeTraceGranularity, ProgramName); 519*5ffd83dbSDimitry Andric } 520*5ffd83dbSDimitry Andric ~TimeTracerRAII() { 521*5ffd83dbSDimitry Andric if (TimeTrace) { 522*5ffd83dbSDimitry Andric if (auto E = timeTraceProfilerWrite(TimeTraceFile, OutputFilename)) { 523*5ffd83dbSDimitry Andric handleAllErrors(std::move(E), [&](const StringError &SE) { 524*5ffd83dbSDimitry Andric errs() << SE.getMessage() << "\n"; 525*5ffd83dbSDimitry Andric }); 526*5ffd83dbSDimitry Andric return; 527*5ffd83dbSDimitry Andric } 528*5ffd83dbSDimitry Andric timeTraceProfilerCleanup(); 529*5ffd83dbSDimitry Andric } 530*5ffd83dbSDimitry Andric } 531*5ffd83dbSDimitry Andric }; 532*5ffd83dbSDimitry Andric 5330b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 5340b57cec5SDimitry Andric // main for opt 5350b57cec5SDimitry Andric // 5360b57cec5SDimitry Andric int main(int argc, char **argv) { 5370b57cec5SDimitry Andric InitLLVM X(argc, argv); 5380b57cec5SDimitry Andric 5390b57cec5SDimitry Andric // Enable debug stream buffering. 5400b57cec5SDimitry Andric EnableDebugBuffering = true; 5410b57cec5SDimitry Andric 5420b57cec5SDimitry Andric LLVMContext Context; 5430b57cec5SDimitry Andric 5440b57cec5SDimitry Andric InitializeAllTargets(); 5450b57cec5SDimitry Andric InitializeAllTargetMCs(); 5460b57cec5SDimitry Andric InitializeAllAsmPrinters(); 5470b57cec5SDimitry Andric InitializeAllAsmParsers(); 5480b57cec5SDimitry Andric 5490b57cec5SDimitry Andric // Initialize passes 5500b57cec5SDimitry Andric PassRegistry &Registry = *PassRegistry::getPassRegistry(); 5510b57cec5SDimitry Andric initializeCore(Registry); 5520b57cec5SDimitry Andric initializeCoroutines(Registry); 5530b57cec5SDimitry Andric initializeScalarOpts(Registry); 5540b57cec5SDimitry Andric initializeObjCARCOpts(Registry); 5550b57cec5SDimitry Andric initializeVectorization(Registry); 5560b57cec5SDimitry Andric initializeIPO(Registry); 5570b57cec5SDimitry Andric initializeAnalysis(Registry); 5580b57cec5SDimitry Andric initializeTransformUtils(Registry); 5590b57cec5SDimitry Andric initializeInstCombine(Registry); 5600b57cec5SDimitry Andric initializeAggressiveInstCombine(Registry); 5610b57cec5SDimitry Andric initializeInstrumentation(Registry); 5620b57cec5SDimitry Andric initializeTarget(Registry); 5630b57cec5SDimitry Andric // For codegen passes, only passes that do IR to IR transformation are 5640b57cec5SDimitry Andric // supported. 5650b57cec5SDimitry Andric initializeExpandMemCmpPassPass(Registry); 5660b57cec5SDimitry Andric initializeScalarizeMaskedMemIntrinPass(Registry); 5670b57cec5SDimitry Andric initializeCodeGenPreparePass(Registry); 5680b57cec5SDimitry Andric initializeAtomicExpandPass(Registry); 5690b57cec5SDimitry Andric initializeRewriteSymbolsLegacyPassPass(Registry); 5700b57cec5SDimitry Andric initializeWinEHPreparePass(Registry); 5710b57cec5SDimitry Andric initializeDwarfEHPreparePass(Registry); 5720b57cec5SDimitry Andric initializeSafeStackLegacyPassPass(Registry); 5730b57cec5SDimitry Andric initializeSjLjEHPreparePass(Registry); 5740b57cec5SDimitry Andric initializePreISelIntrinsicLoweringLegacyPassPass(Registry); 5750b57cec5SDimitry Andric initializeGlobalMergePass(Registry); 5760b57cec5SDimitry Andric initializeIndirectBrExpandPassPass(Registry); 5770b57cec5SDimitry Andric initializeInterleavedLoadCombinePass(Registry); 5780b57cec5SDimitry Andric initializeInterleavedAccessPass(Registry); 5790b57cec5SDimitry Andric initializeEntryExitInstrumenterPass(Registry); 5800b57cec5SDimitry Andric initializePostInlineEntryExitInstrumenterPass(Registry); 5810b57cec5SDimitry Andric initializeUnreachableBlockElimLegacyPassPass(Registry); 5820b57cec5SDimitry Andric initializeExpandReductionsPass(Registry); 5830b57cec5SDimitry Andric initializeWasmEHPreparePass(Registry); 5840b57cec5SDimitry Andric initializeWriteBitcodePassPass(Registry); 5850b57cec5SDimitry Andric initializeHardwareLoopsPass(Registry); 586480093f4SDimitry Andric initializeTypePromotionPass(Registry); 5870b57cec5SDimitry Andric 588480093f4SDimitry Andric #ifdef BUILD_EXAMPLES 589480093f4SDimitry Andric initializeExampleIRTransforms(Registry); 5900b57cec5SDimitry Andric #endif 5910b57cec5SDimitry Andric 5920b57cec5SDimitry Andric cl::ParseCommandLineOptions(argc, argv, 5930b57cec5SDimitry Andric "llvm .bc -> .bc modular optimizer and analysis printer\n"); 5940b57cec5SDimitry Andric 5950b57cec5SDimitry Andric if (AnalyzeOnly && NoOutput) { 5960b57cec5SDimitry Andric errs() << argv[0] << ": analyze mode conflicts with no-output mode.\n"; 5970b57cec5SDimitry Andric return 1; 5980b57cec5SDimitry Andric } 5990b57cec5SDimitry Andric 600*5ffd83dbSDimitry Andric TimeTracerRAII TimeTracer(argv[0]); 601*5ffd83dbSDimitry Andric 6020b57cec5SDimitry Andric SMDiagnostic Err; 6030b57cec5SDimitry Andric 6040b57cec5SDimitry Andric Context.setDiscardValueNames(DiscardValueNames); 6050b57cec5SDimitry Andric if (!DisableDITypeMap) 6060b57cec5SDimitry Andric Context.enableDebugTypeODRUniquing(); 6070b57cec5SDimitry Andric 6080b57cec5SDimitry Andric Expected<std::unique_ptr<ToolOutputFile>> RemarksFileOrErr = 609*5ffd83dbSDimitry Andric setupLLVMOptimizationRemarks(Context, RemarksFilename, RemarksPasses, 6100b57cec5SDimitry Andric RemarksFormat, RemarksWithHotness, 6110b57cec5SDimitry Andric RemarksHotnessThreshold); 6120b57cec5SDimitry Andric if (Error E = RemarksFileOrErr.takeError()) { 6130b57cec5SDimitry Andric errs() << toString(std::move(E)) << '\n'; 6140b57cec5SDimitry Andric return 1; 6150b57cec5SDimitry Andric } 6160b57cec5SDimitry Andric std::unique_ptr<ToolOutputFile> RemarksFile = std::move(*RemarksFileOrErr); 6170b57cec5SDimitry Andric 6180b57cec5SDimitry Andric // Load the input module... 619*5ffd83dbSDimitry Andric auto SetDataLayout = [](StringRef) -> Optional<std::string> { 620*5ffd83dbSDimitry Andric if (ClDataLayout.empty()) 621*5ffd83dbSDimitry Andric return None; 622*5ffd83dbSDimitry Andric return ClDataLayout; 623*5ffd83dbSDimitry Andric }; 624*5ffd83dbSDimitry Andric std::unique_ptr<Module> M; 625*5ffd83dbSDimitry Andric if (NoUpgradeDebugInfo) 626*5ffd83dbSDimitry Andric M = parseAssemblyFileWithIndexNoUpgradeDebugInfo( 627*5ffd83dbSDimitry Andric InputFilename, Err, Context, nullptr, SetDataLayout) 628*5ffd83dbSDimitry Andric .Mod; 629*5ffd83dbSDimitry Andric else 630*5ffd83dbSDimitry Andric M = parseIRFile(InputFilename, Err, Context, SetDataLayout); 6310b57cec5SDimitry Andric 6320b57cec5SDimitry Andric if (!M) { 6330b57cec5SDimitry Andric Err.print(argv[0], errs()); 6340b57cec5SDimitry Andric return 1; 6350b57cec5SDimitry Andric } 6360b57cec5SDimitry Andric 6370b57cec5SDimitry Andric // Strip debug info before running the verifier. 6380b57cec5SDimitry Andric if (StripDebug) 6390b57cec5SDimitry Andric StripDebugInfo(*M); 6400b57cec5SDimitry Andric 6410b57cec5SDimitry Andric // Erase module-level named metadata, if requested. 6420b57cec5SDimitry Andric if (StripNamedMetadata) { 6430b57cec5SDimitry Andric while (!M->named_metadata_empty()) { 6440b57cec5SDimitry Andric NamedMDNode *NMD = &*M->named_metadata_begin(); 6450b57cec5SDimitry Andric M->eraseNamedMetadata(NMD); 6460b57cec5SDimitry Andric } 6470b57cec5SDimitry Andric } 6480b57cec5SDimitry Andric 6490b57cec5SDimitry Andric // If we are supposed to override the target triple or data layout, do so now. 6500b57cec5SDimitry Andric if (!TargetTriple.empty()) 6510b57cec5SDimitry Andric M->setTargetTriple(Triple::normalize(TargetTriple)); 6520b57cec5SDimitry Andric 6530b57cec5SDimitry Andric // Immediately run the verifier to catch any problems before starting up the 6540b57cec5SDimitry Andric // pass pipelines. Otherwise we can crash on broken code during 6550b57cec5SDimitry Andric // doInitialization(). 6560b57cec5SDimitry Andric if (!NoVerify && verifyModule(*M, &errs())) { 6570b57cec5SDimitry Andric errs() << argv[0] << ": " << InputFilename 6580b57cec5SDimitry Andric << ": error: input module is broken!\n"; 6590b57cec5SDimitry Andric return 1; 6600b57cec5SDimitry Andric } 6610b57cec5SDimitry Andric 662*5ffd83dbSDimitry Andric // Enable testing of whole program devirtualization on this module by invoking 663*5ffd83dbSDimitry Andric // the facility for updating public visibility to linkage unit visibility when 664*5ffd83dbSDimitry Andric // specified by an internal option. This is normally done during LTO which is 665*5ffd83dbSDimitry Andric // not performed via opt. 666*5ffd83dbSDimitry Andric updateVCallVisibilityInModule(*M, 667*5ffd83dbSDimitry Andric /* WholeProgramVisibilityEnabledInLTO */ false); 668*5ffd83dbSDimitry Andric 6690b57cec5SDimitry Andric // Figure out what stream we are supposed to write to... 6700b57cec5SDimitry Andric std::unique_ptr<ToolOutputFile> Out; 6710b57cec5SDimitry Andric std::unique_ptr<ToolOutputFile> ThinLinkOut; 6720b57cec5SDimitry Andric if (NoOutput) { 6730b57cec5SDimitry Andric if (!OutputFilename.empty()) 6740b57cec5SDimitry Andric errs() << "WARNING: The -o (output filename) option is ignored when\n" 6750b57cec5SDimitry Andric "the --disable-output option is used.\n"; 6760b57cec5SDimitry Andric } else { 6770b57cec5SDimitry Andric // Default to standard output. 6780b57cec5SDimitry Andric if (OutputFilename.empty()) 6790b57cec5SDimitry Andric OutputFilename = "-"; 6800b57cec5SDimitry Andric 6810b57cec5SDimitry Andric std::error_code EC; 6828bcb0991SDimitry Andric sys::fs::OpenFlags Flags = OutputAssembly ? sys::fs::OF_Text 6838bcb0991SDimitry Andric : sys::fs::OF_None; 6848bcb0991SDimitry Andric Out.reset(new ToolOutputFile(OutputFilename, EC, Flags)); 6850b57cec5SDimitry Andric if (EC) { 6860b57cec5SDimitry Andric errs() << EC.message() << '\n'; 6870b57cec5SDimitry Andric return 1; 6880b57cec5SDimitry Andric } 6890b57cec5SDimitry Andric 6900b57cec5SDimitry Andric if (!ThinLinkBitcodeFile.empty()) { 6910b57cec5SDimitry Andric ThinLinkOut.reset( 6928bcb0991SDimitry Andric new ToolOutputFile(ThinLinkBitcodeFile, EC, sys::fs::OF_None)); 6930b57cec5SDimitry Andric if (EC) { 6940b57cec5SDimitry Andric errs() << EC.message() << '\n'; 6950b57cec5SDimitry Andric return 1; 6960b57cec5SDimitry Andric } 6970b57cec5SDimitry Andric } 6980b57cec5SDimitry Andric } 6990b57cec5SDimitry Andric 7000b57cec5SDimitry Andric Triple ModuleTriple(M->getTargetTriple()); 7010b57cec5SDimitry Andric std::string CPUStr, FeaturesStr; 7020b57cec5SDimitry Andric TargetMachine *Machine = nullptr; 703*5ffd83dbSDimitry Andric const TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(); 7040b57cec5SDimitry Andric 7050b57cec5SDimitry Andric if (ModuleTriple.getArch()) { 706*5ffd83dbSDimitry Andric CPUStr = codegen::getCPUStr(); 707*5ffd83dbSDimitry Andric FeaturesStr = codegen::getFeaturesStr(); 7080b57cec5SDimitry Andric Machine = GetTargetMachine(ModuleTriple, CPUStr, FeaturesStr, Options); 7090b57cec5SDimitry Andric } else if (ModuleTriple.getArchName() != "unknown" && 7100b57cec5SDimitry Andric ModuleTriple.getArchName() != "") { 7110b57cec5SDimitry Andric errs() << argv[0] << ": unrecognized architecture '" 7120b57cec5SDimitry Andric << ModuleTriple.getArchName() << "' provided.\n"; 7130b57cec5SDimitry Andric return 1; 7140b57cec5SDimitry Andric } 7150b57cec5SDimitry Andric 7160b57cec5SDimitry Andric std::unique_ptr<TargetMachine> TM(Machine); 7170b57cec5SDimitry Andric 7180b57cec5SDimitry Andric // Override function attributes based on CPUStr, FeaturesStr, and command line 7190b57cec5SDimitry Andric // flags. 720*5ffd83dbSDimitry Andric codegen::setFunctionAttributes(CPUStr, FeaturesStr, *M); 7210b57cec5SDimitry Andric 7220b57cec5SDimitry Andric // If the output is set to be emitted to standard out, and standard out is a 7230b57cec5SDimitry Andric // console, print out a warning message and refuse to do it. We don't 7240b57cec5SDimitry Andric // impress anyone by spewing tons of binary goo to a terminal. 7250b57cec5SDimitry Andric if (!Force && !NoOutput && !AnalyzeOnly && !OutputAssembly) 726*5ffd83dbSDimitry Andric if (CheckBitcodeOutputToConsole(Out->os())) 7270b57cec5SDimitry Andric NoOutput = true; 7280b57cec5SDimitry Andric 7290b57cec5SDimitry Andric if (OutputThinLTOBC) 7300b57cec5SDimitry Andric M->addModuleFlag(Module::Error, "EnableSplitLTOUnit", SplitLTOUnit); 7310b57cec5SDimitry Andric 732*5ffd83dbSDimitry Andric if (EnableNewPassManager || PassPipeline.getNumOccurrences() > 0) { 733*5ffd83dbSDimitry Andric if (PassPipeline.getNumOccurrences() > 0 && PassList.size() > 0) { 734*5ffd83dbSDimitry Andric errs() 735*5ffd83dbSDimitry Andric << "Cannot specify passes via both -foo-pass and --passes=foo-pass"; 736*5ffd83dbSDimitry Andric return 1; 737*5ffd83dbSDimitry Andric } 738*5ffd83dbSDimitry Andric SmallVector<StringRef, 4> Passes; 739*5ffd83dbSDimitry Andric for (const auto &P : PassList) { 740*5ffd83dbSDimitry Andric Passes.push_back(P->getPassArgument()); 741*5ffd83dbSDimitry Andric } 742*5ffd83dbSDimitry Andric if (OptLevelO0) 743*5ffd83dbSDimitry Andric Passes.push_back("default<O0>"); 744*5ffd83dbSDimitry Andric if (OptLevelO1) 745*5ffd83dbSDimitry Andric Passes.push_back("default<O1>"); 746*5ffd83dbSDimitry Andric if (OptLevelO2) 747*5ffd83dbSDimitry Andric Passes.push_back("default<O2>"); 748*5ffd83dbSDimitry Andric if (OptLevelO3) 749*5ffd83dbSDimitry Andric Passes.push_back("default<O3>"); 750*5ffd83dbSDimitry Andric if (OptLevelOs) 751*5ffd83dbSDimitry Andric Passes.push_back("default<Os>"); 752*5ffd83dbSDimitry Andric if (OptLevelOz) 753*5ffd83dbSDimitry Andric Passes.push_back("default<Oz>"); 7540b57cec5SDimitry Andric OutputKind OK = OK_NoOutput; 7550b57cec5SDimitry Andric if (!NoOutput) 7560b57cec5SDimitry Andric OK = OutputAssembly 7570b57cec5SDimitry Andric ? OK_OutputAssembly 7580b57cec5SDimitry Andric : (OutputThinLTOBC ? OK_OutputThinLTOBitcode : OK_OutputBitcode); 7590b57cec5SDimitry Andric 7600b57cec5SDimitry Andric VerifierKind VK = VK_VerifyInAndOut; 7610b57cec5SDimitry Andric if (NoVerify) 7620b57cec5SDimitry Andric VK = VK_NoVerifier; 7630b57cec5SDimitry Andric else if (VerifyEach) 7640b57cec5SDimitry Andric VK = VK_VerifyEachPass; 7650b57cec5SDimitry Andric 7660b57cec5SDimitry Andric // The user has asked to use the new pass manager and provided a pipeline 7670b57cec5SDimitry Andric // string. Hand off the rest of the functionality to the new code for that 7680b57cec5SDimitry Andric // layer. 7690b57cec5SDimitry Andric return runPassPipeline(argv[0], *M, TM.get(), Out.get(), ThinLinkOut.get(), 770*5ffd83dbSDimitry Andric RemarksFile.get(), PassPipeline, Passes, OK, VK, 7710b57cec5SDimitry Andric PreserveAssemblyUseListOrder, 7720b57cec5SDimitry Andric PreserveBitcodeUseListOrder, EmitSummaryIndex, 773*5ffd83dbSDimitry Andric EmitModuleHash, EnableDebugify, Coroutines) 7740b57cec5SDimitry Andric ? 0 7750b57cec5SDimitry Andric : 1; 7760b57cec5SDimitry Andric } 7770b57cec5SDimitry Andric 7780b57cec5SDimitry Andric // Create a PassManager to hold and optimize the collection of passes we are 7790b57cec5SDimitry Andric // about to build. 7800b57cec5SDimitry Andric OptCustomPassManager Passes; 7810b57cec5SDimitry Andric bool AddOneTimeDebugifyPasses = EnableDebugify && !DebugifyEach; 7820b57cec5SDimitry Andric 7830b57cec5SDimitry Andric // Add an appropriate TargetLibraryInfo pass for the module's triple. 7840b57cec5SDimitry Andric TargetLibraryInfoImpl TLII(ModuleTriple); 7850b57cec5SDimitry Andric 7860b57cec5SDimitry Andric // The -disable-simplify-libcalls flag actually disables all builtin optzns. 7870b57cec5SDimitry Andric if (DisableSimplifyLibCalls) 7880b57cec5SDimitry Andric TLII.disableAllFunctions(); 789480093f4SDimitry Andric else { 790480093f4SDimitry Andric // Disable individual builtin functions in TargetLibraryInfo. 791480093f4SDimitry Andric LibFunc F; 792480093f4SDimitry Andric for (auto &FuncName : DisableBuiltins) 793480093f4SDimitry Andric if (TLII.getLibFunc(FuncName, F)) 794480093f4SDimitry Andric TLII.setUnavailable(F); 795480093f4SDimitry Andric else { 796480093f4SDimitry Andric errs() << argv[0] << ": cannot disable nonexistent builtin function " 797480093f4SDimitry Andric << FuncName << '\n'; 798480093f4SDimitry Andric return 1; 799480093f4SDimitry Andric } 800480093f4SDimitry Andric } 801480093f4SDimitry Andric 8020b57cec5SDimitry Andric Passes.add(new TargetLibraryInfoWrapperPass(TLII)); 8030b57cec5SDimitry Andric 8040b57cec5SDimitry Andric // Add internal analysis passes from the target machine. 8050b57cec5SDimitry Andric Passes.add(createTargetTransformInfoWrapperPass(TM ? TM->getTargetIRAnalysis() 8060b57cec5SDimitry Andric : TargetIRAnalysis())); 8070b57cec5SDimitry Andric 8080b57cec5SDimitry Andric if (AddOneTimeDebugifyPasses) 8090b57cec5SDimitry Andric Passes.add(createDebugifyModulePass()); 8100b57cec5SDimitry Andric 8110b57cec5SDimitry Andric std::unique_ptr<legacy::FunctionPassManager> FPasses; 8120b57cec5SDimitry Andric if (OptLevelO0 || OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz || 8130b57cec5SDimitry Andric OptLevelO3) { 8140b57cec5SDimitry Andric FPasses.reset(new legacy::FunctionPassManager(M.get())); 8150b57cec5SDimitry Andric FPasses->add(createTargetTransformInfoWrapperPass( 8160b57cec5SDimitry Andric TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis())); 8170b57cec5SDimitry Andric } 8180b57cec5SDimitry Andric 8190b57cec5SDimitry Andric if (PrintBreakpoints) { 8200b57cec5SDimitry Andric // Default to standard output. 8210b57cec5SDimitry Andric if (!Out) { 8220b57cec5SDimitry Andric if (OutputFilename.empty()) 8230b57cec5SDimitry Andric OutputFilename = "-"; 8240b57cec5SDimitry Andric 8250b57cec5SDimitry Andric std::error_code EC; 8268bcb0991SDimitry Andric Out = std::make_unique<ToolOutputFile>(OutputFilename, EC, 8278bcb0991SDimitry Andric sys::fs::OF_None); 8280b57cec5SDimitry Andric if (EC) { 8290b57cec5SDimitry Andric errs() << EC.message() << '\n'; 8300b57cec5SDimitry Andric return 1; 8310b57cec5SDimitry Andric } 8320b57cec5SDimitry Andric } 8330b57cec5SDimitry Andric Passes.add(createBreakpointPrinter(Out->os())); 8340b57cec5SDimitry Andric NoOutput = true; 8350b57cec5SDimitry Andric } 8360b57cec5SDimitry Andric 8370b57cec5SDimitry Andric if (TM) { 8380b57cec5SDimitry Andric // FIXME: We should dyn_cast this when supported. 8390b57cec5SDimitry Andric auto <M = static_cast<LLVMTargetMachine &>(*TM); 8400b57cec5SDimitry Andric Pass *TPC = LTM.createPassConfig(Passes); 8410b57cec5SDimitry Andric Passes.add(TPC); 8420b57cec5SDimitry Andric } 8430b57cec5SDimitry Andric 8440b57cec5SDimitry Andric // Create a new optimization pass for each one specified on the command line 8450b57cec5SDimitry Andric for (unsigned i = 0; i < PassList.size(); ++i) { 8460b57cec5SDimitry Andric if (StandardLinkOpts && 8470b57cec5SDimitry Andric StandardLinkOpts.getPosition() < PassList.getPosition(i)) { 8480b57cec5SDimitry Andric AddStandardLinkPasses(Passes); 8490b57cec5SDimitry Andric StandardLinkOpts = false; 8500b57cec5SDimitry Andric } 8510b57cec5SDimitry Andric 8520b57cec5SDimitry Andric if (OptLevelO0 && OptLevelO0.getPosition() < PassList.getPosition(i)) { 8530b57cec5SDimitry Andric AddOptimizationPasses(Passes, *FPasses, TM.get(), 0, 0); 8540b57cec5SDimitry Andric OptLevelO0 = false; 8550b57cec5SDimitry Andric } 8560b57cec5SDimitry Andric 8570b57cec5SDimitry Andric if (OptLevelO1 && OptLevelO1.getPosition() < PassList.getPosition(i)) { 8580b57cec5SDimitry Andric AddOptimizationPasses(Passes, *FPasses, TM.get(), 1, 0); 8590b57cec5SDimitry Andric OptLevelO1 = false; 8600b57cec5SDimitry Andric } 8610b57cec5SDimitry Andric 8620b57cec5SDimitry Andric if (OptLevelO2 && OptLevelO2.getPosition() < PassList.getPosition(i)) { 8630b57cec5SDimitry Andric AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 0); 8640b57cec5SDimitry Andric OptLevelO2 = false; 8650b57cec5SDimitry Andric } 8660b57cec5SDimitry Andric 8670b57cec5SDimitry Andric if (OptLevelOs && OptLevelOs.getPosition() < PassList.getPosition(i)) { 8680b57cec5SDimitry Andric AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 1); 8690b57cec5SDimitry Andric OptLevelOs = false; 8700b57cec5SDimitry Andric } 8710b57cec5SDimitry Andric 8720b57cec5SDimitry Andric if (OptLevelOz && OptLevelOz.getPosition() < PassList.getPosition(i)) { 8730b57cec5SDimitry Andric AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 2); 8740b57cec5SDimitry Andric OptLevelOz = false; 8750b57cec5SDimitry Andric } 8760b57cec5SDimitry Andric 8770b57cec5SDimitry Andric if (OptLevelO3 && OptLevelO3.getPosition() < PassList.getPosition(i)) { 8780b57cec5SDimitry Andric AddOptimizationPasses(Passes, *FPasses, TM.get(), 3, 0); 8790b57cec5SDimitry Andric OptLevelO3 = false; 8800b57cec5SDimitry Andric } 8810b57cec5SDimitry Andric 8820b57cec5SDimitry Andric const PassInfo *PassInf = PassList[i]; 8830b57cec5SDimitry Andric Pass *P = nullptr; 8840b57cec5SDimitry Andric if (PassInf->getNormalCtor()) 8850b57cec5SDimitry Andric P = PassInf->getNormalCtor()(); 8860b57cec5SDimitry Andric else 8870b57cec5SDimitry Andric errs() << argv[0] << ": cannot create pass: " 8880b57cec5SDimitry Andric << PassInf->getPassName() << "\n"; 8890b57cec5SDimitry Andric if (P) { 8900b57cec5SDimitry Andric PassKind Kind = P->getPassKind(); 8910b57cec5SDimitry Andric addPass(Passes, P); 8920b57cec5SDimitry Andric 8930b57cec5SDimitry Andric if (AnalyzeOnly) { 8940b57cec5SDimitry Andric switch (Kind) { 8950b57cec5SDimitry Andric case PT_Region: 896*5ffd83dbSDimitry Andric Passes.add(createRegionPassPrinter(PassInf, Out->os())); 8970b57cec5SDimitry Andric break; 8980b57cec5SDimitry Andric case PT_Loop: 899*5ffd83dbSDimitry Andric Passes.add(createLoopPassPrinter(PassInf, Out->os())); 9000b57cec5SDimitry Andric break; 9010b57cec5SDimitry Andric case PT_Function: 902*5ffd83dbSDimitry Andric Passes.add(createFunctionPassPrinter(PassInf, Out->os())); 9030b57cec5SDimitry Andric break; 9040b57cec5SDimitry Andric case PT_CallGraphSCC: 905*5ffd83dbSDimitry Andric Passes.add(createCallGraphPassPrinter(PassInf, Out->os())); 9060b57cec5SDimitry Andric break; 9070b57cec5SDimitry Andric default: 908*5ffd83dbSDimitry Andric Passes.add(createModulePassPrinter(PassInf, Out->os())); 9090b57cec5SDimitry Andric break; 9100b57cec5SDimitry Andric } 9110b57cec5SDimitry Andric } 9120b57cec5SDimitry Andric } 9130b57cec5SDimitry Andric 9140b57cec5SDimitry Andric if (PrintEachXForm) 9150b57cec5SDimitry Andric Passes.add( 9160b57cec5SDimitry Andric createPrintModulePass(errs(), "", PreserveAssemblyUseListOrder)); 9170b57cec5SDimitry Andric } 9180b57cec5SDimitry Andric 9190b57cec5SDimitry Andric if (StandardLinkOpts) { 9200b57cec5SDimitry Andric AddStandardLinkPasses(Passes); 9210b57cec5SDimitry Andric StandardLinkOpts = false; 9220b57cec5SDimitry Andric } 9230b57cec5SDimitry Andric 9240b57cec5SDimitry Andric if (OptLevelO0) 9250b57cec5SDimitry Andric AddOptimizationPasses(Passes, *FPasses, TM.get(), 0, 0); 9260b57cec5SDimitry Andric 9270b57cec5SDimitry Andric if (OptLevelO1) 9280b57cec5SDimitry Andric AddOptimizationPasses(Passes, *FPasses, TM.get(), 1, 0); 9290b57cec5SDimitry Andric 9300b57cec5SDimitry Andric if (OptLevelO2) 9310b57cec5SDimitry Andric AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 0); 9320b57cec5SDimitry Andric 9330b57cec5SDimitry Andric if (OptLevelOs) 9340b57cec5SDimitry Andric AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 1); 9350b57cec5SDimitry Andric 9360b57cec5SDimitry Andric if (OptLevelOz) 9370b57cec5SDimitry Andric AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 2); 9380b57cec5SDimitry Andric 9390b57cec5SDimitry Andric if (OptLevelO3) 9400b57cec5SDimitry Andric AddOptimizationPasses(Passes, *FPasses, TM.get(), 3, 0); 9410b57cec5SDimitry Andric 9420b57cec5SDimitry Andric if (FPasses) { 9430b57cec5SDimitry Andric FPasses->doInitialization(); 9440b57cec5SDimitry Andric for (Function &F : *M) 9450b57cec5SDimitry Andric FPasses->run(F); 9460b57cec5SDimitry Andric FPasses->doFinalization(); 9470b57cec5SDimitry Andric } 9480b57cec5SDimitry Andric 9490b57cec5SDimitry Andric // Check that the module is well formed on completion of optimization 9500b57cec5SDimitry Andric if (!NoVerify && !VerifyEach) 9510b57cec5SDimitry Andric Passes.add(createVerifierPass()); 9520b57cec5SDimitry Andric 9530b57cec5SDimitry Andric if (AddOneTimeDebugifyPasses) 9540b57cec5SDimitry Andric Passes.add(createCheckDebugifyModulePass(false)); 9550b57cec5SDimitry Andric 9560b57cec5SDimitry Andric // In run twice mode, we want to make sure the output is bit-by-bit 9570b57cec5SDimitry Andric // equivalent if we run the pass manager again, so setup two buffers and 9580b57cec5SDimitry Andric // a stream to write to them. Note that llc does something similar and it 9590b57cec5SDimitry Andric // may be worth to abstract this out in the future. 9600b57cec5SDimitry Andric SmallVector<char, 0> Buffer; 9610b57cec5SDimitry Andric SmallVector<char, 0> FirstRunBuffer; 9620b57cec5SDimitry Andric std::unique_ptr<raw_svector_ostream> BOS; 9630b57cec5SDimitry Andric raw_ostream *OS = nullptr; 9640b57cec5SDimitry Andric 965480093f4SDimitry Andric const bool ShouldEmitOutput = !NoOutput && !AnalyzeOnly; 966480093f4SDimitry Andric 9670b57cec5SDimitry Andric // Write bitcode or assembly to the output as the last step... 968480093f4SDimitry Andric if (ShouldEmitOutput || RunTwice) { 9690b57cec5SDimitry Andric assert(Out); 9700b57cec5SDimitry Andric OS = &Out->os(); 9710b57cec5SDimitry Andric if (RunTwice) { 9728bcb0991SDimitry Andric BOS = std::make_unique<raw_svector_ostream>(Buffer); 9730b57cec5SDimitry Andric OS = BOS.get(); 9740b57cec5SDimitry Andric } 9750b57cec5SDimitry Andric if (OutputAssembly) { 9760b57cec5SDimitry Andric if (EmitSummaryIndex) 9770b57cec5SDimitry Andric report_fatal_error("Text output is incompatible with -module-summary"); 9780b57cec5SDimitry Andric if (EmitModuleHash) 9790b57cec5SDimitry Andric report_fatal_error("Text output is incompatible with -module-hash"); 9800b57cec5SDimitry Andric Passes.add(createPrintModulePass(*OS, "", PreserveAssemblyUseListOrder)); 9810b57cec5SDimitry Andric } else if (OutputThinLTOBC) 9820b57cec5SDimitry Andric Passes.add(createWriteThinLTOBitcodePass( 9830b57cec5SDimitry Andric *OS, ThinLinkOut ? &ThinLinkOut->os() : nullptr)); 9840b57cec5SDimitry Andric else 9850b57cec5SDimitry Andric Passes.add(createBitcodeWriterPass(*OS, PreserveBitcodeUseListOrder, 9860b57cec5SDimitry Andric EmitSummaryIndex, EmitModuleHash)); 9870b57cec5SDimitry Andric } 9880b57cec5SDimitry Andric 9890b57cec5SDimitry Andric // Before executing passes, print the final values of the LLVM options. 9900b57cec5SDimitry Andric cl::PrintOptionValues(); 9910b57cec5SDimitry Andric 9920b57cec5SDimitry Andric if (!RunTwice) { 9930b57cec5SDimitry Andric // Now that we have all of the passes ready, run them. 9940b57cec5SDimitry Andric Passes.run(*M); 9950b57cec5SDimitry Andric } else { 9960b57cec5SDimitry Andric // If requested, run all passes twice with the same pass manager to catch 9970b57cec5SDimitry Andric // bugs caused by persistent state in the passes. 9980b57cec5SDimitry Andric std::unique_ptr<Module> M2(CloneModule(*M)); 9990b57cec5SDimitry Andric // Run all passes on the original module first, so the second run processes 10000b57cec5SDimitry Andric // the clone to catch CloneModule bugs. 10010b57cec5SDimitry Andric Passes.run(*M); 10020b57cec5SDimitry Andric FirstRunBuffer = Buffer; 10030b57cec5SDimitry Andric Buffer.clear(); 10040b57cec5SDimitry Andric 10050b57cec5SDimitry Andric Passes.run(*M2); 10060b57cec5SDimitry Andric 10070b57cec5SDimitry Andric // Compare the two outputs and make sure they're the same 10080b57cec5SDimitry Andric assert(Out); 10090b57cec5SDimitry Andric if (Buffer.size() != FirstRunBuffer.size() || 10100b57cec5SDimitry Andric (memcmp(Buffer.data(), FirstRunBuffer.data(), Buffer.size()) != 0)) { 10110b57cec5SDimitry Andric errs() 10120b57cec5SDimitry Andric << "Running the pass manager twice changed the output.\n" 10130b57cec5SDimitry Andric "Writing the result of the second run to the specified output.\n" 10140b57cec5SDimitry Andric "To generate the one-run comparison binary, just run without\n" 10150b57cec5SDimitry Andric "the compile-twice option\n"; 1016480093f4SDimitry Andric if (ShouldEmitOutput) { 10170b57cec5SDimitry Andric Out->os() << BOS->str(); 10180b57cec5SDimitry Andric Out->keep(); 1019480093f4SDimitry Andric } 10200b57cec5SDimitry Andric if (RemarksFile) 10210b57cec5SDimitry Andric RemarksFile->keep(); 10220b57cec5SDimitry Andric return 1; 10230b57cec5SDimitry Andric } 1024480093f4SDimitry Andric if (ShouldEmitOutput) 10250b57cec5SDimitry Andric Out->os() << BOS->str(); 10260b57cec5SDimitry Andric } 10270b57cec5SDimitry Andric 10280b57cec5SDimitry Andric if (DebugifyEach && !DebugifyExport.empty()) 10290b57cec5SDimitry Andric exportDebugifyStats(DebugifyExport, Passes.getDebugifyStatsMap()); 10300b57cec5SDimitry Andric 10310b57cec5SDimitry Andric // Declare success. 10320b57cec5SDimitry Andric if (!NoOutput || PrintBreakpoints) 10330b57cec5SDimitry Andric Out->keep(); 10340b57cec5SDimitry Andric 10350b57cec5SDimitry Andric if (RemarksFile) 10360b57cec5SDimitry Andric RemarksFile->keep(); 10370b57cec5SDimitry Andric 10380b57cec5SDimitry Andric if (ThinLinkOut) 10390b57cec5SDimitry Andric ThinLinkOut->keep(); 10400b57cec5SDimitry Andric 10410b57cec5SDimitry Andric return 0; 10420b57cec5SDimitry Andric } 1043