[lld] r322415 - [WebAssembly] Add COMDAT support

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 12 14:25:17 PST 2018


Author: sbc
Date: Fri Jan 12 14:25:17 2018
New Revision: 322415

URL: http://llvm.org/viewvc/llvm-project?rev=322415&view=rev
Log:
[WebAssembly] Add COMDAT support

See https://bugs.llvm.org/show_bug.cgi?id=35533, and D40844

Things covered:
* Removing duplicate data segments (as determined by COMDATs emitted
  by the frontend)
* Removing duplicate globals and functions in COMDATs
* Checking that each time a COMDAT is seen it has the same symbols
  as at other times (ie it's a stronger check than simply giving all
  the symbols in the COMDAT weak linkage)

Patch by Nicholas Wilson!

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

Added:
    lld/trunk/test/wasm/Inputs/comdat1.ll
    lld/trunk/test/wasm/Inputs/comdat2.ll
    lld/trunk/test/wasm/comdats.ll
Modified:
    lld/trunk/test/wasm/relocatable.ll
    lld/trunk/wasm/InputChunks.h
    lld/trunk/wasm/InputFiles.cpp
    lld/trunk/wasm/InputFiles.h
    lld/trunk/wasm/SymbolTable.cpp
    lld/trunk/wasm/SymbolTable.h
    lld/trunk/wasm/Writer.cpp

Added: lld/trunk/test/wasm/Inputs/comdat1.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/Inputs/comdat1.ll?rev=322415&view=auto
==============================================================================
--- lld/trunk/test/wasm/Inputs/comdat1.ll (added)
+++ lld/trunk/test/wasm/Inputs/comdat1.ll Fri Jan 12 14:25:17 2018
@@ -0,0 +1,11 @@
+$inlineFn = comdat any
+ at constantData = weak_odr constant [3 x i8] c"abc", comdat($inlineFn)
+define linkonce_odr i32 @inlineFn() comdat {
+entry:
+  ret i32 ptrtoint ([3 x i8]* @constantData to i32)
+}
+
+define i32 @callInline1() {
+entry:
+    ret i32 ptrtoint (i32 ()* @inlineFn to i32)
+}

Added: lld/trunk/test/wasm/Inputs/comdat2.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/Inputs/comdat2.ll?rev=322415&view=auto
==============================================================================
--- lld/trunk/test/wasm/Inputs/comdat2.ll (added)
+++ lld/trunk/test/wasm/Inputs/comdat2.ll Fri Jan 12 14:25:17 2018
@@ -0,0 +1,11 @@
+$inlineFn = comdat any
+ at constantData = weak_odr constant [3 x i8] c"abc", comdat($inlineFn)
+define linkonce_odr i32 @inlineFn() comdat {
+entry:
+  ret i32 ptrtoint ([3 x i8]* @constantData to i32)
+}
+
+define i32 @callInline2() {
+entry:
+    ret i32 ptrtoint (i32 ()* @inlineFn to i32)
+}

