[llvm] r191922 - Optimize linkonce_odr unnamed_addr functions during LTO.
Richard Smith
richard at metafoo.co.uk
Thu Oct 3 16:38:11 PDT 2013
On Thu, Oct 3, 2013 at 11:29 AM, Rafael Espindola <
rafael.espindola at gmail.com> wrote:
> Author: rafael
> Date: Thu Oct 3 13:29:09 2013
> New Revision: 191922
>
> URL: http://llvm.org/viewvc/llvm-project?rev=191922&view=rev
> Log:
> Optimize linkonce_odr unnamed_addr functions during LTO.
>
> Generalize the API so we can distinguish symbols that are needed just for
> a DSO
> symbol table from those that are used from some native .o.
>
> The symbols that are only wanted for the dso symbol table can be dropped if
> llvm can prove every other dso has a copy (linkonce_odr) and the address
> is not
> important (unnamed_addr).
>
> Modified:
> llvm/trunk/include/llvm-c/lto.h
> llvm/trunk/include/llvm/LTO/LTOCodeGenerator.h
> llvm/trunk/include/llvm/Transforms/IPO.h
> llvm/trunk/lib/LTO/LTOCodeGenerator.cpp
> llvm/trunk/lib/Transforms/IPO/IPO.cpp
> llvm/trunk/lib/Transforms/IPO/Internalize.cpp
> llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp
> llvm/trunk/test/LTO/cfi_endproc.ll
> llvm/trunk/test/Transforms/Internalize/lists.ll
> llvm/trunk/tools/gold/gold-plugin.cpp
> llvm/trunk/tools/llvm-lto/llvm-lto.cpp
> llvm/trunk/tools/lto/lto.cpp
>
> Modified: llvm/trunk/include/llvm-c/lto.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm-c/lto.h?rev=191922&r1=191921&r2=191922&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm-c/lto.h (original)
> +++ llvm/trunk/include/llvm-c/lto.h Thu Oct 3 13:29:09 2013
> @@ -29,7 +29,7 @@
> * @{
> */
>
> -#define LTO_API_VERSION 4
> +#define LTO_API_VERSION 5
>
> typedef enum {
> LTO_SYMBOL_ALIGNMENT_MASK = 0x0000001F, /* log2 of
> alignment */
> @@ -253,13 +253,21 @@ lto_codegen_set_assembler_args(lto_code_
> int nargs);
>
> /**
> - * Adds to a list of all global symbols that must exist in the final
> - * generated code. If a function is not listed, it might be
> - * inlined into every usage and optimized away.
> + * Tells LTO optimization passes that this symbol must be preserved
> + * because it is referenced by native code or a command line option.
> */
> extern void
> lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg, const char*
> symbol);
>
> +
> +/**
> + * Tells LTO optimization passes that a dynamic shared library is being
> + * built and this symbol may be exported. Unless IR semantics allow the
> symbol
> + * to be made local to the library, it should remain so it can be
> exported by
> + * the shared library.
> + */
> +extern void lto_codegen_add_dso_symbol(lto_code_gen_t cg, const char
> *symbol);
> +
> /**
> * Writes a new object file at the specified path that contains the
> * merged contents of all modules added so far.
>
> Modified: llvm/trunk/include/llvm/LTO/LTOCodeGenerator.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/LTO/LTOCodeGenerator.h?rev=191922&r1=191921&r2=191922&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/LTO/LTOCodeGenerator.h (original)
> +++ llvm/trunk/include/llvm/LTO/LTOCodeGenerator.h Thu Oct 3 13:29:09 2013
> @@ -73,6 +73,10 @@ struct LTOCodeGenerator {
>
> void addMustPreserveSymbol(const char *sym) { MustPreserveSymbols[sym]
> = 1; }
>
> + void addDSOSymbol(const char* Sym) {
> + DSOSymbols[Sym] = 1;
> + }
> +
> // To pass options to the driver and optimization passes. These options
> are
> // not necessarily for debugging purpose (The function name is
> misleading).
> // This function should be called before LTOCodeGenerator::compilexxx(),
> @@ -126,6 +130,7 @@ private:
> void applyScopeRestrictions();
> void applyRestriction(llvm::GlobalValue &GV,
> std::vector<const char*> &MustPreserveList,
> + std::vector<const char*> &SymtabList,
> llvm::SmallPtrSet<llvm::GlobalValue*, 8> &AsmUsed,
> llvm::Mangler &Mangler);
> bool determineTarget(std::string &errMsg);
> @@ -138,6 +143,7 @@ private:
> bool EmitDwarfDebugInfo;
> bool ScopeRestrictionsDone;
> lto_codegen_model CodeModel;
> + StringSet DSOSymbols;
> StringSet MustPreserveSymbols;
> StringSet AsmUndefinedRefs;
> llvm::MemoryBuffer *NativeObjectFile;
>
> Modified: llvm/trunk/include/llvm/Transforms/IPO.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO.h?rev=191922&r1=191921&r2=191922&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Transforms/IPO.h (original)
> +++ llvm/trunk/include/llvm/Transforms/IPO.h Thu Oct 3 13:29:09 2013
> @@ -104,12 +104,32 @@ Pass *createPruneEHPass();
>
>
> //===----------------------------------------------------------------------===//
> /// createInternalizePass - This pass loops over all of the functions in
> the
> -/// input module, internalizing all globals (functions and variables) not
> in the
> -/// given exportList.
> +/// input module, internalizing all globals (functions and variables) it
> can.
> +////
> +/// The symbols in \p ExportList are never internalized.
> +///
> +/// The symbol in DSOList are internalized if it is safe to drop them from
> +/// the symbol table.
> +///
> +/// For example of the difference, consider a dynamic library being built
> from
> +/// two translation units. The first one compiled to a native object
> +/// (ELF/MachO/COFF) and second one compiled to IL. Translation unit A
> has a
> +/// copy of linkonce_odr unnamed_addr function F. The translation unit B
> has a
> +/// copy of the linkonce_odr unnamed_addr functions F and G.
> +///
> +/// Assume the linker decides to keep the copy of F in B. This means that
> LLVM
> +/// must produce F in the object file it passes to the linker, otherwise
> we
> +/// will have an undefined reference. For G the situation is different.
> The
> +/// linker puts the function in the DSOList, since it is only wanted for
> the
> +/// symbol table. With this information internalize can now reason that
> since
> +/// the function is a linkonce_odr and its address is not important, it
> can be
> +/// omitted. Any other shared library needing this function will have a
> copy of
> +/// it.
> ///
> /// Note that commandline options that are used with the above function
> are not
> /// used now!
> -ModulePass *createInternalizePass(ArrayRef<const char *> ExportList);
> +ModulePass *createInternalizePass(ArrayRef<const char *> ExportList,
> + ArrayRef<const char *> DSOList);
> /// createInternalizePass - Same as above, but with an empty exportList.
> ModulePass *createInternalizePass();
>
>
> Modified: llvm/trunk/lib/LTO/LTOCodeGenerator.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/LTO/LTOCodeGenerator.cpp?rev=191922&r1=191921&r2=191922&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/LTO/LTOCodeGenerator.cpp (original)
> +++ llvm/trunk/lib/LTO/LTOCodeGenerator.cpp Thu Oct 3 13:29:09 2013
> @@ -310,6 +310,7 @@ bool LTOCodeGenerator::determineTarget(s
> void LTOCodeGenerator::
> applyRestriction(GlobalValue &GV,
> std::vector<const char*> &MustPreserveList,
> + std::vector<const char*> &DSOList,
> SmallPtrSet<GlobalValue*, 8> &AsmUsed,
> Mangler &Mangler) {
> SmallString<64> Buffer;
> @@ -319,6 +320,8 @@ applyRestriction(GlobalValue &GV,
> return;
> if (MustPreserveSymbols.count(Buffer))
> MustPreserveList.push_back(GV.getName().data());
> + if (DSOSymbols.count(Buffer))
> + DSOList.push_back(GV.getName().data());
> if (AsmUndefinedRefs.count(Buffer))
> AsmUsed.insert(&GV);
> }
> @@ -348,17 +351,18 @@ void LTOCodeGenerator::applyScopeRestric
> NULL);
> Mangler Mangler(MContext, TargetMach);
> std::vector<const char*> MustPreserveList;
> + std::vector<const char*> DSOList;
> SmallPtrSet<GlobalValue*, 8> AsmUsed;
>
> for (Module::iterator f = mergedModule->begin(),
> e = mergedModule->end(); f != e; ++f)
> - applyRestriction(*f, MustPreserveList, AsmUsed, Mangler);
> + applyRestriction(*f, MustPreserveList, DSOList, AsmUsed, Mangler);
> for (Module::global_iterator v = mergedModule->global_begin(),
> e = mergedModule->global_end(); v != e; ++v)
> - applyRestriction(*v, MustPreserveList, AsmUsed, Mangler);
> + applyRestriction(*v, MustPreserveList, DSOList, AsmUsed, Mangler);
> for (Module::alias_iterator a = mergedModule->alias_begin(),
> e = mergedModule->alias_end(); a != e; ++a)
> - applyRestriction(*a, MustPreserveList, AsmUsed, Mangler);
> + applyRestriction(*a, MustPreserveList, DSOList, AsmUsed, Mangler);
>
> GlobalVariable *LLVMCompilerUsed =
> mergedModule->getGlobalVariable("llvm.compiler.used");
> @@ -386,7 +390,7 @@ void LTOCodeGenerator::applyScopeRestric
> LLVMCompilerUsed->setSection("llvm.metadata");
> }
>
> - passes.add(createInternalizePass(MustPreserveList));
> + passes.add(createInternalizePass(MustPreserveList, DSOList));
>
> // apply scope restrictions
> passes.run(*mergedModule);
>
> Modified: llvm/trunk/lib/Transforms/IPO/IPO.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/IPO.cpp?rev=191922&r1=191921&r2=191922&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Transforms/IPO/IPO.cpp (original)
> +++ llvm/trunk/lib/Transforms/IPO/IPO.cpp Thu Oct 3 13:29:09 2013
> @@ -98,7 +98,7 @@ void LLVMAddInternalizePass(LLVMPassMana
> std::vector<const char *> Export;
> if (AllButMain)
> Export.push_back("main");
> - unwrap(PM)->add(createInternalizePass(Export));
> + unwrap(PM)->add(createInternalizePass(Export, None));
> }
>
> void LLVMAddStripDeadPrototypesPass(LLVMPassManagerRef PM) {
>
> Modified: llvm/trunk/lib/Transforms/IPO/Internalize.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Internalize.cpp?rev=191922&r1=191921&r2=191922&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Transforms/IPO/Internalize.cpp (original)
> +++ llvm/trunk/lib/Transforms/IPO/Internalize.cpp Thu Oct 3 13:29:09 2013
> @@ -44,13 +44,20 @@ APIList("internalize-public-api-list", c
> cl::desc("A list of symbol names to preserve"),
> cl::CommaSeparated);
>
> +static cl::list<std::string>
> +DSOList("internalize-dso-list", cl::value_desc("list"),
> + cl::desc("A list of symbol names need for a dso symbol table"),
> + cl::CommaSeparated);
> +
> namespace {
> class InternalizePass : public ModulePass {
> std::set<std::string> ExternalNames;
> + std::set<std::string> DSONames;
> public:
> static char ID; // Pass identification, replacement for typeid
> explicit InternalizePass();
> - explicit InternalizePass(ArrayRef<const char *> ExportList);
> + explicit InternalizePass(ArrayRef<const char *> ExportList,
> + ArrayRef<const char *> DSOList);
> void LoadFile(const char *Filename);
> virtual bool runOnModule(Module &M);
>
> @@ -71,15 +78,21 @@ InternalizePass::InternalizePass()
> if (!APIFile.empty()) // If a filename is specified, use it.
> LoadFile(APIFile.c_str());
> ExternalNames.insert(APIList.begin(), APIList.end());
> + DSONames.insert(DSOList.begin(), DSOList.end());
> }
>
> -InternalizePass::InternalizePass(ArrayRef<const char *> ExportList)
> +InternalizePass::InternalizePass(ArrayRef<const char *> ExportList,
> + ArrayRef<const char *> DSOList)
> : ModulePass(ID){
> initializeInternalizePassPass(*PassRegistry::getPassRegistry());
> for(ArrayRef<const char *>::const_iterator itr = ExportList.begin();
> itr != ExportList.end(); itr++) {
> ExternalNames.insert(*itr);
> }
> + for(ArrayRef<const char *>::const_iterator itr = DSOList.begin();
> + itr != DSOList.end(); itr++) {
> + DSONames.insert(*itr);
> + }
> }
>
> void InternalizePass::LoadFile(const char *Filename) {
> @@ -99,7 +112,8 @@ void InternalizePass::LoadFile(const cha
> }
>
> static bool shouldInternalize(const GlobalValue &GV,
> - const std::set<std::string> &ExternalNames)
> {
> + const std::set<std::string> &ExternalNames,
> + const std::set<std::string> &DSONames) {
> // Function must be defined here
> if (GV.isDeclaration())
> return false;
> @@ -116,7 +130,20 @@ static bool shouldInternalize(const Glob
> if (ExternalNames.count(GV.getName()))
> return false;
>
> - return true;
> + // Not needed for the symbol table?
> + if (!DSONames.count(GV.getName()))
> + return true;
> +
> + // Not a linkonce. Someone can depend on it being on the symbol table.
> + if (!GV.hasLinkOnceLinkage())
> + return false;
> +
> + // The address is not important, we can hide it.
> + if (GV.hasUnnamedAddr())
> + return true;
> +
> + // FIXME: Check if the address is used.
> + return false;
> }
>
> bool InternalizePass::runOnModule(Module &M) {
> @@ -145,7 +172,7 @@ bool InternalizePass::runOnModule(Module
> // Mark all functions not in the api as internal.
> // FIXME: maybe use private linkage?
> for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
> - if (!shouldInternalize(*I, ExternalNames))
> + if (!shouldInternalize(*I, ExternalNames, DSONames))
> continue;
>
> I->setLinkage(GlobalValue::InternalLinkage);
> @@ -182,7 +209,7 @@ bool InternalizePass::runOnModule(Module
> // FIXME: maybe use private linkage?
> for (Module::global_iterator I = M.global_begin(), E = M.global_end();
> I != E; ++I) {
> - if (!shouldInternalize(*I, ExternalNames))
> + if (!shouldInternalize(*I, ExternalNames, DSONames))
> continue;
>
> I->setLinkage(GlobalValue::InternalLinkage);
> @@ -194,7 +221,7 @@ bool InternalizePass::runOnModule(Module
> // Mark all aliases that are not in the api as internal as well.
> for (Module::alias_iterator I = M.alias_begin(), E = M.alias_end();
> I != E; ++I) {
> - if (!shouldInternalize(*I, ExternalNames))
> + if (!shouldInternalize(*I, ExternalNames, DSONames))
> continue;
>
> I->setLinkage(GlobalValue::InternalLinkage);
> @@ -210,6 +237,7 @@ ModulePass *llvm::createInternalizePass(
> return new InternalizePass();
> }
>
> -ModulePass *llvm::createInternalizePass(ArrayRef<const char *>
> ExportList) {
> - return new InternalizePass(ExportList);
> +ModulePass *llvm::createInternalizePass(ArrayRef<const char *> ExportList,
> + ArrayRef<const char *> DSOList) {
> + return new InternalizePass(ExportList, DSOList);
> }
>
> Modified: llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp?rev=191922&r1=191921&r2=191922&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp (original)
> +++ llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp Thu Oct 3
> 13:29:09 2013
> @@ -277,7 +277,7 @@ void PassManagerBuilder::populateLTOPass
> // for a main function. If main is defined, mark all other functions
> // internal.
> if (Internalize)
> - PM.add(createInternalizePass("main"));
> + PM.add(createInternalizePass("main", None));
>
> // Propagate constants at call sites into the functions they call. This
> // opens opportunities for globalopt (and inlining) by substituting
> function
>
> Modified: llvm/trunk/test/LTO/cfi_endproc.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/cfi_endproc.ll?rev=191922&r1=191921&r2=191922&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/LTO/cfi_endproc.ll (original)
> +++ llvm/trunk/test/LTO/cfi_endproc.ll Thu Oct 3 13:29:09 2013
> @@ -27,3 +27,11 @@ define i32 @main(i32 %argc, i8** %argv)
> call void @PR14512()
> ret i32 0
> }
> +
> +; RUN: llvm-lto -o %t -dso-symbol=zed1 -dso-symbol=zed2 %t1 -disable-opt
> +; RUN: llvm-nm %t | FileCheck %s -check-prefix=ZED1_AND_ZED2
> +; ZED1_AND_ZED2: V zed1
> + at zed1 = linkonce_odr global i32 42
> +
> +; ZED1_AND_ZED2: d zed2
> + at zed2 = linkonce_odr unnamed_addr global i32 42
>
> Modified: llvm/trunk/test/Transforms/Internalize/lists.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Internalize/lists.ll?rev=191922&r1=191921&r2=191922&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Transforms/Internalize/lists.ll (original)
> +++ llvm/trunk/test/Transforms/Internalize/lists.ll Thu Oct 3 13:29:09
> 2013
> @@ -13,6 +13,10 @@
> ; -file and -list options should be merged, the apifile contains foo and j
> ; RUN: opt < %s -internalize -internalize-public-api-list bar
> -internalize-public-api-file %S/apifile -S | FileCheck
> --check-prefix=FOO_J_AND_BAR %s
>
> +; Put zed1 and zed2 in the symbol table. If the address is not relevant,
> we
> +; internalize them.
> +; RUN: opt < %s -internalize -internalize-dso-list zed1,zed2 -S |
> FileCheck --check-prefix=ZED1_AND_ZED2 %s
> +
> ; ALL: @i = internal global
> ; FOO_AND_J: @i = internal global
> ; FOO_AND_BAR: @i = internal global
> @@ -25,6 +29,12 @@
> ; FOO_J_AND_BAR: @j = global
> @j = global i32 0
>
> +; ZED1_AND_ZED2: @zed1 = linkonce_odr global i32 42
> + at zed1 = linkonce_odr global i32 42
> +
> +; ZED1_AND_ZED2: @zed2 = internal unnamed_addr global i32 42
> + at zed2 = linkonce_odr unnamed_addr global i32 42
> +
> ; ALL: define internal void @main() {
> ; FOO_AND_J: define internal void @main() {
> ; FOO_AND_BAR: define internal void @main() {
>
> Modified: llvm/trunk/tools/gold/gold-plugin.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/gold/gold-plugin.cpp?rev=191922&r1=191921&r2=191922&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/gold/gold-plugin.cpp (original)
> +++ llvm/trunk/tools/gold/gold-plugin.cpp Thu Oct 3 13:29:09 2013
> @@ -197,7 +197,7 @@ ld_plugin_status onload(ld_plugin_tv *tv
> case LDPT_ADD_SYMBOLS:
> add_symbols = tv->tv_u.tv_add_symbols;
> break;
> - case LDPT_GET_SYMBOLS:
> + case LDPT_GET_SYMBOLS_V2:
> get_symbols = tv->tv_u.tv_get_symbols;
> break;
> case LDPT_ADD_INPUT_FILE:
> @@ -386,6 +386,11 @@ static ld_plugin_status all_symbols_read
>
> if (options::generate_api_file)
> api_file << I->syms[i].name << "\n";
> + } else if (I->syms[i].resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
> {
>
third_party/llvm/llvm/tools/gold/gold-plugin.cpp:200:12: error: use of
undeclared identifier 'LDPT_GET_SYMBOLS_V2'; did you mean
'LDPT_GET_SYMBOLS'?
third_party/llvm/llvm/tools/gold/gold-plugin.cpp:389:43: error: use of
undeclared identifier 'LDPR_PREVAILING_DEF_IRONLY_EXP'; did you mean
'LDPR_PREVAILING_DEF_IRONLY'?
I think you've increased the minimum required version of something. Can you
make this change conditional on these names existing?
> + lto_codegen_add_dso_symbol(code_gen, I->syms[i].name);
> +
> + if (options::generate_api_file)
> + api_file << I->syms[i].name << " dso only\n";
> }
> }
> }
>
> Modified: llvm/trunk/tools/llvm-lto/llvm-lto.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-lto/llvm-lto.cpp?rev=191922&r1=191921&r2=191922&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-lto/llvm-lto.cpp (original)
> +++ llvm/trunk/tools/llvm-lto/llvm-lto.cpp Thu Oct 3 13:29:09 2013
> @@ -50,6 +50,10 @@ ExportedSymbols("exported-symbol",
> cl::desc("Symbol to export from the resulting object file"),
> cl::ZeroOrMore);
>
> +static cl::list<std::string>
> +DSOSymbols("dso-symbol",
> + cl::desc("Symbol to put in the symtab in the resulting dso"),
> + cl::ZeroOrMore);
>
> int main(int argc, char **argv) {
> // Print a stack trace if we signal out.
> @@ -117,6 +121,10 @@ int main(int argc, char **argv) {
> for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
> CodeGen.addMustPreserveSymbol(ExportedSymbols[i].c_str());
>
> + // Add all the dso symbols to the table of symbols to expose.
> + for (unsigned i = 0; i < DSOSymbols.size(); ++i)
> + CodeGen.addDSOSymbol(DSOSymbols[i].c_str());
> +
> if (!OutputFilename.empty()) {
> size_t len = 0;
> std::string ErrorInfo;
>
> Modified: llvm/trunk/tools/lto/lto.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lto/lto.cpp?rev=191922&r1=191921&r2=191922&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/lto/lto.cpp (original)
> +++ llvm/trunk/tools/lto/lto.cpp Thu Oct 3 13:29:09 2013
> @@ -260,6 +260,10 @@ void lto_codegen_add_must_preserve_symbo
> cg->addMustPreserveSymbol(symbol);
> }
>
> +void lto_codegen_add_dso_symbol(lto_code_gen_t cg, const char *symbol) {
> + cg->addDSOSymbol(symbol);
> +}
> +
> /// lto_codegen_write_merged_modules - Writes a new file at the specified
> path
> /// that contains the merged contents of all modules added so far.
> Returns true
> /// on error (check lto_get_error_message() for details).
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20131003/c9186d29/attachment.html>
More information about the llvm-commits
mailing list