[WebAssembly] Add DataCount section to object files

Summary:
This ensures that object files will continue to validate as
WebAssembly modules in the presence of bulk memory operations. Engines
that don't support bulk memory operations will not recognize the
DataCount section and will report validation errors, but that's ok
because object files aren't supposed to be run directly anyway.

Reviewers: aheejin, dschuff, sbc100

Subscribers: jgravelle-google, hiraditya, sunfish, rupprecht, llvm-commits

Tags: #llvm

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

llvm-svn: 358315
diff --git a/llvm/tools/llvm-readobj/WasmDumper.cpp b/llvm/tools/llvm-readobj/WasmDumper.cpp
index edcd073..e232d112 100644
--- a/llvm/tools/llvm-readobj/WasmDumper.cpp
+++ b/llvm/tools/llvm-readobj/WasmDumper.cpp
@@ -32,11 +32,11 @@
 static const EnumEntry<uint32_t> WasmSectionTypes[] = {
 #define ENUM_ENTRY(X)                                                          \
   { #X, wasm::WASM_SEC_##X }
-    ENUM_ENTRY(CUSTOM),   ENUM_ENTRY(TYPE),  ENUM_ENTRY(IMPORT),
-    ENUM_ENTRY(FUNCTION), ENUM_ENTRY(TABLE), ENUM_ENTRY(MEMORY),
-    ENUM_ENTRY(GLOBAL),   ENUM_ENTRY(EVENT), ENUM_ENTRY(EXPORT),
-    ENUM_ENTRY(START),    ENUM_ENTRY(ELEM),  ENUM_ENTRY(CODE),
-    ENUM_ENTRY(DATA),
+    ENUM_ENTRY(CUSTOM),   ENUM_ENTRY(TYPE),      ENUM_ENTRY(IMPORT),
+    ENUM_ENTRY(FUNCTION), ENUM_ENTRY(TABLE),     ENUM_ENTRY(MEMORY),
+    ENUM_ENTRY(GLOBAL),   ENUM_ENTRY(EVENT),     ENUM_ENTRY(EXPORT),
+    ENUM_ENTRY(START),    ENUM_ENTRY(ELEM),      ENUM_ENTRY(CODE),
+    ENUM_ENTRY(DATA),     ENUM_ENTRY(DATACOUNT),
 #undef ENUM_ENTRY
 };
 
diff --git a/llvm/tools/obj2yaml/wasm2yaml.cpp b/llvm/tools/obj2yaml/wasm2yaml.cpp
index eacbe62..47d984b 100644
--- a/llvm/tools/obj2yaml/wasm2yaml.cpp
+++ b/llvm/tools/obj2yaml/wasm2yaml.cpp
@@ -353,6 +353,12 @@
       S = std::move(DataSec);
       break;
     }
+    case wasm::WASM_SEC_DATACOUNT: {
+      auto DataCountSec = make_unique<WasmYAML::DataCountSection>();
+      DataCountSec->Count = Obj.dataSegments().size();
+      S = std::move(DataCountSec);
+      break;
+    }
     default:
       llvm_unreachable("Unknown section type");
       break;
diff --git a/llvm/tools/yaml2obj/yaml2wasm.cpp b/llvm/tools/yaml2obj/yaml2wasm.cpp
index 322ac01..cd07a30 100644
--- a/llvm/tools/yaml2obj/yaml2wasm.cpp
+++ b/llvm/tools/yaml2obj/yaml2wasm.cpp
@@ -43,6 +43,7 @@
   int writeSectionContent(raw_ostream &OS, WasmYAML::ElemSection &Section);
   int writeSectionContent(raw_ostream &OS, WasmYAML::CodeSection &Section);
   int writeSectionContent(raw_ostream &OS, WasmYAML::DataSection &Section);
+  int writeSectionContent(raw_ostream &OS, WasmYAML::DataCountSection &Section);
 
   // Custom section types
   int writeSectionContent(raw_ostream &OS, WasmYAML::DylinkSection &Section);
@@ -514,6 +515,12 @@
   return 0;
 }
 
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+                                    WasmYAML::DataCountSection &Section) {
+  encodeULEB128(Section.Count, OS);
+  return 0;
+}
+
 int WasmWriter::writeRelocSection(raw_ostream &OS, WasmYAML::Section &Sec,
                                   uint32_t SectionIndex) {
   switch (Sec.Type) {
@@ -614,6 +621,9 @@
     } else if (auto S = dyn_cast<WasmYAML::DataSection>(Sec.get())) {
       if (auto Err = writeSectionContent(StringStream, *S))
         return Err;
+    } else if (auto S = dyn_cast<WasmYAML::DataCountSection>(Sec.get())) {
+      if (auto Err = writeSectionContent(StringStream, *S))
+        return Err;
     } else {
       errs() << "Unknown section type: " << Sec->Type << "\n";
       return 1;