Index: llvm/trunk/include/llvm/LTO/legacy/LTOCodeGenerator.h =================================================================== --- llvm/trunk/include/llvm/LTO/legacy/LTOCodeGenerator.h +++ llvm/trunk/include/llvm/LTO/legacy/LTOCodeGenerator.h @@ -175,6 +175,10 @@ /// Calls \a verifyMergedModuleOnce(). bool compileOptimized(ArrayRef Out); + /// Enable the Freestanding mode: indicate 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/trunk/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h =================================================================== --- llvm/trunk/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h +++ llvm/trunk/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h @@ -205,6 +205,10 @@ TMBuilder.Options = std::move(Options); } + /// Enable the Freestanding mode: indicate 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/trunk/lib/LTO/LTOCodeGenerator.cpp =================================================================== --- llvm/trunk/lib/LTO/LTOCodeGenerator.cpp +++ llvm/trunk/lib/LTO/LTOCodeGenerator.cpp @@ -555,6 +555,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/trunk/lib/LTO/ThinLTOCodeGenerator.cpp =================================================================== --- llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp +++ llvm/trunk/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; @@ -264,7 +266,7 @@ const std::map &ResolvedODR, const GVSummaryMapTy &DefinedFunctions, const DenseSet &PreservedSymbols, unsigned OptLevel, - const TargetMachineBuilder &TMBuilder) { + bool Freestanding, const TargetMachineBuilder &TMBuilder) { if (CachePath.empty()) return; @@ -321,6 +323,7 @@ AddUnsigned(*TMBuilder.RelocModel); AddUnsigned(TMBuilder.CGOptLevel); AddUnsigned(OptLevel); + AddUnsigned(Freestanding); Hasher.update(ArrayRef((uint8_t *)&ModHash[0], sizeof(ModHash))); for (auto F : ExportList) @@ -404,7 +407,7 @@ 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); @@ -436,7 +439,7 @@ saveTempBitcode(TheModule, SaveTempsDir, count, ".3.imported.bc"); } - optimizeModule(TheModule, TM, OptLevel); + optimizeModule(TheModule, TM, OptLevel, Freestanding); saveTempBitcode(TheModule, SaveTempsDir, count, ".4.opt.bc"); @@ -762,7 +765,7 @@ initTMBuilder(TMBuilder, Triple(TheModule.getTargetTriple())); // Optimize now - optimizeModule(TheModule, *TMBuilder.create(), OptLevel); + optimizeModule(TheModule, *TMBuilder.create(), OptLevel, Freestanding); } /** @@ -948,7 +951,7 @@ ImportLists[ModuleIdentifier], ExportList, ResolvedODR[ModuleIdentifier], DefinedFunctions, GUIDPreservedSymbols, - OptLevel, TMBuilder); + OptLevel, Freestanding, TMBuilder); auto CacheEntryPath = CacheEntry.getEntryPath(); { @@ -994,7 +997,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/trunk/test/ThinLTO/X86/tli-nobuiltin.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/tli-nobuiltin.ll +++ llvm/trunk/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/trunk/tools/llvm-lto/llvm-lto.cpp =================================================================== --- llvm/trunk/tools/llvm-lto/llvm-lto.cpp +++ llvm/trunk/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,7 @@ CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr); CodeGen.setCodePICModel(getRelocModel()); + CodeGen.setFreestanding(EnableFreestanding); CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF); CodeGen.setTargetOptions(Options); Index: llvm/trunk/tools/lto/lto.cpp =================================================================== --- llvm/trunk/tools/lto/lto.cpp +++ llvm/trunk/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")); + +static cl::opt EnableFreestanding( + "lto-freestanding", cl::init(false), + cl::desc("Enable Freestanding (disable builtins / TLI) during LTO")); #ifdef NDEBUG static bool VerifyByDefault = false; @@ -159,6 +163,7 @@ 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 +469,7 @@ lto_initialize(); ThinLTOCodeGenerator *CodeGen = new ThinLTOCodeGenerator(); CodeGen->setTargetOptions(InitTargetOptionsFromCodeGenFlags()); + CodeGen->setFreestanding(EnableFreestanding); if (OptLevel.getNumOccurrences()) { if (OptLevel < '0' || OptLevel > '3')