Added: lld/trunk/test/wasm/comdats.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/comdats.ll?rev=322415&view=auto
==============================================================================
--- lld/trunk/test/wasm/comdats.ll (added)
+++ lld/trunk/test/wasm/comdats.ll Fri Jan 12 14:25:17 2018
@@ -0,0 +1,70 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/comdat1.ll -o %t1.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/comdat2.ll -o %t2.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o
+; RUN: lld -flavor wasm -o %t.wasm %t.o %t1.o %t2.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+declare i32 @inlineFn()
+
+define void @_start() local_unnamed_addr {
+entry:
+  %call = call i32 @inlineFn()
+  ret void
+}
+
+; CHECK:       - Type:            GLOBAL
+; CHECK-NEXT:    Globals:
+; CHECK-NEXT:      - Index:           0
+; CHECK-NEXT:        Type:            I32
+; CHECK-NEXT:        Mutable:         true
+; CHECK-NEXT:        InitExpr:
+; CHECK-NEXT:          Opcode:          I32_CONST
+; CHECK-NEXT:          Value:           66576
+; CHECK-NEXT:  - Type:            EXPORT
+; CHECK-NEXT:    Exports:
+; CHECK-NEXT:      - Name:            memory
+; CHECK-NEXT:        Kind:            MEMORY
+; CHECK-NEXT:        Index:           0
+; CHECK-NEXT:      - Name:            _start
+; CHECK-NEXT:        Kind:            FUNCTION
+; CHECK-NEXT:        Index:           0
+; CHECK-NEXT:      - Name:            inlineFn
+; CHECK-NEXT:        Kind:            FUNCTION
+; CHECK-NEXT:        Index:           1
+; CHECK-NEXT:      - Name:            callInline1
+; CHECK-NEXT:        Kind:            FUNCTION
+; CHECK-NEXT:        Index:           2
+; CHECK-NEXT:      - Name:            callInline2
+; CHECK-NEXT:        Kind:            FUNCTION
+; CHECK-NEXT:        Index:           3
+; CHECK-NEXT:  - Type:            ELEM
+; CHECK-NEXT:    Segments:
+; CHECK-NEXT:      - Offset:
+; CHECK-NEXT:          Opcode:          I32_CONST
+; CHECK-NEXT:          Value:           1
+; CHECK-NEXT:        Functions:       [ 1 ]
+; CHECK-NEXT:  - Type:            CODE
+; CHECK-NEXT:    Functions:
+; CHECK-NEXT:      - Index:           0
+; CHECK-NEXT:        Locals:
+; CHECK-NEXT:        Body:            1081808080001A0B
+; CHECK-NEXT:      - Index:           1
+; CHECK-NEXT:        Locals:
+; CHECK-NEXT:        Body:            4180888080000B
+; CHECK-NEXT:      - Index:           2
+; CHECK-NEXT:        Locals:
+; CHECK-NEXT:        Body:            4181808080000B
+; CHECK-NEXT:      - Index:           3
+; CHECK-NEXT:        Locals:
+; CHECK-NEXT:        Body:            4181808080000B
+; CHECK-NEXT:      - Index:           4
+; CHECK-NEXT:        Locals:
+; CHECK-NEXT:        Body:            0B
+; CHECK-NEXT:  - Type:            DATA
+; CHECK-NEXT:    Segments:
+; CHECK-NEXT:      - SectionOffset:   7
+; CHECK-NEXT:        MemoryIndex:     0
+; CHECK-NEXT:        Offset:
+; CHECK-NEXT:          Opcode:          I32_CONST
+; CHECK-NEXT:          Value:           1024
+; CHECK-NEXT:        Content:         '616263'

Modified: lld/trunk/test/wasm/relocatable.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/relocatable.ll?rev=322415&r1=322414&r2=322415&view=diff
==============================================================================
--- lld/trunk/test/wasm/relocatable.ll (original)
+++ lld/trunk/test/wasm/relocatable.ll Fri Jan 12 14:25:17 2018
@@ -17,6 +17,13 @@ declare i32 @foo_import() local_unnamed_
 @func_addr2 = hidden global i32()* @foo_import, align 4
 @data_addr1 = hidden global i64* @data_import, align 8
 
+$func_comdat = comdat any
+ at data_comdat = weak_odr constant [3 x i8] c"abc", comdat($func_comdat)
+define linkonce_odr i32 @func_comdat() comdat {
+entry:
+  ret i32 ptrtoint ([3 x i8]* @data_comdat to i32)
+}
+
 ; CHECK:      --- !WASM
 ; CHECK-NEXT: FileHeader:
 ; CHECK-NEXT:   Version:         0x00000001
@@ -49,7 +56,7 @@ declare i32 @foo_import() local_unnamed_
 ; CHECK-NEXT:         GlobalType:      I32
 ; CHECK-NEXT:         GlobalMutable:   false
 ; CHECK-NEXT:   - Type:            FUNCTION
