<div dir="ltr">This doesn't build for me.<div><br></div><div><div>/home/michael/llvm-project/lld/wasm/Symbols.h:240:3: error: static assertion failed: Symbol types must be trivially destructible │</div><div> static_assert(std::is_trivially_destructible<T>(), │</div><div> ^~~~~~~~~~~~~</div><div class="gmail_extra"><br clear="all"><div><div class="gmail_signature">- Michael Spencer</div></div>
<br><div class="gmail_quote">On Wed, Feb 14, 2018 at 10:27 AM, Sam Clegg via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: sbc<br>
Date: Wed Feb 14 10:27:59 2018<br>
New Revision: 325150<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=325150&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=325150&view=rev</a><br>
Log:<br>
[WebAssembly] Use a Symbol class heirarchy. NFC.<br>
<br>
This brings wasm into line with ELF and COFF in terms of<br>
symbol types are represented.<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D43112" rel="noreferrer" target="_blank">https://reviews.llvm.org/<wbr>D43112</a><br>
<br>
Modified:<br>
lld/trunk/wasm/InputFiles.cpp<br>
lld/trunk/wasm/InputFiles.h<br>
lld/trunk/wasm/SymbolTable.cpp<br>
lld/trunk/wasm/SymbolTable.h<br>
lld/trunk/wasm/Symbols.cpp<br>
lld/trunk/wasm/Symbols.h<br>
lld/trunk/wasm/Writer.cpp<br>
<br>
Modified: lld/trunk/wasm/InputFiles.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/InputFiles.cpp?rev=325150&r1=325149&r2=325150&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/lld/trunk/wasm/<wbr>InputFiles.cpp?rev=325150&r1=<wbr>325149&r2=325150&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lld/trunk/wasm/InputFiles.cpp (original)<br>
+++ lld/trunk/wasm/InputFiles.cpp Wed Feb 14 10:27:59 2018<br>
@@ -51,11 +51,14 @@ void ObjFile::dumpInfo() const {<br>
}<br>
<br>
uint32_t ObjFile::<wbr>relocateVirtualAddress(uint32_<wbr>t GlobalIndex) const {<br>
- return getGlobalSymbol(GlobalIndex)-><wbr>getVirtualAddress();<br>
+ if (auto *DG = dyn_cast<DefinedGlobal>(<wbr>getGlobalSymbol(GlobalIndex)))<br>
+ return DG->getVirtualAddress();<br>
+ else<br>
+ return 0;<br>
}<br>
<br>
uint32_t ObjFile::<wbr>relocateFunctionIndex(uint32_t Original) const {<br>
- const Symbol *Sym = getFunctionSymbol(Original);<br>
+ const FunctionSymbol *Sym = getFunctionSymbol(Original);<br>
uint32_t Index = Sym->getOutputIndex();<br>
DEBUG(dbgs() << "relocateFunctionIndex: " << toString(*Sym) << ": "<br>
<< Original << " -> " << Index << "\n");<br>
@@ -68,7 +71,7 @@ uint32_t ObjFile::relocateTypeIndex(<wbr>uint<br>
}<br>
<br>
uint32_t ObjFile::relocateTableIndex(<wbr>uint32_t Original) const {<br>
- const Symbol *Sym = getFunctionSymbol(Original);<br>
+ const FunctionSymbol *Sym = getFunctionSymbol(Original);<br>
uint32_t Index = Sym->hasTableIndex() ? Sym->getTableIndex() : 0;<br>
DEBUG(dbgs() << "relocateTableIndex: " << toString(*Sym) << ": " << Original<br>
<< " -> " << Index << "\n");<br>
@@ -249,7 +252,7 @@ void ObjFile::initializeSymbols() {<br>
case WasmSymbol::SymbolType::<wbr>FUNCTION_EXPORT: {<br>
InputFunction *Function = getFunction(WasmSym);<br>
if (!isExcludedByComdat(Function)<wbr>) {<br>
- S = createDefined(WasmSym, Symbol::Kind::<wbr>DefinedFunctionKind, Function);<br>
+ S = createDefinedFunction(WasmSym, Function);<br>
break;<br>
} else {<br>
Function->Live = false;<br>
@@ -263,8 +266,7 @@ void ObjFile::initializeSymbols() {<br>
case WasmSymbol::SymbolType::<wbr>GLOBAL_EXPORT: {<br>
InputSegment *Segment = getSegment(WasmSym);<br>
if (!isExcludedByComdat(Segment)) {<br>
- S = createDefined(WasmSym, Symbol::Kind::<wbr>DefinedGlobalKind, Segment,<br>
- getGlobalValue(WasmSym));<br>
+ S = createDefinedGlobal(WasmSym, Segment, getGlobalValue(WasmSym));<br>
break;<br>
} else {<br>
Segment->Live = false;<br>
@@ -302,15 +304,18 @@ Symbol *ObjFile::createUndefined(<wbr>const W<br>
return Symtab->addUndefined(Sym.Name, Kind, Sym.Flags, this, Signature);<br>
}<br>
<br>
-Symbol *ObjFile::createDefined(const WasmSymbol &Sym, Symbol::Kind Kind,<br>
- InputChunk *Chunk, uint32_t Address) {<br>
- Symbol *S;<br>
- if (Sym.isBindingLocal()) {<br>
- S = make<Symbol>(Sym.Name, true);<br>
- S->update(Kind, this, Sym.Flags, Chunk, Address);<br>
- return S;<br>
- }<br>
- return Symtab->addDefined(Sym.Name, Kind, Sym.Flags, this, Chunk, Address);<br>
+Symbol *ObjFile::<wbr>createDefinedFunction(const WasmSymbol &Sym,<br>
+ InputChunk *Chunk) {<br>
+ if (Sym.isBindingLocal())<br>
+ return make<DefinedFunction>(Sym.<wbr>Name, Sym.Flags, this, Chunk);<br>
+ return Symtab->addDefined(true, Sym.Name, Sym.Flags, this, Chunk);<br>
+}<br>
+<br>
+Symbol *ObjFile::createDefinedGlobal(<wbr>const WasmSymbol &Sym, InputChunk *Chunk,<br>
+ uint32_t Address) {<br>
+ if (Sym.isBindingLocal())<br>
+ return make<DefinedGlobal>(Sym.Name, Sym.Flags, this, Chunk, Address);<br>
+ return Symtab->addDefined(false, Sym.Name, Sym.Flags, this, Chunk, Address);<br>
}<br>
<br>
void ArchiveFile::parse() {<br>
<br>
Modified: lld/trunk/wasm/InputFiles.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/InputFiles.h?rev=325150&r1=325149&r2=325150&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/lld/trunk/wasm/<wbr>InputFiles.h?rev=325150&r1=<wbr>325149&r2=325150&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lld/trunk/wasm/InputFiles.h (original)<br>
+++ lld/trunk/wasm/InputFiles.h Wed Feb 14 10:27:59 2018<br>
@@ -107,11 +107,13 @@ public:<br>
<br>
ArrayRef<Symbol *> getSymbols() const { return Symbols; }<br>
<br>
- Symbol *getFunctionSymbol(uint32_t Index) const {<br>
- return FunctionSymbols[Index];<br>
+ FunctionSymbol *getFunctionSymbol(uint32_t Index) const {<br>
+ return cast<FunctionSymbol>(<wbr>FunctionSymbols[Index]);<br>
}<br>
<br>
- Symbol *getGlobalSymbol(uint32_t Index) const { return GlobalSymbols[Index]; }<br>
+ GlobalSymbol *getGlobalSymbol(uint32_t Index) const {<br>
+ return cast<GlobalSymbol>(<wbr>GlobalSymbols[Index]);<br>
+ }<br>
<br>
private:<br>
uint32_t relocateVirtualAddress(uint32_<wbr>t Index) const;<br>
@@ -119,9 +121,9 @@ private:<br>
uint32_t relocateGlobalIndex(uint32_t Original) const;<br>
uint32_t relocateTableIndex(uint32_t Original) const;<br>
<br>
- Symbol *createDefined(const WasmSymbol &Sym, Symbol::Kind Kind,<br>
- InputChunk *Chunk = nullptr,<br>
- uint32_t Address = UINT32_MAX);<br>
+ Symbol *createDefinedGlobal(const WasmSymbol &Sym, InputChunk *Chunk,<br>
+ uint32_t Address);<br>
+ Symbol *createDefinedFunction(const WasmSymbol &Sym, InputChunk *Chunk);<br>
Symbol *createUndefined(const WasmSymbol &Sym, Symbol::Kind Kind,<br>
const WasmSignature *Signature = nullptr);<br>
void initializeSymbols();<br>
<br>
Modified: lld/trunk/wasm/SymbolTable.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SymbolTable.cpp?rev=325150&r1=325149&r2=325150&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/lld/trunk/wasm/<wbr>SymbolTable.cpp?rev=325150&r1=<wbr>325149&r2=325150&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lld/trunk/wasm/SymbolTable.cpp (original)<br>
+++ lld/trunk/wasm/SymbolTable.cpp Wed Feb 14 10:27:59 2018<br>
@@ -66,7 +66,7 @@ std::pair<Symbol *, bool> SymbolTable::i<br>
Symbol *&Sym = SymMap[CachedHashStringRef(<wbr>Name)];<br>
if (Sym)<br>
return {Sym, false};<br>
- Sym = make<Symbol>(Name, false);<br>
+ Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());<br>
SymVector.emplace_back(Sym);<br>
return {Sym, true};<br>
}<br>
@@ -80,13 +80,10 @@ void SymbolTable::reportDuplicate(<wbr>Symbol<br>
// Check the type of new symbol matches that of the symbol is replacing.<br>
// For functions this can also involve verifying that the signatures match.<br>
static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,<br>
- Symbol::Kind Kind, const WasmSignature *NewSig) {<br>
+ bool NewIsFunction, const WasmSignature *NewSig) {<br>
if (Existing.isLazy())<br>
return;<br>
<br>
- bool NewIsFunction = Kind == Symbol::Kind::<wbr>UndefinedFunctionKind ||<br>
- Kind == Symbol::Kind::<wbr>DefinedFunctionKind;<br>
-<br>
// First check the symbol types match (i.e. either both are function<br>
// symbols or both are data symbols).<br>
if (Existing.isFunction() != NewIsFunction) {<br>
@@ -98,105 +95,102 @@ static void checkSymbolTypes(const Symbo<br>
}<br>
<br>
// For function symbols, optionally check the function signature matches too.<br>
- if (!NewIsFunction || !Config->CheckSignatures)<br>
+ auto *ExistingFunc = dyn_cast<FunctionSymbol>(&<wbr>Existing);<br>
+ if (!ExistingFunc || !Config->CheckSignatures)<br>
return;<br>
+<br>
// Skip the signature check if the existing function has no signature (e.g.<br>
// if it is an undefined symbol generated by --undefined command line flag).<br>
- if (!Existing.hasFunctionType())<br>
+ if (!ExistingFunc-><wbr>hasFunctionType())<br>
return;<br>
<br>
- DEBUG(dbgs() << "checkSymbolTypes: " << Existing.getName() << "\n");<br>
+ DEBUG(dbgs() << "checkSymbolTypes: " << ExistingFunc->getName() << "\n");<br>
assert(NewSig);<br>
<br>
- const WasmSignature &OldSig = Existing.getFunctionType();<br>
+ const WasmSignature &OldSig = ExistingFunc->getFunctionType(<wbr>);<br>
if (*NewSig == OldSig)<br>
return;<br>
<br>
- error("function signature mismatch: " + Existing.getName() +<br>
+ error("function signature mismatch: " + ExistingFunc->getName() +<br>
"\n>>> defined as " + toString(OldSig) + " in " +<br>
- toString(Existing.getFile()) + "\n>>> defined as " + toString(*NewSig) +<br>
- " in " + F.getName());<br>
+ toString(ExistingFunc-><wbr>getFile()) + "\n>>> defined as " +<br>
+ toString(*NewSig) + " in " + F.getName());<br>
}<br>
<br>
static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,<br>
- Symbol::Kind Kind, const InputChunk *Chunk) {<br>
+ bool IsFunction, const InputChunk *Chunk) {<br>
const WasmSignature *Sig = nullptr;<br>
if (auto *F = dyn_cast_or_null<<wbr>InputFunction>(Chunk))<br>
Sig = &F->Signature;<br>
- return checkSymbolTypes(Existing, F, Kind, Sig);<br>
+ return checkSymbolTypes(Existing, F, IsFunction, Sig);<br>
}<br>
<br>
-Symbol *SymbolTable::<wbr>addSyntheticFunction(StringRef Name,<br>
- const WasmSignature *Type,<br>
- uint32_t Flags) {<br>
+DefinedFunction *SymbolTable::<wbr>addSyntheticFunction(StringRef Name,<br>
+ const WasmSignature *Type,<br>
+ uint32_t Flags) {<br>
DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");<br>
Symbol *S;<br>
bool WasInserted;<br>
std::tie(S, WasInserted) = insert(Name);<br>
assert(WasInserted);<br>
- S->update(Symbol::<wbr>DefinedFunctionKind, nullptr, Flags);<br>
- S->setFunctionType(Type);<br>
- return S;<br>
+ return replaceSymbol<DefinedFunction><wbr>(S, Name, Flags, Type);<br>
}<br>
<br>
-Symbol *SymbolTable::<wbr>addSyntheticGlobal(StringRef Name) {<br>
+DefinedGlobal *SymbolTable::<wbr>addSyntheticGlobal(StringRef Name, uint32_t Flags) {<br>
DEBUG(dbgs() << "addSyntheticGlobal: " << Name << "\n");<br>
Symbol *S;<br>
bool WasInserted;<br>
std::tie(S, WasInserted) = insert(Name);<br>
assert(WasInserted);<br>
- S->update(Symbol::<wbr>DefinedGlobalKind);<br>
- return S;<br>
+ return replaceSymbol<DefinedGlobal>(<wbr>S, Name, Flags);<br>
}<br>
<br>
-Symbol *SymbolTable::addDefined(<wbr>StringRef Name, Symbol::Kind Kind,<br>
- uint32_t Flags, InputFile *F, InputChunk *Chunk,<br>
+Symbol *SymbolTable::addDefined(bool IsFunction, StringRef Name, uint32_t Flags,<br>
+ InputFile *F, InputChunk *Chunk,<br>
uint32_t Address) {<br>
- DEBUG(dbgs() << "addDefined: " << Name << " addr:" << Address << "\n");<br>
+ if (IsFunction)<br>
+ DEBUG(dbgs() << "addDefined: func:" << Name << "\n");<br>
+ else<br>
+ DEBUG(dbgs() << "addDefined: global:" << Name << " addr:" << Address<br>
+ << "\n");<br>
Symbol *S;<br>
bool WasInserted;<br>
+ bool Replace = false;<br>
+ bool CheckTypes = false;<br>
<br>
std::tie(S, WasInserted) = insert(Name);<br>
if (WasInserted) {<br>
- S->update(Kind, F, Flags, Chunk, Address);<br>
+ Replace = true;<br>
} else if (S->isLazy()) {<br>
- // The existing symbol is lazy. Replace it without checking types since<br>
+ // Existing symbol is lazy. Replace it without checking types since<br>
// lazy symbols don't have any type information.<br>
DEBUG(dbgs() << "replacing existing lazy symbol: " << Name << "\n");<br>
- S->update(Kind, F, Flags, Chunk, Address);<br>
+ Replace = true;<br>
} else if (!S->isDefined()) {<br>
- // The existing symbol table entry is undefined. The new symbol replaces<br>
- // it, after checking the type matches<br>
+ // Existing symbol is undefined: replace it, while check types.<br>
DEBUG(dbgs() << "resolving existing undefined symbol: " << Name << "\n");<br>
- checkSymbolTypes(*S, *F, Kind, Chunk);<br>
- S->update(Kind, F, Flags, Chunk, Address);<br>
+ Replace = true;<br>
+ CheckTypes = true;<br>
} else if ((Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {<br>
// the new symbol is weak we can ignore it<br>
DEBUG(dbgs() << "existing symbol takes precedence\n");<br>
} else if (S->isWeak()) {<br>
- // the new symbol is not weak and the existing symbol is, so we replace<br>
- // it<br>
+ // the existing symbol is, so we replace it<br>
DEBUG(dbgs() << "replacing existing weak symbol\n");<br>
- checkSymbolTypes(*S, *F, Kind, Chunk);<br>
- S->update(Kind, F, Flags, Chunk, Address);<br>
+ Replace = true;<br>
+ CheckTypes = true;<br>
} else {<br>
// neither symbol is week. They conflict.<br>
reportDuplicate(S, F);<br>
}<br>
- return S;<br>
-}<br>
<br>
-Symbol *SymbolTable::<wbr>addUndefinedFunction(StringRef Name,<br>
- const WasmSignature *Type) {<br>
- DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n");<br>
- Symbol *S;<br>
- bool WasInserted;<br>
- std::tie(S, WasInserted) = insert(Name);<br>
- if (WasInserted) {<br>
- S->update(Symbol::<wbr>UndefinedFunctionKind);<br>
- S->setFunctionType(Type);<br>
- } else if (!S->isFunction()) {<br>
- error("symbol type mismatch: " + Name);<br>
+ if (Replace) {<br>
+ if (CheckTypes)<br>
+ checkSymbolTypes(*S, *F, IsFunction, Chunk);<br>
+ if (IsFunction)<br>
+ replaceSymbol<DefinedFunction><wbr>(S, Name, Flags, F, Chunk);<br>
+ else<br>
+ replaceSymbol<DefinedGlobal>(<wbr>S, Name, Flags, F, Chunk, Address);<br>
}<br>
return S;<br>
}<br>
@@ -208,17 +202,19 @@ Symbol *SymbolTable::addUndefined(<wbr>String<br>
Symbol *S;<br>
bool WasInserted;<br>
std::tie(S, WasInserted) = insert(Name);<br>
+ bool IsFunction = Kind == Symbol::UndefinedFunctionKind;<br>
if (WasInserted) {<br>
- S->update(Kind, F, Flags);<br>
- if (Type)<br>
- S->setFunctionType(Type);<br>
- } else if (S->isLazy()) {<br>
+ if (IsFunction)<br>
+ replaceSymbol<<wbr>UndefinedFunction>(S, Name, Flags, F, Type);<br>
+ else<br>
+ replaceSymbol<UndefinedGlobal><wbr>(S, Name, Flags, F);<br>
+ } else if (auto *LazySym = dyn_cast<LazySymbol>(S)) {<br>
DEBUG(dbgs() << "resolved by existing lazy\n");<br>
- auto *AF = cast<ArchiveFile>(S->getFile()<wbr>);<br>
- AF->addMember(&S-><wbr>getArchiveSymbol());<br>
+ auto *AF = cast<ArchiveFile>(LazySym-><wbr>getFile());<br>
+ AF->addMember(&LazySym-><wbr>getArchiveSymbol());<br>
} else if (S->isDefined()) {<br>
DEBUG(dbgs() << "resolved by existing\n");<br>
- checkSymbolTypes(*S, *F, Kind, Type);<br>
+ checkSymbolTypes(*S, *F, IsFunction, Type);<br>
}<br>
return S;<br>
}<br>
@@ -230,8 +226,7 @@ void SymbolTable::addLazy(<wbr>ArchiveFile *F<br>
bool WasInserted;<br>
std::tie(S, WasInserted) = insert(Name);<br>
if (WasInserted) {<br>
- S->update(Symbol::LazyKind, F);<br>
- S->setArchiveSymbol(*Sym);<br>
+ replaceSymbol<LazySymbol>(S, Name, F, *Sym);<br>
} else if (S->isUndefined()) {<br>
// There is an existing undefined symbol. The can load from the<br>
// archive.<br>
<br>
Modified: lld/trunk/wasm/SymbolTable.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SymbolTable.h?rev=325150&r1=325149&r2=325150&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/lld/trunk/wasm/<wbr>SymbolTable.h?rev=325150&r1=<wbr>325149&r2=325150&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lld/trunk/wasm/SymbolTable.h (original)<br>
+++ lld/trunk/wasm/SymbolTable.h Wed Feb 14 10:27:59 2018<br>
@@ -49,7 +49,7 @@ public:<br>
Symbol *find(StringRef Name);<br>
ObjFile *findComdat(StringRef Name) const;<br>
<br>
- Symbol *addDefined(StringRef Name, Symbol::Kind Kind, uint32_t Flags,<br>
+ Symbol *addDefined(bool IsFunction, StringRef Name, uint32_t Flags,<br>
InputFile *F, InputChunk *Chunk = nullptr,<br>
uint32_t Address = 0);<br>
Symbol *addUndefined(StringRef Name, Symbol::Kind Kind, uint32_t Flags,<br>
@@ -58,9 +58,10 @@ public:<br>
void addLazy(ArchiveFile *F, const Archive::Symbol *Sym);<br>
bool addComdat(StringRef Name, ObjFile *);<br>
<br>
- Symbol *addSyntheticGlobal(StringRef Name);<br>
- Symbol *addSyntheticFunction(<wbr>StringRef Name, const WasmSignature *Type,<br>
- uint32_t Flags);<br>
+ DefinedGlobal *addSyntheticGlobal(StringRef Name, uint32_t Flags = 0);<br>
+ DefinedFunction *addSyntheticFunction(<wbr>StringRef Name,<br>
+ const WasmSignature *Type,<br>
+ uint32_t Flags = 0);<br>
private:<br>
std::pair<Symbol *, bool> insert(StringRef Name);<br>
<br>
<br>
Modified: lld/trunk/wasm/Symbols.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.cpp?rev=325150&r1=325149&r2=325150&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/lld/trunk/wasm/<wbr>Symbols.cpp?rev=325150&r1=<wbr>325149&r2=325150&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lld/trunk/wasm/Symbols.cpp (original)<br>
+++ lld/trunk/wasm/Symbols.cpp Wed Feb 14 10:27:59 2018<br>
@@ -22,32 +22,11 @@ using namespace llvm::wasm;<br>
using namespace lld;<br>
using namespace lld::wasm;<br>
<br>
-Symbol *WasmSym::CallCtors;<br>
-Symbol *WasmSym::DsoHandle;<br>
-Symbol *WasmSym::DataEnd;<br>
-Symbol *WasmSym::HeapBase;<br>
-Symbol *WasmSym::StackPointer;<br>
-<br>
-const WasmSignature &Symbol::getFunctionType() const {<br>
- if (Chunk != nullptr)<br>
- return dyn_cast<InputFunction>(Chunk)<wbr>->Signature;<br>
-<br>
- assert(FunctionType != nullptr);<br>
- return *FunctionType;<br>
-}<br>
-<br>
-void Symbol::setFunctionType(const WasmSignature *Type) {<br>
- assert(FunctionType == nullptr);<br>
- assert(!Chunk);<br>
- FunctionType = Type;<br>
-}<br>
-<br>
-uint32_t Symbol::getVirtualAddress() const {<br>
- assert(isGlobal());<br>
- DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");<br>
- return Chunk ? dyn_cast<InputSegment>(Chunk)-<wbr>>translateVA(VirtualAddress)<br>
- : VirtualAddress;<br>
-}<br>
+DefinedFunction *WasmSym::CallCtors;<br>
+DefinedGlobal *WasmSym::DsoHandle;<br>
+DefinedGlobal *WasmSym::DataEnd;<br>
+DefinedGlobal *WasmSym::HeapBase;<br>
+DefinedGlobal *WasmSym::StackPointer;<br>
<br>
bool Symbol::hasOutputIndex() const {<br>
if (auto *F = dyn_cast_or_null<<wbr>InputFunction>(Chunk))<br>
@@ -61,12 +40,6 @@ uint32_t Symbol::getOutputIndex() const<br>
return OutputIndex.getValue();<br>
}<br>
<br>
-void Symbol::setVirtualAddress(<wbr>uint32_t Value) {<br>
- DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n");<br>
- assert(isGlobal());<br>
- VirtualAddress = Value;<br>
-}<br>
-<br>
void Symbol::setOutputIndex(uint32_<wbr>t Index) {<br>
DEBUG(dbgs() << "setOutputIndex " << Name << " -> " << Index << "\n");<br>
assert(!dyn_cast_or_null<<wbr>InputFunction>(Chunk));<br>
@@ -74,19 +47,54 @@ void Symbol::setOutputIndex(uint32_<wbr>t Ind<br>
OutputIndex = Index;<br>
}<br>
<br>
-uint32_t Symbol::getTableIndex() const {<br>
+bool Symbol::isWeak() const {<br>
+ return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;<br>
+}<br>
+<br>
+bool Symbol::isLocal() const {<br>
+ return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;<br>
+}<br>
+<br>
+bool Symbol::isHidden() const {<br>
+ return (Flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;<br>
+}<br>
+<br>
+void Symbol::setHidden(bool IsHidden) {<br>
+ DEBUG(dbgs() << "setHidden: " << Name << " -> " << IsHidden << "\n");<br>
+ Flags &= ~WASM_SYMBOL_VISIBILITY_MASK;<br>
+ if (IsHidden)<br>
+ Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;<br>
+ else<br>
+ Flags |= WASM_SYMBOL_VISIBILITY_<wbr>DEFAULT;<br>
+}<br>
+<br>
+const WasmSignature &FunctionSymbol::<wbr>getFunctionType() const {<br>
+ if (auto *F = dyn_cast_or_null<<wbr>InputFunction>(Chunk))<br>
+ return F->Signature;<br>
+<br>
+ assert(FunctionType != nullptr);<br>
+ return *FunctionType;<br>
+}<br>
+<br>
+void FunctionSymbol::<wbr>setFunctionType(const WasmSignature *Type) {<br>
+ assert(FunctionType == nullptr);<br>
+ assert(!Chunk);<br>
+ FunctionType = Type;<br>
+}<br>
+<br>
+uint32_t FunctionSymbol::getTableIndex(<wbr>) const {<br>
if (auto *F = dyn_cast_or_null<<wbr>InputFunction>(Chunk))<br>
return F->getTableIndex();<br>
return TableIndex.getValue();<br>
}<br>
<br>
-bool Symbol::hasTableIndex() const {<br>
+bool FunctionSymbol::hasTableIndex(<wbr>) const {<br>
if (auto *F = dyn_cast_or_null<<wbr>InputFunction>(Chunk))<br>
return F->hasTableIndex();<br>
return TableIndex.hasValue();<br>
}<br>
<br>
-void Symbol::setTableIndex(uint32_t Index) {<br>
+void FunctionSymbol::setTableIndex(<wbr>uint32_t Index) {<br>
// For imports, we set the table index here on the Symbol; for defined<br>
// functions we set the index on the InputFunction so that we don't export<br>
// the same thing twice (keeps the table size down).<br>
@@ -99,35 +107,17 @@ void Symbol::setTableIndex(uint32_t Inde<br>
TableIndex = Index;<br>
}<br>
<br>
-void Symbol::update(Kind K, InputFile *F, uint32_t Flags_, InputChunk *Chunk_,<br>
- uint32_t Address) {<br>
- SymbolKind = K;<br>
- File = F;<br>
- Flags = Flags_;<br>
- Chunk = Chunk_;<br>
- if (Address != UINT32_MAX)<br>
- setVirtualAddress(Address);<br>
-}<br>
-<br>
-bool Symbol::isWeak() const {<br>
- return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;<br>
-}<br>
-<br>
-bool Symbol::isLocal() const {<br>
- return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;<br>
-}<br>
-<br>
-bool Symbol::isHidden() const {<br>
- return (Flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;<br>
+uint32_t DefinedGlobal::<wbr>getVirtualAddress() const {<br>
+ assert(isGlobal());<br>
+ DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");<br>
+ return Chunk ? dyn_cast<InputSegment>(Chunk)-<wbr>>translateVA(VirtualAddress)<br>
+ : VirtualAddress;<br>
}<br>
<br>
-void Symbol::setHidden(bool IsHidden) {<br>
- DEBUG(dbgs() << "setHidden: " << Name << " -> " << IsHidden << "\n");<br>
- Flags &= ~WASM_SYMBOL_VISIBILITY_MASK;<br>
- if (IsHidden)<br>
- Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;<br>
- else<br>
- Flags |= WASM_SYMBOL_VISIBILITY_<wbr>DEFAULT;<br>
+void DefinedGlobal::<wbr>setVirtualAddress(uint32_t Value) {<br>
+ DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n");<br>
+ assert(isGlobal());<br>
+ VirtualAddress = Value;<br>
}<br>
<br>
std::string lld::toString(const wasm::Symbol &Sym) {<br>
<br>
Modified: lld/trunk/wasm/Symbols.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.h?rev=325150&r1=325149&r2=325150&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/lld/trunk/wasm/<wbr>Symbols.h?rev=325150&r1=<wbr>325149&r2=325150&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lld/trunk/wasm/Symbols.h (original)<br>
+++ lld/trunk/wasm/Symbols.h Wed Feb 14 10:27:59 2018<br>
@@ -23,6 +23,7 @@ namespace wasm {<br>
class InputFile;<br>
class InputChunk;<br>
<br>
+// The base class for real symbol classes.<br>
class Symbol {<br>
public:<br>
enum Kind {<br>
@@ -37,9 +38,7 @@ public:<br>
InvalidKind,<br>
};<br>
<br>
- Symbol(StringRef Name, uint32_t Flags) : Flags(Flags), Name(Name) {}<br>
-<br>
- Kind getKind() const { return SymbolKind; }<br>
+ Kind kind() const { return static_cast<Kind>(SymbolKind); }<br>
<br>
bool isLazy() const { return SymbolKind == LazyKind; }<br>
bool isDefined() const { return SymbolKind <= LastDefinedKind; }<br>
@@ -63,9 +62,6 @@ public:<br>
InputFile *getFile() const { return File; }<br>
InputChunk *getChunk() const { return Chunk; }<br>
<br>
- bool hasFunctionType() const { return FunctionType != nullptr; }<br>
- const WasmSignature &getFunctionType() const;<br>
- void setFunctionType(const WasmSignature *Type);<br>
void setHidden(bool IsHidden);<br>
<br>
uint32_t getOutputIndex() const;<br>
@@ -77,6 +73,28 @@ public:<br>
// space of the output object.<br>
void setOutputIndex(uint32_t Index);<br>
<br>
+protected:<br>
+ Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F, InputChunk *C)<br>
+ : Name(Name), SymbolKind(K), Flags(Flags), File(F), Chunk(C) {}<br>
+<br>
+ StringRef Name;<br>
+ Kind SymbolKind;<br>
+ uint32_t Flags;<br>
+ InputFile *File;<br>
+ InputChunk *Chunk;<br>
+ llvm::Optional<uint32_t> OutputIndex;<br>
+};<br>
+<br>
+class FunctionSymbol : public Symbol {<br>
+public:<br>
+ static bool classof(const Symbol *S) {<br>
+ return S->kind() == DefinedFunctionKind ||<br>
+ S->kind() == UndefinedFunctionKind;<br>
+ }<br>
+<br>
+ bool hasFunctionType() const { return FunctionType != nullptr; }<br>
+ const WasmSignature &getFunctionType() const;<br>
+<br>
uint32_t getTableIndex() const;<br>
<br>
// Returns true if a table index has been set for this symbol<br>
@@ -85,30 +103,99 @@ public:<br>
// Set the table index of the symbol<br>
void setTableIndex(uint32_t Index);<br>
<br>
- // Returns the virtual address of a defined global.<br>
- // Only works for globals, not functions.<br>
+protected:<br>
+ void setFunctionType(const WasmSignature *Type);<br>
+<br>
+ FunctionSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,<br>
+ InputChunk *C)<br>
+ : Symbol(Name, K, Flags, F, C) {}<br>
+<br>
+ llvm::Optional<uint32_t> TableIndex;<br>
+<br>
+ // Explict function type, needed for undefined or synthetic functions only.<br>
+ const WasmSignature *FunctionType = nullptr;<br>
+};<br>
+<br>
+class DefinedFunction : public FunctionSymbol {<br>
+public:<br>
+ DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F = nullptr,<br>
+ InputChunk *C = nullptr)<br>
+ : FunctionSymbol(Name, DefinedFunctionKind, Flags, F, C) {}<br>
+<br>
+ DefinedFunction(StringRef Name, uint32_t Flags, const WasmSignature *Type)<br>
+ : FunctionSymbol(Name, DefinedFunctionKind, Flags, nullptr, nullptr) {<br>
+ setFunctionType(Type);<br>
+ }<br>
+<br>
+ static bool classof(const Symbol *S) {<br>
+ return S->kind() == DefinedFunctionKind;<br>
+ }<br>
+};<br>
+<br>
+class UndefinedFunction : public FunctionSymbol {<br>
+public:<br>
+ UndefinedFunction(StringRef Name, uint32_t Flags, InputFile *File = nullptr,<br>
+ const WasmSignature *Type = nullptr)<br>
+ : FunctionSymbol(Name, UndefinedFunctionKind, Flags, File, nullptr) {<br>
+ setFunctionType(Type);<br>
+ }<br>
+<br>
+ static bool classof(const Symbol *S) {<br>
+ return S->kind() == UndefinedFunctionKind;<br>
+ }<br>
+};<br>
+<br>
+class GlobalSymbol : public Symbol {<br>
+public:<br>
+ static bool classof(const Symbol *S) {<br>
+ return S->kind() == DefinedGlobalKind || S->kind() == UndefinedGlobalKind;<br>
+ }<br>
+<br>
+protected:<br>
+ GlobalSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,<br>
+ InputChunk *C)<br>
+ : Symbol(Name, K, Flags, F, C) {}<br>
+};<br>
+<br>
+class DefinedGlobal : public GlobalSymbol {<br>
+public:<br>
+ DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *F = nullptr,<br>
+ InputChunk *C = nullptr, uint32_t Address = 0)<br>
+ : GlobalSymbol(Name, DefinedGlobalKind, Flags, F, C),<br>
+ VirtualAddress(Address) {}<br>
+<br>
+ static bool classof(const Symbol *S) {<br>
+ return S->kind() == DefinedGlobalKind;<br>
+ }<br>
+<br>
uint32_t getVirtualAddress() const;<br>
<br>
void setVirtualAddress(uint32_t VA);<br>
<br>
- void update(Kind K, InputFile *F = nullptr, uint32_t Flags = 0,<br>
- InputChunk *chunk = nullptr, uint32_t Address = UINT32_MAX);<br>
+protected:<br>
+ uint32_t VirtualAddress;<br>
+};<br>
+<br>
+class UndefinedGlobal : public GlobalSymbol {<br>
+public:<br>
+ UndefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File = nullptr)<br>
+ : GlobalSymbol(Name, UndefinedGlobalKind, Flags, File, nullptr) {}<br>
+ static bool classof(const Symbol *S) {<br>
+ return S->kind() == UndefinedGlobalKind;<br>
+ }<br>
+};<br>
+<br>
+class LazySymbol : public Symbol {<br>
+public:<br>
+ LazySymbol(StringRef Name, InputFile *File, const Archive::Symbol &Sym)<br>
+ : Symbol(Name, LazyKind, 0, File, nullptr), ArchiveSymbol(Sym) {}<br>
+<br>
+ static bool classof(const Symbol *S) { return S->kind() == LazyKind; }<br>
<br>
- void setArchiveSymbol(const Archive::Symbol &Sym) { ArchiveSymbol = Sym; }<br>
const Archive::Symbol &getArchiveSymbol() { return ArchiveSymbol; }<br>
<br>
protected:<br>
- uint32_t Flags;<br>
- uint32_t VirtualAddress = 0;<br>
-<br>
- StringRef Name;<br>
- Archive::Symbol ArchiveSymbol = {nullptr, 0, 0};<br>
- Kind SymbolKind = InvalidKind;<br>
- InputFile *File = nullptr;<br>
- InputChunk *Chunk = nullptr;<br>
- llvm::Optional<uint32_t> OutputIndex;<br>
- llvm::Optional<uint32_t> TableIndex;<br>
- const WasmSignature *FunctionType = nullptr;<br>
+ Archive::Symbol ArchiveSymbol;<br>
};<br>
<br>
// linker-generated symbols<br>
@@ -116,27 +203,50 @@ struct WasmSym {<br>
// __stack_pointer<br>
// Global that holds the address of the top of the explicit value stack in<br>
// linear memory.<br>
- static Symbol *StackPointer;<br>
+ static DefinedGlobal *StackPointer;<br>
<br>
// __data_end<br>
// Symbol marking the end of the data and bss.<br>
- static Symbol *DataEnd;<br>
+ static DefinedGlobal *DataEnd;<br>
<br>
// __heap_base<br>
// Symbol marking the end of the data, bss and explicit stack. Any linear<br>
// memory following this address is not used by the linked code and can<br>
// therefore be used as a backing store for brk()/malloc() implementations.<br>
- static Symbol *HeapBase;<br>
+ static DefinedGlobal *HeapBase;<br>
<br>
// __wasm_call_ctors<br>
// Function that directly calls all ctors in priority order.<br>
- static Symbol *CallCtors;<br>
+ static DefinedFunction *CallCtors;<br>
<br>
// __dso_handle<br>
// Global used in calls to __cxa_atexit to determine current DLL<br>
- static Symbol *DsoHandle;<br>
+ static DefinedGlobal *DsoHandle;<br>
+};<br>
+<br>
+// A buffer class that is large enough to hold any Symbol-derived<br>
+// object. We allocate memory using this class and instantiate a symbol<br>
+// using the placement new.<br>
+union SymbolUnion {<br>
+ alignas(DefinedFunction) char A[sizeof(DefinedFunction)];<br>
+ alignas(DefinedGlobal) char B[sizeof(DefinedGlobal)];<br>
+ alignas(LazySymbol) char C[sizeof(LazySymbol)];<br>
+ alignas(UndefinedFunction) char D[sizeof(UndefinedFunction)];<br>
+ alignas(UndefinedGlobal) char E[sizeof(UndefinedFunction)];<br>
};<br>
<br>
+template <typename T, typename... ArgT><br>
+T *replaceSymbol(Symbol *S, ArgT &&... Arg) {<br>
+ static_assert(std::is_<wbr>trivially_destructible<T>(),<br>
+ "Symbol types must be trivially destructible");<br>
+ static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small");<br>
+ static_assert(alignof(T) <= alignof(SymbolUnion),<br>
+ "SymbolUnion not aligned enough");<br>
+ assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&<br>
+ "Not a Symbol");<br>
+ return new (S) T(std::forward<ArgT>(Arg)...);<br>
+}<br>
+<br>
} // namespace wasm<br>
<br>
// Returns a symbol name for an error message.<br>
<br>
Modified: lld/trunk/wasm/Writer.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Writer.cpp?rev=325150&r1=325149&r2=325150&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/lld/trunk/wasm/Writer.<wbr>cpp?rev=325150&r1=325149&r2=<wbr>325150&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lld/trunk/wasm/Writer.cpp (original)<br>
+++ lld/trunk/wasm/Writer.cpp Wed Feb 14 10:27:59 2018<br>
@@ -119,12 +119,12 @@ private:<br>
<br>
std::vector<const WasmSignature *> Types;<br>
DenseMap<WasmSignature, int32_t, WasmSignatureDenseMapInfo> TypeIndices;<br>
- std::vector<const Symbol *> ImportedFunctions;<br>
- std::vector<const Symbol *> ImportedGlobals;<br>
+ std::vector<const FunctionSymbol *> ImportedFunctions;<br>
+ std::vector<const GlobalSymbol *> ImportedGlobals;<br>
std::vector<WasmExportEntry> ExportedSymbols;<br>
- std::vector<const Symbol *> DefinedGlobals;<br>
+ std::vector<const DefinedGlobal *> DefinedGlobals;<br>
std::vector<InputFunction *> DefinedFunctions;<br>
- std::vector<const Symbol *> IndirectFunctions;<br>
+ std::vector<const FunctionSymbol *> IndirectFunctions;<br>
std::vector<WasmInitFunc> InitFunctions;<br>
<br>
// Elements that are used to construct the final output<br>
@@ -164,7 +164,7 @@ void Writer::createImportSection() {<br>
<br>
writeUleb128(OS, NumImports, "import count");<br>
<br>
- for (const Symbol *Sym : ImportedFunctions) {<br>
+ for (const FunctionSymbol *Sym : ImportedFunctions) {<br>
WasmImport Import;<br>
Import.Module = "env";<br>
Import.Field = Sym->getName();<br>
@@ -234,7 +234,7 @@ void Writer::createGlobalSection() {<br>
raw_ostream &OS = Section->getStream();<br>
<br>
writeUleb128(OS, DefinedGlobals.size(), "global count");<br>
- for (const Symbol *Sym : DefinedGlobals) {<br>
+ for (const DefinedGlobal *Sym : DefinedGlobals) {<br>
WasmGlobal Global;<br>
Global.Type.Type = WASM_TYPE_I32;<br>
Global.Type.Mutable = Sym == WasmSym::StackPointer;<br>
@@ -316,7 +316,7 @@ void Writer::createElemSection() {<br>
writeUleb128(OS, IndirectFunctions.size(), "elem count");<br>
<br>
uint32_t TableIndex = kInitialTableOffset;<br>
- for (const Symbol *Sym : IndirectFunctions) {<br>
+ for (const FunctionSymbol *Sym : IndirectFunctions) {<br>
assert(Sym->getTableIndex() == TableIndex);<br>
writeUleb128(OS, Sym->getOutputIndex(), "function index");<br>
++TableIndex;<br>
@@ -619,12 +619,12 @@ void Writer::calculateImports() {<br>
if (!Sym->isUndefined() || (Sym->isWeak() && !Config->Relocatable))<br>
continue;<br>
<br>
- if (Sym->isFunction()) {<br>
- Sym->setOutputIndex(<wbr>ImportedFunctions.size());<br>
- ImportedFunctions.push_back(<wbr>Sym);<br>
- } else {<br>
- Sym->setOutputIndex(<wbr>ImportedGlobals.size());<br>
- ImportedGlobals.push_back(Sym)<wbr>;<br>
+ if (auto *F = dyn_cast<FunctionSymbol>(Sym)) {<br>
+ F->setOutputIndex(<wbr>ImportedFunctions.size());<br>
+ ImportedFunctions.push_back(F)<wbr>;<br>
+ } else if (auto *G = dyn_cast<GlobalSymbol>(Sym)) {<br>
+ G->setOutputIndex(<wbr>ImportedGlobals.size());<br>
+ ImportedGlobals.push_back(G);<br>
}<br>
}<br>
}<br>
@@ -712,7 +712,7 @@ void Writer::calculateTypes() {<br>
File->TypeMap[I] = registerType(Types[I]);<br>
}<br>
<br>
- for (const Symbol *Sym : ImportedFunctions)<br>
+ for (const FunctionSymbol *Sym : ImportedFunctions)<br>
registerType(Sym-><wbr>getFunctionType());<br>
<br>
for (const InputFunction *F : DefinedFunctions)<br>
@@ -723,7 +723,7 @@ void Writer::assignIndexes() {<br>
uint32_t GlobalIndex = ImportedGlobals.size() + DefinedGlobals.size();<br>
uint32_t FunctionIndex = ImportedFunctions.size() + DefinedFunctions.size();<br>
<br>
- auto AddDefinedGlobal = [&](Symbol* Sym) {<br>
+ auto AddDefinedGlobal = [&](DefinedGlobal *Sym) {<br>
if (Sym) {<br>
DefinedGlobals.emplace_back(<wbr>Sym);<br>
Sym->setOutputIndex(<wbr>GlobalIndex++);<br>
@@ -743,12 +743,10 @@ void Writer::assignIndexes() {<br>
DEBUG(dbgs() << "Globals: " << File->getName() << "\n");<br>
for (Symbol *Sym : File->getSymbols()) {<br>
// Create wasm globals for data symbols defined in this file<br>
- if (!Sym->isDefined() || File != Sym->getFile())<br>
+ if (File != Sym->getFile())<br>
continue;<br>
- if (Sym->isFunction())<br>
- continue;<br>
-<br>
- AddDefinedGlobal(Sym);<br>
+ if (auto *G = dyn_cast<DefinedGlobal>(Sym))<br>
+ AddDefinedGlobal(G);<br>
}<br>
}<br>
}<br>
@@ -772,7 +770,7 @@ void Writer::assignIndexes() {<br>
for (const WasmRelocation& Reloc : Chunk->getRelocations()) {<br>
if (Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_I32 ||<br>
Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_<wbr>SLEB) {<br>
- Symbol *Sym = File->getFunctionSymbol(Reloc.<wbr>Index);<br>
+ FunctionSymbol *Sym = File->getFunctionSymbol(Reloc.<wbr>Index);<br>
if (Sym->hasTableIndex() || !Sym->hasOutputIndex())<br>
continue;<br>
Sym->setTableIndex(TableIndex+<wbr>+);<br>
<br>
<br>
______________________________<wbr>_________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div></div>