opt: Add -std-link-opts argument, matches llvm-ld's optimizations.
[oota-llvm.git] / tools / gold / gold-plugin.cpp
index 65092a682a446ce205882b09e4563dfdbdfbf0c3..9554b8adc314b55c4df3ae050c0853a793a0caab 100644 (file)
 #include "llvm-c/lto.h"
 
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Errno.h"
 #include "llvm/System/Path.h"
+#include "llvm/System/Program.h"
 
+#include <cerrno>
 #include <cstdlib>
 #include <cstring>
+#include <fstream>
 #include <list>
 #include <vector>
-#include <cerrno>
 
 using namespace llvm;
 
@@ -42,10 +45,12 @@ namespace {
   int api_version = 0;
   int gold_version = 0;
 
+  bool generate_api_file = false;
+  const char *as_path = NULL;
+
   struct claimed_file {
     lto_module_t M;
     void *handle;
-    void *buf;
     std::vector<ld_plugin_symbol> syms;
   };
 
@@ -97,7 +102,18 @@ ld_plugin_status onload(ld_plugin_tv *tv) {
         //output_type = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
         break;
       case LDPT_OPTION:
-        (*message)(LDPL_WARNING, "Ignoring flag %s", tv->tv_u.tv_string);
+        if (strcmp("generate-api-file", tv->tv_u.tv_string) == 0) {
+          generate_api_file = true;
+        } else if (strncmp("as=", tv->tv_u.tv_string, 3) == 0) {
+          if (as_path) {
+            (*message)(LDPL_WARNING, "Path to as specified twice. "
+                       "Discarding %s", tv->tv_u.tv_string);
+          } else {
+            as_path = strdup(tv->tv_u.tv_string + 3);
+          }
+        } else {
+          (*message)(LDPL_WARNING, "Ignoring flag %s", tv->tv_u.tv_string);
+        }
         break;
       case LDPT_REGISTER_CLAIM_FILE_HOOK: {
         ld_plugin_register_claim_file callback;
@@ -143,9 +159,12 @@ ld_plugin_status onload(ld_plugin_tv *tv) {
     }
   }
 
-  if (!registeredClaimFile || !registeredAllSymbolsRead || !registeredCleanup ||
-      !add_symbols || !get_symbols || !add_input_file) {
-    (*message)(LDPL_ERROR, "Not all hooks registered for LLVMgold.");
+  if (!registeredClaimFile) {
+    (*message)(LDPL_ERROR, "register_claim_file not passed to LLVMgold.");
+    return LDPS_ERR;
+  }
+  if (!add_symbols) {
+    (*message)(LDPL_ERROR, "add_symbols not passed to LLVMgold.");
     return LDPS_ERR;
   }
 
@@ -158,30 +177,29 @@ ld_plugin_status onload(ld_plugin_tv *tv) {
 ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
                                  int *claimed) {
   void *buf = NULL;
-  // If set, this means gold found IR in an ELF section. LLVM doesn't wrap its
-  // IR in ELF, so we know it's not us. But it can also be an .a file containing
-  // LLVM IR.
   if (file->offset) {
+    // Gold has found what might be IR part-way inside of a file, such as
+    // an .a archive.
     if (lseek(file->fd, file->offset, SEEK_SET) == -1) {
-      (*message)(LDPL_ERROR, 
+      (*message)(LDPL_ERROR,
                  "Failed to seek to archive member of %s at offset %d: %s\n", 
                  file->name,
-                 file->offset, strerror(errno));
+                 file->offset, sys::StrError(errno).c_str());
       return LDPS_ERR;
     }
     buf = malloc(file->filesize);
     if (!buf) {
-      (*message)(LDPL_ERROR, 
+      (*message)(LDPL_ERROR,
                  "Failed to allocate buffer for archive member of size: %d\n", 
                  file->filesize);
       return LDPS_ERR;
     }
     if (read(file->fd, buf, file->filesize) != file->filesize) {
-      (*message)(LDPL_ERROR, 
-                 "Failed to read archive member of %s at offset %d: %s\n", 
+      (*message)(LDPL_ERROR,
+                 "Failed to read archive member of %s at offset %d: %s\n",
                  file->name,
-                 file->offset,           
-                 strerror(errno));
+                 file->offset,
+                 sys::StrError(errno).c_str());
       free(buf);
       return LDPS_ERR;
     }
@@ -196,9 +214,9 @@ ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
   Modules.resize(Modules.size() + 1);
   claimed_file &cf = Modules.back();
 
-  cf.M = buf ?  lto_module_create_from_memory(buf, file->filesize) :
-                lto_module_create(file->name);
-  cf.buf = buf;
+  cf.M = buf ? lto_module_create_from_memory(buf, file->filesize) :
+               lto_module_create(file->name);
+  free(buf);
   if (!cf.M) {
     (*message)(LDPL_ERROR, "Failed to create LLVM module: %s",
                lto_get_error_message());
@@ -232,7 +250,6 @@ ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
         break;
       default:
         (*message)(LDPL_ERROR, "Unknown scope attribute: %d", scope);
-        free(buf);
         return LDPS_ERR;
     }
 
@@ -250,9 +267,11 @@ ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
       case LTO_SYMBOL_DEFINITION_WEAK:
         sym.def = LDPK_WEAKDEF;
         break;
+      case LTO_SYMBOL_DEFINITION_WEAKUNDEF:
+        sym.def = LDPK_WEAKUNDEF;
+        break;
       default:
         (*message)(LDPL_ERROR, "Unknown definition attribute: %d", definition);
-        free(buf);
         return LDPS_ERR;
     }
 
@@ -268,7 +287,6 @@ ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
   if (!cf.syms.empty()) {
     if ((*add_symbols)(cf.handle, cf.syms.size(), &cf.syms[0]) != LDPS_OK) {
       (*message)(LDPL_ERROR, "Unable to add symbols!");
-      free(buf);
       return LDPS_ERR;
     }
   }
@@ -287,6 +305,15 @@ ld_plugin_status all_symbols_read_hook(void) {
        E = Modules.end(); I != E; ++I)
     lto_codegen_add_module(cg, I->M);
 
+  std::ofstream api_file;
+  if (generate_api_file) {
+    api_file.open("apifile.txt", std::ofstream::out | std::ofstream::trunc);
+    if (!api_file.is_open()) {
+      (*message)(LDPL_FATAL, "Unable to open apifile.txt for writing.");
+      abort();
+    }
+  }
+
   // If we don't preserve any symbols, libLTO will assume that all symbols are
   // needed. Keep all symbols unless we're producing a final executable.
   if (output_type == LTO_CODEGEN_PIC_MODEL_STATIC) {
@@ -295,15 +322,21 @@ ld_plugin_status all_symbols_read_hook(void) {
          E = Modules.end(); I != E; ++I) {
       (*get_symbols)(I->handle, I->syms.size(), &I->syms[0]);
       for (unsigned i = 0, e = I->syms.size(); i != e; i++) {
-        (*message)(LDPL_WARNING, "def: %d visibility: %d resolution %d",
-                   I->syms[i].def, I->syms[i].visibility, I->syms[i].resolution);
-        if (I->syms[i].resolution == LDPR_PREVAILING_DEF) {
+        if (I->syms[i].resolution == LDPR_PREVAILING_DEF ||
+            (I->syms[i].def == LDPK_COMMON &&
+             I->syms[i].resolution == LDPR_RESOLVED_IR)) {
           lto_codegen_add_must_preserve_symbol(cg, I->syms[i].name);
           anySymbolsPreserved = true;
+
+          if (generate_api_file)
+            api_file << I->syms[i].name << "\n";
         }
       }
     }
 
+    if (generate_api_file)
+      api_file.close();
+
     if (!anySymbolsPreserved) {
       // This entire file is unnecessary!
       lto_codegen_dispose(cg);
@@ -313,6 +346,10 @@ ld_plugin_status all_symbols_read_hook(void) {
 
   lto_codegen_set_pic_model(cg, output_type);
   lto_codegen_set_debug_model(cg, LTO_DEBUG_MODEL_DWARF);
+  if (as_path) {
+    sys::Path p = sys::Program::FindProgramByName(as_path);
+    lto_codegen_set_assembler_path(cg, p.c_str());
+  }
 
   size_t bufsize = 0;
   const char *buffer = static_cast<const char *>(lto_codegen_compile(cg,
@@ -325,7 +362,9 @@ ld_plugin_status all_symbols_read_hook(void) {
     (*message)(LDPL_ERROR, "%s", ErrMsg.c_str());
     return LDPS_ERR;
   }
-  raw_fd_ostream *objFile = new raw_fd_ostream(uniqueObjPath.c_str(), true,
+  raw_fd_ostream *objFile = new raw_fd_ostream(uniqueObjPath.c_str(),
+                                               /*Binary=*/true,
+                                               /*Force=*/true,
                                                ErrMsg);
   if (!ErrMsg.empty()) {
     delete objFile;
@@ -337,10 +376,6 @@ ld_plugin_status all_symbols_read_hook(void) {
   objFile->close();
 
   lto_codegen_dispose(cg);
-  for (std::list<claimed_file>::iterator I = Modules.begin(),
-       E = Modules.end(); I != E; ++I) {
-    free(I->buf);
-  }
 
   if ((*add_input_file)(const_cast<char*>(uniqueObjPath.c_str())) != LDPS_OK) {
     (*message)(LDPL_ERROR, "Unable to add .o file to the link.");