-; CHECK-NEXT:     FunctionTypes:   [ 0, 2 ]
+; CHECK-NEXT:     FunctionTypes:   [ 0, 2, 2 ]
 ; CHECK-NEXT:   - Type:            TABLE
 ; CHECK-NEXT:     Tables:
 ; CHECK-NEXT:       - ElemType:        ANYFUNC
@@ -73,18 +80,24 @@ declare i32 @foo_import() local_unnamed_
 ; CHECK-NEXT:         Mutable:         false
 ; CHECK-NEXT:         InitExpr:
 ; CHECK-NEXT:           Opcode:          I32_CONST
-; CHECK-NEXT:           Value:           8
+; CHECK-NEXT:           Value:           20
 ; CHECK-NEXT:       - Index:           3
 ; CHECK-NEXT:         Type:            I32
 ; CHECK-NEXT:         Mutable:         false
 ; CHECK-NEXT:         InitExpr:
 ; CHECK-NEXT:           Opcode:          I32_CONST
-; CHECK-NEXT:           Value:           12
+; CHECK-NEXT:           Value:           8
 ; CHECK-NEXT:       - Index:           4
 ; CHECK-NEXT:         Type:            I32
 ; CHECK-NEXT:         Mutable:         false
 ; CHECK-NEXT:         InitExpr:
 ; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           12
+; CHECK-NEXT:       - Index:           5
+; CHECK-NEXT:         Type:            I32
+; CHECK-NEXT:         Mutable:         false
+; CHECK-NEXT:         InitExpr:
+; CHECK-NEXT:           Opcode:          I32_CONST
 ; CHECK-NEXT:           Value:           16
 ; CHECK-NEXT:   - Type:            EXPORT
 ; CHECK-NEXT:     Exports:
@@ -94,18 +107,24 @@ declare i32 @foo_import() local_unnamed_
 ; CHECK-NEXT:       - Name:            my_func
 ; CHECK-NEXT:         Kind:            FUNCTION
 ; CHECK-NEXT:         Index:           3
+; CHECK-NEXT:       - Name:            func_comdat
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           4
 ; CHECK-NEXT:       - Name:            hello_str
 ; CHECK-NEXT:         Kind:            GLOBAL
 ; CHECK-NEXT:         Index:           1
-; CHECK-NEXT:       - Name:            func_addr1
+; CHECK-NEXT:       - Name:            data_comdat
 ; CHECK-NEXT:         Kind:            GLOBAL
 ; CHECK-NEXT:         Index:           2
-; CHECK-NEXT:       - Name:            func_addr2
+; CHECK-NEXT:       - Name:            func_addr1
 ; CHECK-NEXT:         Kind:            GLOBAL
 ; CHECK-NEXT:         Index:           3
-; CHECK-NEXT:       - Name:            data_addr1
+; CHECK-NEXT:       - Name:            func_addr2
 ; CHECK-NEXT:         Kind:            GLOBAL
 ; CHECK-NEXT:         Index:           4
+; CHECK-NEXT:       - Name:            data_addr1
+; CHECK-NEXT:         Kind:            GLOBAL
+; CHECK-NEXT:         Index:           5
 ; CHECK-NEXT:   - Type:            ELEM
 ; CHECK-NEXT:     Segments:
 ; CHECK-NEXT:       - Offset:
@@ -123,6 +142,9 @@ declare i32 @foo_import() local_unnamed_
 ; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_FUNCTION_INDEX_LEB
 ; CHECK-NEXT:         Index:           1
 ; CHECK-NEXT:         Offset:          0x00000013
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_SLEB
+; CHECK-NEXT:         Index:           2
+; CHECK-NEXT:         Offset:          0x0000001F
 ; CHECK-NEXT:     Functions:
 ; CHECK-NEXT:       - Index:         2
 ; CHECK-NEXT:         Locals:
@@ -130,6 +152,9 @@ declare i32 @foo_import() local_unnamed_
 ; CHECK-NEXT:       - Index:         3
 ; CHECK-NEXT:         Locals:
 ; CHECK-NEXT:         Body:          1081808080001A41010B
