Index: include/llvm/IR/LLVMContext.h =================================================================== --- include/llvm/IR/LLVMContext.h +++ include/llvm/IR/LLVMContext.h @@ -104,6 +104,15 @@ /// Remove the GC for a function void deleteGC(const Function &Fn); + /// Return true if the Context runtime configuration is set to discard all + /// value names. When true, only GlobalValue names will be available in the + /// IR. + bool discardValueNames(); + + /// Set the Context runtime configuration to discard all value name (but + /// GlobalValue). Clients can use this flag to save memory and runtime, + /// especially in release mode. + void setDiscardValueNames(bool Discard); typedef void (*InlineAsmDiagHandlerTy)(const SMDiagnostic&, void *Context, unsigned LocCookie); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -46,6 +46,11 @@ // Prime the lexer. Lex.Lex(); + if (Context.discardValueNames()) + return Error( + Lex.getLoc(), + "Can't read textual IR with a Context that discards named Values"); + return ParseTopLevelEntities() || ValidateEndOfModule(); } Index: lib/IR/LLVMContext.cpp =================================================================== --- lib/IR/LLVMContext.cpp +++ lib/IR/LLVMContext.cpp @@ -325,3 +325,9 @@ void LLVMContext::deleteGC(const Function &Fn) { pImpl->GCNames.erase(&Fn); } + +bool LLVMContext::discardValueNames() { return pImpl->DiscardValueNames; } + +void LLVMContext::setDiscardValueNames(bool Discard) { + pImpl->DiscardValueNames = Discard; +} Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -1034,6 +1034,10 @@ /// clients which do use GC. DenseMap GCNames; + /// Flag to indicate if Value (other than GlobalValue) retains their name or + /// not. + bool DiscardValueNames = false; + LLVMContextImpl(LLVMContext &C); ~LLVMContextImpl(); Index: lib/IR/Value.cpp =================================================================== --- lib/IR/Value.cpp +++ lib/IR/Value.cpp @@ -198,6 +198,10 @@ } void Value::setNameImpl(const Twine &NewName) { + // Fast-path: LLVMContext can be set to strip out non-GlobalValue names + if (getContext().discardValueNames() && !isa(this)) + return; + // Fast path for common IRBuilder case of setName("") when there is no name. if (NewName.isTriviallyEmpty() && !hasName()) return; Index: lib/LTO/LTOCodeGenerator.cpp =================================================================== --- lib/LTO/LTOCodeGenerator.cpp +++ lib/LTO/LTOCodeGenerator.cpp @@ -65,9 +65,22 @@ #endif } +namespace llvm { +cl::opt LTODiscardValueNames( + "discard-value-names", + cl::desc("Strip names from Value (other than GlobalValue)."), +#ifdef NDEBUG + cl::init(true), +#else + cl::init(false), +#endif + cl::Hidden); +} + LTOCodeGenerator::LTOCodeGenerator(LLVMContext &Context) : Context(Context), MergedModule(new Module("ld-temp.o", Context)), TheLinker(new Linker(*MergedModule)) { + Context.setDiscardValueNames(LTODiscardValueNames); initializeLTOPasses(); } Index: lib/LTO/ThinLTOCodeGenerator.cpp =================================================================== --- lib/LTO/ThinLTOCodeGenerator.cpp +++ lib/LTO/ThinLTOCodeGenerator.cpp @@ -41,6 +41,11 @@ using namespace llvm; +namespace llvm { +// Flags -discard-value-names, defined in LTOCodeGenerator.cpp +extern cl::opt LTODiscardValueNames; +} + namespace { static cl::opt ThreadCount("threads", @@ -361,6 +366,7 @@ for (auto &ModuleBuffer : Modules) { Pool.async([&](int count) { LLVMContext Context; + Context.setDiscardValueNames(LTODiscardValueNames); // Parse module now auto TheModule = loadModuleFromBuffer(ModuleBuffer, Context, false); Index: test/Feature/strip_names.ll =================================================================== --- /dev/null +++ test/Feature/strip_names.ll @@ -0,0 +1,26 @@ +; RUN: opt < %s -S | FileCheck %s +; RUN: opt < %s | opt -S -discard-value-names | FileCheck --check-prefix=NONAME %s + + +; CHECK: @GlobalValueName +; CHECK: @foo(i32 %in) +; CHECK: somelabel: +; CHECK: %GV = load i32, i32* @GlobalValueName +; CHECK: %add = add i32 %in, %GV +; CHECK: ret i32 %add + +; NONAME: @GlobalValueName +; NONAME: @foo(i32) +; NONAME-NOT: somelabel: +; NONAME: %2 = load i32, i32* @GlobalValueName +; NONAME: %3 = add i32 %0, %2 +; NONAME: ret i32 %3 + +@GlobalValueName = global i32 0 + +define i32 @foo(i32 %in) { +somelabel: + %GV = load i32, i32* @GlobalValueName + %add = add i32 %in, %GV + ret i32 %add +} Index: tools/llc/llc.cpp =================================================================== --- tools/llc/llc.cpp +++ tools/llc/llc.cpp @@ -103,6 +103,11 @@ "manager and verify the result is the same."), cl::init(false)); +static cl::opt DiscardValueNames( + "discard-value-names", + cl::desc("Discard names from Value (other than GlobalValue)."), + cl::init(false), cl::Hidden); + static int compileModule(char **, LLVMContext &); static std::unique_ptr @@ -205,6 +210,8 @@ cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n"); + Context.setDiscardValueNames(DiscardValueNames); + // Compile the module TimeCompilations times to give better compile time // metrics. for (unsigned I = TimeCompilations; I; --I) Index: tools/opt/opt.cpp =================================================================== --- tools/opt/opt.cpp +++ tools/opt/opt.cpp @@ -196,6 +196,11 @@ cl::desc("Run all passes twice, re-using the same pass manager."), cl::init(false), cl::Hidden); +static cl::opt DiscardValueNames( + "discard-value-names", + cl::desc("Discard names from Value (other than GlobalValue)."), + cl::init(false), cl::Hidden); + static inline void addPass(legacy::PassManagerBase &PM, Pass *P) { // Add the pass to the pass manager... PM.add(P); @@ -346,6 +351,8 @@ SMDiagnostic Err; + Context.setDiscardValueNames(DiscardValueNames); + // Load the input module... std::unique_ptr M = parseIRFile(InputFilename, Err, Context);