Index: llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h =================================================================== --- llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h +++ llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h @@ -175,6 +175,10 @@ /// Calls \a verifyMergedModuleOnce(). bool compileOptimized(ArrayRef Out); + /// Enabled the Freestanding mode: indicates that the optimizer should not + /// assume builtins are present on the target. + void setFreestanding(bool Enabled) { Freestanding = Enabled; } + void setDiagnosticHandler(lto_diagnostic_handler_t, void *); LLVMContext &getContext() { return Context; } @@ -237,6 +241,7 @@ bool ShouldRestoreGlobalsLinkage = false; TargetMachine::CodeGenFileType FileType = TargetMachine::CGFT_ObjectFile; std::unique_ptr DiagnosticOutputFile; + bool Freestanding = false; }; } #endif Index: llvm/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h =================================================================== --- llvm/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h +++ llvm/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h @@ -205,6 +205,10 @@ TMBuilder.Options = std::move(Options); } + /// Enabled the Freestanding mode: indicates that the optimizer should not + /// assume builtins are present on the target. + void setFreestanding(bool Enabled) { Freestanding = Enabled; } + /// CodeModel void setCodePICModel(Optional Model) { TMBuilder.RelocModel = Model; @@ -322,6 +326,10 @@ /// importing or optimization. bool CodeGenOnly = false; + /// Flag to indicate that the optimizer should not assume builtins are present + /// on the target. + bool Freestanding = false; + /// IR Optimization Level [0-3]. unsigned OptLevel = 3; }; Index: llvm/lib/LTO/LTOCodeGenerator.cpp =================================================================== --- llvm/lib/LTO/LTOCodeGenerator.cpp +++ llvm/lib/LTO/LTOCodeGenerator.cpp @@ -554,6 +554,8 @@ if (!DisableInline) PMB.Inliner = createFunctionInliningPass(); PMB.LibraryInfo = new TargetLibraryInfoImpl(TargetTriple); + if (Freestanding) + PMB.LibraryInfo->disableAllFunctions(); PMB.OptLevel = OptLevel; PMB.VerifyInput = !DisableVerify; PMB.VerifyOutput = !DisableVerify; Index: llvm/lib/LTO/ThinLTOCodeGenerator.cpp =================================================================== --- llvm/lib/LTO/ThinLTOCodeGenerator.cpp +++ llvm/lib/LTO/ThinLTOCodeGenerator.cpp @@ -187,10 +187,12 @@ } static void optimizeModule(Module &TheModule, TargetMachine &TM, - unsigned OptLevel) { + unsigned OptLevel, bool Freestanding) { // Populate the PassManager PassManagerBuilder PMB; PMB.LibraryInfo = new TargetLibraryInfoImpl(TM.getTargetTriple()); + if (Freestanding) + PMB.LibraryInfo->disableAllFunctions(); PMB.Inliner = createFunctionInliningPass(); // FIXME: should get it from the bitcode? PMB.OptLevel = OptLevel; @@ -401,7 +403,8 @@ const GVSummaryMapTy &DefinedGlobals, const ThinLTOCodeGenerator::CachingOptions &CacheOptions, bool DisableCodeGen, StringRef SaveTempsDir, - unsigned OptLevel, unsigned count) { + bool Freestanding, unsigned OptLevel, + unsigned count) { // "Benchmark"-like optimization: single-source case bool SingleModule = (ModuleMap.size() == 1); @@ -433,7 +436,7 @@ saveTempBitcode(TheModule, SaveTempsDir, count, ".3.imported.bc"); } - optimizeModule(TheModule, TM, OptLevel); + optimizeModule(TheModule, TM, OptLevel, Freestanding); saveTempBitcode(TheModule, SaveTempsDir, count, ".4.opt.bc"); @@ -759,7 +762,7 @@ initTMBuilder(TMBuilder, Triple(TheModule.getTargetTriple())); // Optimize now - optimizeModule(TheModule, *TMBuilder.create(), OptLevel); + optimizeModule(TheModule, *TMBuilder.create(), OptLevel, Freestanding); } /** @@ -991,7 +994,7 @@ *TheModule, *Index, ModuleMap, *TMBuilder.create(), ImportList, ExportList, GUIDPreservedSymbols, ModuleToDefinedGVSummaries[ModuleIdentifier], CacheOptions, - DisableCodeGen, SaveTempsDir, OptLevel, count); + DisableCodeGen, SaveTempsDir, Freestanding, OptLevel, count); // Commit to the cache (if enabled) CacheEntry.write(*OutputBuffer); Index: llvm/test/ThinLTO/X86/tli-nobuiltin.ll =================================================================== --- /dev/null +++ llvm/test/ThinLTO/X86/tli-nobuiltin.ll @@ -0,0 +1,46 @@ +; Test -lto-freestanding option for libLTO. +; RUN: llvm-as < %s > %t.bc + +; Regular run: expects fprintf to be turned into fwrite +; RUN: llvm-lto %t.bc -exported-symbol=_foo -o %t.o +; RUN: llvm-nm %t.o | FileCheck %s --check-prefix=LTO +; LTO: fwrite + +; Freestanding run: expects fprintf to NOT be turned into fwrite +; RUN: llvm-lto %t.bc -lto-freestanding -exported-symbol=_foo -o %t.o +; RUN: llvm-nm %t.o | FileCheck %s --check-prefix=LTO-FREESTANDING +; LTO-FREESTANDING: fprintf + +; Same with ThinLTO now. +; RUN: opt -module-hash -module-summary %s -o %t.bc + +; Regular run: expects fprintf to be turned into fwrite +; RUN: llvm-lto -exported-symbol=_foo -thinlto-action=run %t.bc +; RUN: llvm-nm %t.bc.thinlto.o | FileCheck %s --check-prefix=ThinLTO +; ThinLTO: fwrite + +; Freestanding run: expects fprintf to NOT be turned into fwrite +; RUN: llvm-lto -lto-freestanding -exported-symbol=_foo -thinlto-action=run %t.bc +; RUN: llvm-nm %t.bc.thinlto.o | FileCheck %s --check-prefix=ThinLTO-FREESTANDING +; ThinLTO-FREESTANDING: fprintf + + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + +declare i32 @fprintf(%FILE*, i8*, ...) + +%FILE = type { } + +@hello_world = constant [13 x i8] c"hello world\0A\00" +@percent_s = constant [3 x i8] c"%s\00" + +; Check fprintf(fp, "%s", str) -> fwrite(str, fp) only when builtins are enabled + +define void @foo(%FILE* %fp) { + %fmt = getelementptr [3 x i8], [3 x i8]* @percent_s, i32 0, i32 0 + %str = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0 + call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* %fmt, i8* %str) + ret void +} + Index: llvm/tools/llvm-lto/llvm-lto.cpp =================================================================== --- llvm/tools/llvm-lto/llvm-lto.cpp +++ llvm/tools/llvm-lto/llvm-lto.cpp @@ -63,6 +63,10 @@ "disable-lto-vectorization", cl::init(false), cl::desc("Do not run loop or slp vectorization during LTO")); +static cl::opt + EnableFreestanding("lto-freestanding", cl::init(false), + cl::desc("Enable Freestanding (disable builtins / TLI) during LTO")); + static cl::opt UseDiagnosticHandler( "use-diagnostic-handler", cl::init(false), cl::desc("Use a diagnostic handler to test the handler interface")); @@ -433,6 +437,7 @@ ThinGenerator.setCodePICModel(getRelocModel()); ThinGenerator.setTargetOptions(Options); ThinGenerator.setCacheDir(ThinLTOCacheDir); + ThinGenerator.setFreestanding(EnableFreestanding); // Add all the exported symbols to the table of symbols to preserve. for (unsigned i = 0; i < ExportedSymbols.size(); ++i) @@ -809,6 +814,8 @@ CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr); CodeGen.setCodePICModel(getRelocModel()); + CodeGen.setFreestanding(EnableFreestanding); + CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF); CodeGen.setTargetOptions(Options); Index: llvm/tools/lto/lto.cpp =================================================================== --- llvm/tools/lto/lto.cpp +++ llvm/tools/lto/lto.cpp @@ -44,9 +44,13 @@ DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false), cl::desc("Do not run the GVN load PRE pass")); +static cl::opt DisableLTOVectorization( + "disable-lto-vectorization", cl::init(false), + cl::desc("Do not run loop or slp vectorization during LTO")); + static cl::opt -DisableLTOVectorization("disable-lto-vectorization", cl::init(false), - cl::desc("Do not run loop or slp vectorization during LTO")); + EnableFreestanding("lto-freestanding", cl::init(false), + cl::desc("Enable Freestanding (disable builtins / TLI) during LTO")); #ifdef NDEBUG static bool VerifyByDefault = false; @@ -159,6 +163,8 @@ if (OptLevel < '0' || OptLevel > '3') report_fatal_error("Optimization level must be between 0 and 3"); CG->setOptLevel(OptLevel - '0'); + CG->setFreestanding(EnableFreestanding); + } extern const char* lto_get_version() { @@ -464,6 +470,7 @@ lto_initialize(); ThinLTOCodeGenerator *CodeGen = new ThinLTOCodeGenerator(); CodeGen->setTargetOptions(InitTargetOptionsFromCodeGenFlags()); + CodeGen->setFreestanding(EnableFreestanding); if (OptLevel.getNumOccurrences()) { if (OptLevel < '0' || OptLevel > '3')