+; CHECK-NEXT:       - Index:           4
+; CHECK-NEXT:         Locals:
+; CHECK-NEXT:         Body:            4194808080000B
 ; CHECK-NEXT:   - Type:            DATA
 ; CHECK-NEXT:     Relocations:
 ; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_TABLE_INDEX_I32
@@ -166,26 +191,43 @@ declare i32 @foo_import() local_unnamed_
 ; CHECK-NEXT:           Opcode:          I32_CONST
 ; CHECK-NEXT:           Value:           16
 ; CHECK-NEXT:         Content:         '00000000'
+; CHECK-NEXT:       - SectionOffset:   45
+; CHECK-NEXT:         MemoryIndex:     0
+; CHECK-NEXT:         Offset:
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           20
+; CHECK-NEXT:         Content:         '616263'
 ; CHECK-NEXT:   - Type:            CUSTOM
 ; CHECK-NEXT:     Name:            linking
-; CHECK-NEXT:     DataSize:        20
+; CHECK-NEXT:     DataSize:        23
 ; CHECK-NEXT:     SegmentInfo:
 ; CHECK-NEXT:       - Index:           0
 ; CHECK-NEXT:         Name:            .rodata.hello_str
 ; CHECK-NEXT:         Alignment:       1
-; CHECK-NEXT:         Flags:           [ ]
+; CHECK-NEXT:         Flags:           [  ]
 ; CHECK-NEXT:       - Index:           1
 ; CHECK-NEXT:         Name:            .data.func_addr1
 ; CHECK-NEXT:         Alignment:       4
-; CHECK-NEXT:         Flags:           [ ]
+; CHECK-NEXT:         Flags:           [  ]
 ; CHECK-NEXT:       - Index:           2
 ; CHECK-NEXT:         Name:            .data.func_addr2
 ; CHECK-NEXT:         Alignment:       4
-; CHECK-NEXT:         Flags:           [ ]
+; CHECK-NEXT:         Flags:           [  ]
 ; CHECK-NEXT:       - Index:           3
 ; CHECK-NEXT:         Name:            .data.data_addr1
 ; CHECK-NEXT:         Alignment:       8
-; CHECK-NEXT:         Flags:           [ ]
+; CHECK-NEXT:         Flags:           [  ]
+; CHECK-NEXT:       - Index:           4
+; CHECK-NEXT:         Name:            .rodata.data_comdat
+; CHECK-NEXT:         Alignment:       1
+; CHECK-NEXT:         Flags:           [  ]
+; CHECK-NEXT:     Comdats:
+; CHECK-NEXT:       - Name:            func_comdat
+; CHECK-NEXT:         Entries:
+; CHECK-NEXT:           - Kind:            FUNCTION
+; CHECK-NEXT:             Index:           4
+; CHECK-NEXT:           - Kind:            DATA
+; CHECK-NEXT:             Index:           4
 ; CHECK-NEXT:   - Type:            CUSTOM
 ; CHECK-NEXT:     Name:            name
 ; CHECK-NEXT:     FunctionNames:

Modified: lld/trunk/wasm/InputChunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/InputChunks.h?rev=322415&r1=322414&r2=322415&view=diff
==============================================================================
--- lld/trunk/wasm/InputChunks.h (original)
+++ lld/trunk/wasm/InputChunks.h Fri Jan 12 14:25:17 2018
@@ -47,6 +47,9 @@ public:
 
   uint32_t getOutputOffset() const { return OutputOffset; }
 
+  virtual StringRef getComdat() const = 0;
+
+  bool Discarded = false;
   std::vector<OutputRelocation> OutRelocations;
 
 protected:
@@ -93,6 +96,7 @@ public:
   uint32_t startVA() const { return Segment.Data.Offset.Value.Int32; }
   uint32_t endVA() const { return startVA() + getSize(); }
   StringRef getName() const { return Segment.Data.Name; }
