[WebAssembly] Merge producers section

Reviewers: sbc100, aheejin, dschuff

Subscribers: jgravelle-google, sunfish, llvm-commits

Differential Revision: https://reviews.llvm.org/D56807

llvm-svn: 351400
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 819d429..ea65bc3 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -21,6 +21,8 @@
 #include "lld/Common/Strings.h"
 #include "lld/Common/Threads.h"
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/BinaryFormat/Wasm.h"
 #include "llvm/Object/WasmTraits.h"
@@ -95,6 +97,7 @@
   void createRelocSections();
   void createLinkingSection();
   void createNameSection();
+  void createProducersSection();
 
   void writeHeader();
   void writeSections();
@@ -327,7 +330,8 @@
       StringRef Name = Section->getName();
       // These custom sections are known the linker and synthesized rather than
       // blindly copied
-      if (Name == "linking" || Name == "name" || Name.startswith("reloc."))
+      if (Name == "linking" || Name == "name" || Name == "producers" ||
+          Name.startswith("reloc."))
         continue;
       // .. or it is a debug section
       if (StripDebug && Name.startswith(".debug_"))
@@ -633,6 +637,43 @@
   Sub.writeTo(Section->getStream());
 }
 
+void Writer::createProducersSection() {
+  SmallVector<std::pair<std::string, std::string>, 8> Languages;
+  SmallVector<std::pair<std::string, std::string>, 8> Tools;
+  SmallVector<std::pair<std::string, std::string>, 8> SDKs;
+  for (ObjFile *File : Symtab->ObjectFiles) {
+    const WasmProducerInfo &Info = File->getWasmObj()->getProducerInfo();
+    for (auto &Producers : {std::make_pair(&Info.Languages, &Languages),
+                            std::make_pair(&Info.Tools, &Tools),
+                            std::make_pair(&Info.SDKs, &SDKs)}) {
+      llvm::SmallSet<StringRef, 8> SeenProducers;
+      for (auto &Producer : *Producers.first)
+        if (SeenProducers.insert(Producer.first).second)
+          Producers.second->push_back(Producer);
+    }
+  }
+  int FieldCount =
+      int(!Languages.empty()) + int(!Tools.empty()) + int(!SDKs.empty());
+  if (FieldCount == 0)
+    return;
+  SyntheticSection *Section =
+      createSyntheticSection(WASM_SEC_CUSTOM, "producers");
+  auto &OS = Section->getStream();
+  writeUleb128(OS, FieldCount, "field count");
+  for (auto &Field : {std::make_pair(StringRef("language"), Languages),
+                      std::make_pair(StringRef("processed-by"), Tools),
+                      std::make_pair(StringRef("sdk"), SDKs)}) {
+    if (Field.second.empty())
+      continue;
+    writeStr(OS, Field.first, "field name");
+    writeUleb128(OS, Field.second.size(), "number of entries");
+    for (auto &Entry : Field.second) {
+      writeStr(OS, Entry.first, "producer name");
+      writeStr(OS, Entry.second, "producer version");
+    }
+  }
+}
+
 void Writer::writeHeader() {
   memcpy(Buffer->getBufferStart(), Header.data(), Header.size());
 }
@@ -772,9 +813,13 @@
     createLinkingSection();
     createRelocSections();
   }
+
   if (!Config->StripDebug && !Config->StripAll)
     createNameSection();
 
+  if (!Config->StripAll)
+    createProducersSection();
+
   for (OutputSection *S : OutputSections) {
     S->setOffset(FileSize);
     S->finalizeContents();