+  StringRef getComdat() const override { return Segment.Data.Comdat; }
 
   int32_t OutputSegmentOffset = 0;
 
@@ -100,6 +104,7 @@ protected:
   uint32_t getInputSectionOffset() const override {
     return Segment.SectionOffset;
   }
+
   const WasmSegment &Segment;
   const OutputSegment *OutputSeg = nullptr;
 };
@@ -116,7 +121,7 @@ public:
   const uint8_t *getData() const override {
     return File->CodeSection->Content.data() + getInputSectionOffset();
   }
-
+  StringRef getComdat() const override { return Function->Comdat; }
   uint32_t getOutputIndex() const { return OutputIndex.getValue(); };
   bool hasOutputIndex() const { return OutputIndex.hasValue(); };
   void setOutputIndex(uint32_t Index);

Modified: lld/trunk/wasm/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/InputFiles.cpp?rev=322415&r1=322414&r2=322415&view=diff
==============================================================================
--- lld/trunk/wasm/InputFiles.cpp (original)
+++ lld/trunk/wasm/InputFiles.cpp Fri Jan 12 14:25:17 2018
@@ -170,6 +170,11 @@ InputFunction *ObjFile::getFunction(cons
   return Functions[FunctionIndex];
 }
 
+bool ObjFile::isExcludedByComdat(InputChunk *Chunk) const {
+  StringRef Comdat = Chunk->getComdat();
+  return !Comdat.empty() && Symtab->findComdat(Comdat) != this;
+}
+
 void ObjFile::initializeSymbols() {
   Symbols.reserve(WasmObj->getNumberOfSymbols());
 
@@ -187,15 +192,23 @@ void ObjFile::initializeSymbols() {
   FunctionSymbols.resize(NumFunctionImports + WasmObj->functions().size());
   GlobalSymbols.resize(NumGlobalImports + WasmObj->globals().size());
 
+  ArrayRef<WasmFunction> Funcs = WasmObj->functions();
+  ArrayRef<uint32_t> FuncTypes = WasmObj->functionTypes();
+  ArrayRef<WasmSignature> Types = WasmObj->types();
+  ArrayRef<WasmGlobal> Globals = WasmObj->globals();
+
+  for (const auto &C : WasmObj->comdats())
+    Symtab->addComdat(C, this);
+
+  FunctionSymbols.resize(NumFunctionImports + Funcs.size());
+  GlobalSymbols.resize(NumGlobalImports + Globals.size());
+
   for (const WasmSegment &S : WasmObj->dataSegments()) {
     InputSegment *Seg = make<InputSegment>(S, this);
     Seg->copyRelocations(*DataSection);
     Segments.emplace_back(Seg);
   }
 
-  ArrayRef<WasmFunction> Funcs = WasmObj->functions();
-  ArrayRef<uint32_t> FuncTypes = WasmObj->functionTypes();
-  ArrayRef<WasmSignature> Types = WasmObj->types();
   for (size_t I = 0; I < Funcs.size(); ++I) {
     const WasmFunction &Func = Funcs[I];
     const WasmSignature &Sig = Types[FuncTypes[I]];
@@ -210,21 +223,35 @@ void ObjFile::initializeSymbols() {
     const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl());
     Symbol *S;
     switch (WasmSym.Type) {
+    case WasmSymbol::SymbolType::FUNCTION_EXPORT: {
+      InputFunction *Function = getFunction(WasmSym);
+      if (!isExcludedByComdat(Function)) {
+        S = createDefined(WasmSym, Symbol::Kind::DefinedFunctionKind, nullptr,
+                          Function);
+        break;
+      } else {
+        Function->Discarded = true;
+        LLVM_FALLTHROUGH; // Exclude function, and add the symbol as undefined
+      }
+    }
     case WasmSymbol::SymbolType::FUNCTION_IMPORT:
       S = createUndefined(WasmSym, Symbol::Kind::UndefinedFunctionKind,
                           getFunctionSig(WasmSym));
       break;
+    case WasmSymbol::SymbolType::GLOBAL_EXPORT: {
+      InputSegment *Segment = getSegment(WasmSym);
+      if (!isExcludedByComdat(Segment)) {
+        S = createDefined(WasmSym, Symbol::Kind::DefinedGlobalKind,
+                          Segment, nullptr, getGlobalValue(WasmSym));
+        break;
+      } else {
+        Segment->Discarded = true;
+        LLVM_FALLTHROUGH; // Exclude global, and add the symbol as undefined
+      }
+    }
     case WasmSymbol::SymbolType::GLOBAL_IMPORT:
       S = createUndefined(WasmSym, Symbol::Kind::UndefinedGlobalKind);
       break;
-    case WasmSymbol::SymbolType::GLOBAL_EXPORT:
-      S = createDefined(WasmSym, Symbol::Kind::DefinedGlobalKind,
-                        getSegment(WasmSym), nullptr, getGlobalValue(WasmSym));
-      break;
-    case WasmSymbol::SymbolType::FUNCTION_EXPORT:
-      S = createDefined(WasmSym, Symbol::Kind::DefinedFunctionKind, nullptr,
-                        getFunction(WasmSym));
-      break;
     case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
       // These are for debugging only, no need to create linker symbols for them
       continue;

Modified: lld/trunk/wasm/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/InputFiles.h?rev=322415&r1=322414&r2=322415&view=diff
==============================================================================
--- lld/trunk/wasm/InputFiles.h (original)
+++ lld/trunk/wasm/InputFiles.h Fri Jan 12 14:25:17 2018
@@ -33,6 +33,7 @@ using llvm::wasm::WasmRelocation;
 namespace lld {
 namespace wasm {
 
+class InputChunk;
 class InputFunction;
 class InputSegment;
 
@@ -122,6 +123,7 @@ private:
   const WasmSignature *getFunctionSig(const WasmSymbol &Sym) const;
   uint32_t getGlobalValue(const WasmSymbol &Sym) const;
   InputFunction *getFunction(const WasmSymbol &Sym) const;
+  bool isExcludedByComdat(InputChunk *Chunk) const;
 
   // List of all symbols referenced or defined by this file.
   std::vector<Symbol *> Symbols;

Modified: lld/trunk/wasm/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SymbolTable.cpp?rev=322415&r1=322414&r2=322415&view=diff
==============================================================================
--- lld/trunk/wasm/SymbolTable.cpp (original)
+++ lld/trunk/wasm/SymbolTable.cpp Fri Jan 12 14:25:17 2018
@@ -237,3 +237,19 @@ void SymbolTable::addLazy(ArchiveFile *F
     F->addMember(Sym);
   }
 }
+
+bool SymbolTable::addComdat(StringRef Name, ObjFile *F) {
+  DEBUG(dbgs() << "addComdat: " << Name << "\n");
+  ObjFile *&File = ComdatMap[CachedHashStringRef(Name)];
+  if (File) {
+    DEBUG(dbgs() << "COMDAT already defined\n");
+    return false;
+  }
+  File = F;
+  return true;
+}
+
+ObjFile *SymbolTable::findComdat(StringRef Name) const {
+  auto It = ComdatMap.find(CachedHashStringRef(Name));
+  return It == ComdatMap.end() ? nullptr : It->second;
+}

Modified: lld/trunk/wasm/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SymbolTable.h?rev=322415&r1=322414&r2=322415&view=diff
==============================================================================
--- lld/trunk/wasm/SymbolTable.h (original)
+++ lld/trunk/wasm/SymbolTable.h Fri Jan 12 14:25:17 2018
@@ -47,6 +47,7 @@ public:
 
   ArrayRef<Symbol *> getSymbols() const { return SymVector; }
   Symbol *find(StringRef Name);
+  ObjFile *findComdat(StringRef Name) const;
 
   Symbol *addDefined(StringRef Name, Symbol::Kind Kind, uint32_t Flags,
                      InputFile *F, const InputSegment *Segment = nullptr,
@@ -58,10 +59,12 @@ public:
   Symbol *addDefinedFunction(StringRef Name, const WasmSignature *Type,
                              uint32_t Flags);
   void addLazy(ArchiveFile *F, const Archive::Symbol *Sym);
+  bool addComdat(StringRef Name, ObjFile *);
 
 private:
   std::pair<Symbol *, bool> insert(StringRef Name);
 
+  llvm::DenseMap<llvm::CachedHashStringRef, ObjFile *> ComdatMap;
   llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> SymMap;
   std::vector<Symbol *> SymVector;
 };

Modified: lld/trunk/wasm/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Writer.cpp?rev=322415&r1=322414&r2=322415&view=diff
==============================================================================
--- lld/trunk/wasm/Writer.cpp (original)
+++ lld/trunk/wasm/Writer.cpp Fri Jan 12 14:25:17 2018
@@ -25,6 +25,7 @@
 #include "llvm/Support/LEB128.h"
 
 #include <cstdarg>
+#include <map>
 
 #define DEBUG_TYPE "lld"
 
@@ -427,6 +428,42 @@ void Writer::createLinkingSection() {
     SubSection.finalizeContents();
     SubSection.writeToStream(OS);
   }
+
+  struct ComdatEntry { unsigned Kind; uint32_t Index; };
+  std::map<StringRef,std::vector<ComdatEntry>> Comdats;
+
+  for (const InputFunction *F : DefinedFunctions) {
+    StringRef Comdat = F->getComdat();
+    if (!Comdat.empty())
+      Comdats[Comdat].emplace_back(
+          ComdatEntry{WASM_COMDAT_FUNCTION, F->getOutputIndex()});
+  }
+  for (uint32_t I = 0; I < Segments.size(); ++I) {
+    const auto &InputSegments = Segments[I]->InputSegments;
+    if (InputSegments.empty())
+      continue;
+    StringRef Comdat = InputSegments[0]->getComdat();
+    for (const InputSegment *IS : InputSegments)
+      assert(IS->getComdat() == Comdat);
+    if (!Comdat.empty())
+      Comdats[Comdat].emplace_back(ComdatEntry{WASM_COMDAT_DATA, I});
+  }
+
+  if (!Comdats.empty()) {
+    SubSection SubSection(WASM_COMDAT_INFO);
+    writeUleb128(SubSection.getStream(), Comdats.size(), "num comdats");
+    for (const auto &C : Comdats) {
+      writeStr(SubSection.getStream(), C.first, "comdat name");
+      writeUleb128(SubSection.getStream(), 0, "comdat flags"); // flags for future use
+      writeUleb128(SubSection.getStream(), C.second.size(), "num entries");
+      for (const ComdatEntry &Entry : C.second) {
+        writeUleb128(SubSection.getStream(), Entry.Kind, "entry kind");
+        writeUleb128(SubSection.getStream(), Entry.Index, "entry index");
+      }
+    }
+    SubSection.finalizeContents();
+    SubSection.writeToStream(OS);
+  }
 }
 
 // Create the custom "name" section containing debug symbol names.
@@ -654,6 +691,8 @@ void Writer::assignIndexes() {
   for (ObjFile *File : Symtab->ObjectFiles) {
     DEBUG(dbgs() << "Functions: " << File->getName() << "\n");
     for (InputFunction *Func : File->Functions) {
+      if (Func->Discarded)
+        continue;
       DefinedFunctions.emplace_back(Func);
       Func->setOutputIndex(FunctionIndex++);
     }
@@ -689,6 +728,8 @@ static StringRef getOutputDataSegmentNam
 void Writer::createOutputSegments() {
   for (ObjFile *File : Symtab->ObjectFiles) {
     for (InputSegment *Segment : File->Segments) {
+      if (Segment->Discarded)
+        continue;
       StringRef Name = getOutputDataSegmentName(Segment->getName());
       OutputSegment *&S = SegmentMap[Name];
       if (S == nullptr) {




More information about the llvm-commits mailing list