54 changes: 47 additions & 7 deletions llvm/lib/AsmParser/LLLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ lltok::Kind LLLexer::LexToken() {
return LexToken();
case '+': return LexPositive();
case '@': return LexAt();
case '$': return LexDollar();
case '%': return LexPercent();
case '"': return LexQuote();
case '.':
Expand All @@ -222,13 +223,6 @@ lltok::Kind LLLexer::LexToken() {
return lltok::dotdotdot;
}
return lltok::Error;
case '$':
if (const char *Ptr = isLabelTail(CurPtr)) {
CurPtr = Ptr;
StrVal.assign(TokStart, CurPtr-1);
return lltok::LabelStr;
}
return lltok::Error;
case ';':
SkipLineComment();
return LexToken();
Expand Down Expand Up @@ -307,6 +301,43 @@ lltok::Kind LLLexer::LexAt() {
return lltok::Error;
}

lltok::Kind LLLexer::LexDollar() {
if (const char *Ptr = isLabelTail(TokStart)) {
CurPtr = Ptr;
StrVal.assign(TokStart, CurPtr - 1);
return lltok::LabelStr;
}

// Handle DollarStringConstant: $\"[^\"]*\"
if (CurPtr[0] == '"') {
++CurPtr;

while (1) {
int CurChar = getNextChar();

if (CurChar == EOF) {
Error("end of file in COMDAT variable name");
return lltok::Error;
}
if (CurChar == '"') {
StrVal.assign(TokStart + 2, CurPtr - 1);
UnEscapeLexed(StrVal);
if (StringRef(StrVal).find_first_of(0) != StringRef::npos) {
Error("Null bytes are not allowed in names");
return lltok::Error;
}
return lltok::ComdatVar;
}
}
}

// Handle ComdatVarName: $[-a-zA-Z$._][-a-zA-Z$._0-9]*
if (ReadVarName())
return lltok::ComdatVar;

return lltok::Error;
}

/// ReadString - Read a string until the closing quote.
lltok::Kind LLLexer::ReadString(lltok::Kind kind) {
const char *Start = CurPtr;
Expand Down Expand Up @@ -618,6 +649,15 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(type);
KEYWORD(opaque);

KEYWORD(comdat);

// Comdat types
KEYWORD(any);
KEYWORD(exactmatch);
KEYWORD(largest);
KEYWORD(noduplicates);
KEYWORD(samesize);

KEYWORD(eq); KEYWORD(ne); KEYWORD(slt); KEYWORD(sgt); KEYWORD(sle);
KEYWORD(sge); KEYWORD(ult); KEYWORD(ugt); KEYWORD(ule); KEYWORD(uge);
KEYWORD(oeq); KEYWORD(one); KEYWORD(olt); KEYWORD(ogt); KEYWORD(ole);
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/AsmParser/LLLexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ namespace llvm {
lltok::Kind LexDigitOrNegative();
lltok::Kind LexPositive();
lltok::Kind LexAt();
lltok::Kind LexDollar();
lltok::Kind LexExclaim();
lltok::Kind LexPercent();
lltok::Kind LexQuote();
Expand Down
98 changes: 97 additions & 1 deletion llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ bool LLParser::ValidateEndOfModule() {
return Error(I->second.second,
"use of undefined type named '" + I->getKey() + "'");

if (!ForwardRefComdats.empty())
return Error(ForwardRefComdats.begin()->second,
"use of undefined comdat '$" +
ForwardRefComdats.begin()->first + "'");

if (!ForwardRefVals.empty())
return Error(ForwardRefVals.begin()->second.second,
"use of undefined value '@" + ForwardRefVals.begin()->first +
Expand Down Expand Up @@ -238,6 +243,7 @@ bool LLParser::ParseTopLevelEntities() {
case lltok::LocalVar: if (ParseNamedType()) return true; break;
case lltok::GlobalID: if (ParseUnnamedGlobal()) return true; break;
case lltok::GlobalVar: if (ParseNamedGlobal()) return true; break;
case lltok::ComdatVar: if (parseComdat()) return true; break;
case lltok::exclaim: if (ParseStandaloneMetadata()) return true; break;
case lltok::MetadataVar:if (ParseNamedMetadata()) return true; break;

Expand Down Expand Up @@ -513,6 +519,56 @@ bool LLParser::ParseNamedGlobal() {
UnnamedAddr);
}

bool LLParser::parseComdat() {
assert(Lex.getKind() == lltok::ComdatVar);
std::string Name = Lex.getStrVal();
LocTy NameLoc = Lex.getLoc();
Lex.Lex();

if (ParseToken(lltok::equal, "expected '=' here"))
return true;

if (ParseToken(lltok::kw_comdat, "expected comdat keyword"))
return TokError("expected comdat type");

Comdat::SelectionKind SK;
switch (Lex.getKind()) {
default:
return TokError("unknown selection kind");
case lltok::kw_any:
SK = Comdat::Any;
break;
case lltok::kw_exactmatch:
SK = Comdat::ExactMatch;
break;
case lltok::kw_largest:
SK = Comdat::Largest;
break;
case lltok::kw_noduplicates:
SK = Comdat::NoDuplicates;
break;
case lltok::kw_samesize:
SK = Comdat::SameSize;
break;
}
Lex.Lex();

// See if the comdat was forward referenced, if so, use the comdat.
Module::ComdatSymTabType &ComdatSymTab = M->getComdatSymbolTable();
Module::ComdatSymTabType::iterator I = ComdatSymTab.find(Name);
if (I != ComdatSymTab.end() && !ForwardRefComdats.erase(Name))
return Error(NameLoc, "redefinition of comdat '$" + Name + "'");

Comdat *C;
if (I != ComdatSymTab.end())
C = &I->second;
else
C = M->getOrInsertComdat(Name);
C->setSelectionKind(SK);

return false;
}

// MDString:
// ::= '!' STRINGCONSTANT
bool LLParser::ParseMDString(MDString *&Result) {
Expand Down Expand Up @@ -838,7 +894,13 @@ bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc,
if (ParseOptionalAlignment(Alignment)) return true;
GV->setAlignment(Alignment);
} else {
TokError("unknown global variable property!");
Comdat *C;
if (parseOptionalComdat(C))
return true;
if (C)
GV->setComdat(C);
else
return TokError("unknown global variable property!");
}
}

Expand Down Expand Up @@ -1096,6 +1158,24 @@ GlobalValue *LLParser::GetGlobalVal(unsigned ID, Type *Ty, LocTy Loc) {
}


//===----------------------------------------------------------------------===//
// Comdat Reference/Resolution Routines.
//===----------------------------------------------------------------------===//

Comdat *LLParser::getComdat(const std::string &Name, LocTy Loc) {
// Look this name up in the comdat symbol table.
Module::ComdatSymTabType &ComdatSymTab = M->getComdatSymbolTable();
Module::ComdatSymTabType::iterator I = ComdatSymTab.find(Name);
if (I != ComdatSymTab.end())
return &I->second;

// Otherwise, create a new forward reference for this value and remember it.
Comdat *C = M->getOrInsertComdat(Name);
ForwardRefComdats[Name] = Loc;
return C;
}


//===----------------------------------------------------------------------===//
// Helper Routines.
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -2790,6 +2870,19 @@ bool LLParser::ParseGlobalTypeAndValue(Constant *&V) {
ParseGlobalValue(Ty, V);
}

bool LLParser::parseOptionalComdat(Comdat *&C) {
C = nullptr;
if (!EatIfPresent(lltok::kw_comdat))
return false;
if (Lex.getKind() != lltok::ComdatVar)
return TokError("expected comdat variable");
LocTy Loc = Lex.getLoc();
StringRef Name = Lex.getStrVal();
C = getComdat(Name, Loc);
Lex.Lex();
return false;
}

/// ParseGlobalValueVector
/// ::= /*empty*/
/// ::= TypeAndValue (',' TypeAndValue)*
Expand Down Expand Up @@ -3090,6 +3183,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
bool UnnamedAddr;
LocTy UnnamedAddrLoc;
Constant *Prefix = nullptr;
Comdat *C;

if (ParseArgumentList(ArgList, isVarArg) ||
ParseOptionalToken(lltok::kw_unnamed_addr, UnnamedAddr,
Expand All @@ -3098,6 +3192,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
BuiltinLoc) ||
(EatIfPresent(lltok::kw_section) &&
ParseStringConstant(Section)) ||
parseOptionalComdat(C) ||
ParseOptionalAlignment(Alignment) ||
(EatIfPresent(lltok::kw_gc) &&
ParseStringConstant(GC)) ||
Expand Down Expand Up @@ -3200,6 +3295,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
Fn->setUnnamedAddr(UnnamedAddr);
Fn->setAlignment(Alignment);
Fn->setSection(Section);
Fn->setComdat(C);
if (!GC.empty()) Fn->setGC(GC.c_str());
Fn->setPrefixData(Prefix);
ForwardRefAttrGroups[Fn] = FwdRefAttrGrps;
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/AsmParser/LLParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ namespace llvm {
class Instruction;
class Constant;
class GlobalValue;
class Comdat;
class MDString;
class MDNode;
class StructType;
Expand Down Expand Up @@ -122,6 +123,9 @@ namespace llvm {
std::map<unsigned, std::pair<GlobalValue*, LocTy> > ForwardRefValIDs;
std::vector<GlobalValue*> NumberedVals;

// Comdat forward reference information.
std::map<std::string, LocTy> ForwardRefComdats;

// References to blockaddress. The key is the function ValID, the value is
// a list of references to blocks in that function.
std::map<ValID, std::vector<std::pair<ValID, GlobalValue*> > >
Expand Down Expand Up @@ -154,6 +158,10 @@ namespace llvm {
GlobalValue *GetGlobalVal(const std::string &N, Type *Ty, LocTy Loc);
GlobalValue *GetGlobalVal(unsigned ID, Type *Ty, LocTy Loc);

/// Get a Comdat with the specified name, creating a forward reference
/// record if needed.
Comdat *getComdat(const std::string &N, LocTy Loc);

// Helper Routines.
bool ParseToken(lltok::Kind T, const char *ErrMsg);
bool EatIfPresent(lltok::Kind T) {
Expand Down Expand Up @@ -247,6 +255,7 @@ namespace llvm {
bool ParseAlias(const std::string &Name, LocTy Loc, unsigned Visibility,
unsigned DLLStorageClass,
GlobalVariable::ThreadLocalMode TLM, bool UnnamedAddr);
bool parseComdat();
bool ParseStandaloneMetadata();
bool ParseNamedMetadata();
bool ParseMDString(MDString *&Result);
Expand Down Expand Up @@ -358,6 +367,7 @@ namespace llvm {
bool ParseGlobalValue(Type *Ty, Constant *&V);
bool ParseGlobalTypeAndValue(Constant *&V);
bool ParseGlobalValueVector(SmallVectorImpl<Constant*> &Elts);
bool parseOptionalComdat(Comdat *&C);
bool ParseMetadataListValue(ValID &ID, PerFunctionState *PFS);
bool ParseMetadataValue(ValID &ID, PerFunctionState *PFS);
bool ParseMDNodeVector(SmallVectorImpl<Value*> &, PerFunctionState *PFS);
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/AsmParser/LLToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@ namespace lltok {
kw_type,
kw_opaque,

kw_comdat,

// Comdat types
kw_any,
kw_exactmatch,
kw_largest,
kw_noduplicates,
kw_samesize,

kw_eq, kw_ne, kw_slt, kw_sgt, kw_sle, kw_sge, kw_ult, kw_ugt, kw_ule,
kw_uge, kw_oeq, kw_one, kw_olt, kw_ogt, kw_ole, kw_oge, kw_ord, kw_uno,
kw_ueq, kw_une,
Expand Down Expand Up @@ -180,6 +189,7 @@ namespace lltok {
// String valued tokens (StrVal).
LabelStr, // foo:
GlobalVar, // @foo @"foo"
ComdatVar, // $foo
LocalVar, // %foo %"foo"
MetadataVar, // !foo
StringConstant, // "foo"
Expand Down
43 changes: 43 additions & 0 deletions llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ void BitcodeReader::FreeState() {
std::vector<Type*>().swap(TypeList);
ValueList.clear();
MDValueList.clear();
std::vector<Comdat *>().swap(ComdatList);

std::vector<AttributeSet>().swap(MAttributes);
std::vector<BasicBlock*>().swap(FunctionBBs);
Expand Down Expand Up @@ -203,6 +204,22 @@ static SynchronizationScope GetDecodedSynchScope(unsigned Val) {
}
}

static Comdat::SelectionKind getDecodedComdatSelectionKind(unsigned Val) {
switch (Val) {
default: // Map unknown selection kinds to any.
case bitc::COMDAT_SELECTION_KIND_ANY:
return Comdat::Any;
case bitc::COMDAT_SELECTION_KIND_EXACT_MATCH:
return Comdat::ExactMatch;
case bitc::COMDAT_SELECTION_KIND_LARGEST:
return Comdat::Largest;
case bitc::COMDAT_SELECTION_KIND_NO_DUPLICATES:
return Comdat::NoDuplicates;
case bitc::COMDAT_SELECTION_KIND_SAME_SIZE:
return Comdat::SameSize;
}
}

static void UpgradeDLLImportExportLinkage(llvm::GlobalValue *GV, unsigned Val) {
switch (Val) {
case 5: GV->setDLLStorageClass(GlobalValue::DLLImportStorageClass); break;
Expand Down Expand Up @@ -1838,6 +1855,20 @@ std::error_code BitcodeReader::ParseModule(bool Resume) {
GCTable.push_back(S);
break;
}
case bitc::MODULE_CODE_COMDAT: { // COMDAT: [selection_kind, name]
if (Record.size() < 2)
return Error(InvalidRecord);
Comdat::SelectionKind SK = getDecodedComdatSelectionKind(Record[0]);
unsigned ComdatNameSize = Record[1];
std::string ComdatName;
ComdatName.reserve(ComdatNameSize);
for (unsigned i = 0; i != ComdatNameSize; ++i)
ComdatName += (char)Record[2 + i];
Comdat *C = TheModule->getOrInsertComdat(ComdatName);
C->setSelectionKind(SK);
ComdatList.push_back(C);
break;
}
// GLOBALVAR: [pointer type, isconst, initid,
// linkage, alignment, section, visibility, threadlocal,
// unnamed_addr, dllstorageclass]
Expand Down Expand Up @@ -1898,6 +1929,12 @@ std::error_code BitcodeReader::ParseModule(bool Resume) {
// Remember which value to use for the global initializer.
if (unsigned InitID = Record[2])
GlobalInits.push_back(std::make_pair(NewGV, InitID-1));

if (Record.size() > 11)
if (unsigned ComdatID = Record[11]) {
assert(ComdatID <= ComdatList.size());
NewGV->setComdat(ComdatList[ComdatID - 1]);
}
break;
}
// FUNCTION: [type, callingconv, isproto, linkage, paramattr,
Expand Down Expand Up @@ -1951,6 +1988,12 @@ std::error_code BitcodeReader::ParseModule(bool Resume) {
else
UpgradeDLLImportExportLinkage(Func, Record[3]);

if (Record.size() > 12)
if (unsigned ComdatID = Record[12]) {
assert(ComdatID <= ComdatList.size());
Func->setComdat(ComdatList[ComdatID - 1]);
}

ValueList.push_back(Func);

// If this is a function with a body, remember the prototype we are
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Bitcode/Reader/BitcodeReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <vector>

namespace llvm {
class Comdat;
class MemoryBuffer;
class LLVMContext;

Expand Down Expand Up @@ -135,6 +136,7 @@ class BitcodeReader : public GVMaterializer {
std::vector<Type*> TypeList;
BitcodeReaderValueList ValueList;
BitcodeReaderMDValueList MDValueList;
std::vector<Comdat *> ComdatList;
SmallVector<Instruction *, 64> InstructionList;
SmallVector<SmallVector<uint64_t, 64>, 64> UseListRecords;

Expand Down
36 changes: 35 additions & 1 deletion llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,35 @@ static unsigned getEncodedThreadLocalMode(const GlobalValue &GV) {
llvm_unreachable("Invalid TLS model");
}

static unsigned getEncodedComdatSelectionKind(const Comdat &C) {
switch (C.getSelectionKind()) {
case Comdat::Any:
return bitc::COMDAT_SELECTION_KIND_ANY;
case Comdat::ExactMatch:
return bitc::COMDAT_SELECTION_KIND_EXACT_MATCH;
case Comdat::Largest:
return bitc::COMDAT_SELECTION_KIND_LARGEST;
case Comdat::NoDuplicates:
return bitc::COMDAT_SELECTION_KIND_NO_DUPLICATES;
case Comdat::SameSize:
return bitc::COMDAT_SELECTION_KIND_SAME_SIZE;
}
llvm_unreachable("Invalid selection kind");
}

static void writeComdats(const ValueEnumerator &VE, BitstreamWriter &Stream) {
SmallVector<uint8_t, 64> Vals;
for (const Comdat *C : VE.getComdats()) {
// COMDAT: [selection_kind, name]
Vals.push_back(getEncodedComdatSelectionKind(*C));
Vals.push_back(C->getName().size());
for (char Chr : C->getName())
Vals.push_back((unsigned char)Chr);
Stream.EmitRecord(bitc::MODULE_CODE_COMDAT, Vals, /*AbbrevToUse=*/0);
Vals.clear();
}
}

// Emit top-level description of module, including target triple, inline asm,
// descriptors for global variables, and function prototype info.
static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
Expand Down Expand Up @@ -625,12 +654,14 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
if (GV.isThreadLocal() ||
GV.getVisibility() != GlobalValue::DefaultVisibility ||
GV.hasUnnamedAddr() || GV.isExternallyInitialized() ||
GV.getDLLStorageClass() != GlobalValue::DefaultStorageClass) {
GV.getDLLStorageClass() != GlobalValue::DefaultStorageClass ||
GV.hasComdat()) {
Vals.push_back(getEncodedVisibility(GV));
Vals.push_back(getEncodedThreadLocalMode(GV));
Vals.push_back(GV.hasUnnamedAddr());
Vals.push_back(GV.isExternallyInitialized());
Vals.push_back(getEncodedDLLStorageClass(GV));
Vals.push_back(GV.hasComdat() ? VE.getComdatID(GV.getComdat()) : 0);
} else {
AbbrevToUse = SimpleGVarAbbrev;
}
Expand All @@ -656,6 +687,7 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
Vals.push_back(F.hasPrefixData() ? (VE.getValueID(F.getPrefixData()) + 1)
: 0);
Vals.push_back(getEncodedDLLStorageClass(F));
Vals.push_back(F.hasComdat() ? VE.getComdatID(F.getComdat()) : 0);

unsigned AbbrevToUse = 0;
Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse);
Expand Down Expand Up @@ -1915,6 +1947,8 @@ static void WriteModule(const Module *M, BitstreamWriter &Stream) {
// Emit information describing all of the types in the module.
WriteTypeTable(VE, Stream);

writeComdats(VE, Stream);

// Emit top-level description of module, including target triple, inline asm,
// descriptors for global variables, and function prototype info.
WriteModuleInfo(M, VE, Stream);
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ unsigned ValueEnumerator::getInstructionID(const Instruction *Inst) const {
return I->second;
}

unsigned ValueEnumerator::getComdatID(const Comdat *C) const {
unsigned ComdatID = Comdats.idFor(C);
assert(ComdatID && "Comdat not found!");
return ComdatID;
}

void ValueEnumerator::setInstructionID(const Instruction *I) {
InstructionMap[I] = InstructionCount++;
}
Expand Down Expand Up @@ -307,6 +313,10 @@ void ValueEnumerator::EnumerateValue(const Value *V) {
return;
}

if (auto *GO = dyn_cast<GlobalObject>(V))
if (const Comdat *C = GO->getComdat())
Comdats.insert(C);

// Enumerate the type of this value.
EnumerateType(V->getType());

Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/Bitcode/Writer/ValueEnumerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/UniqueVector.h"
#include "llvm/IR/Attributes.h"
#include <vector>

Expand All @@ -25,6 +26,7 @@ class Type;
class Value;
class Instruction;
class BasicBlock;
class Comdat;
class Function;
class Module;
class MDNode;
Expand All @@ -48,6 +50,10 @@ class ValueEnumerator {
typedef DenseMap<const Value*, unsigned> ValueMapType;
ValueMapType ValueMap;
ValueList Values;

typedef UniqueVector<const Comdat *> ComdatSetType;
ComdatSetType Comdats;

ValueList MDValues;
SmallVector<const MDNode *, 8> FunctionLocalMDs;
ValueMapType MDValueMap;
Expand Down Expand Up @@ -139,6 +145,9 @@ class ValueEnumerator {
return AttributeGroups;
}

const ComdatSetType &getComdats() const { return Comdats; }
unsigned getComdatID(const Comdat *C) const;

/// getGlobalBasicBlockID - This returns the function-specific ID for the
/// specified basic block. This is relatively expensive information, so it
/// should only be used by rare constructs such as address-of-label.
Expand Down
133 changes: 115 additions & 18 deletions llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,18 @@ getELFSectionFlags(SectionKind K) {
return Flags;
}

static const Comdat *getELFComdat(const GlobalValue *GV) {
const Comdat *C = GV->getComdat();
if (!C)
return nullptr;

if (C->getSelectionKind() != Comdat::Any)
report_fatal_error("ELF COMDATs only support SelectionKind::Any, '" +
C->getName() + "' cannot be lowered.");

return C;
}

const MCSection *TargetLoweringObjectFileELF::getExplicitSectionGlobal(
const GlobalValue *GV, SectionKind Kind, Mangler &Mang,
const TargetMachine &TM) const {
Expand All @@ -200,9 +212,15 @@ const MCSection *TargetLoweringObjectFileELF::getExplicitSectionGlobal(
// Infer section flags from the section name if we can.
Kind = getELFKindForNamedSection(SectionName, Kind);

StringRef Group = "";
unsigned Flags = getELFSectionFlags(Kind);
if (const Comdat *C = getELFComdat(GV)) {
Group = C->getName();
Flags |= ELF::SHF_GROUP;
}
return getContext().getELFSection(SectionName,
getELFSectionType(SectionName, Kind),
getELFSectionFlags(Kind), Kind);
getELFSectionType(SectionName, Kind), Flags,
Kind, /*EntrySize=*/0, Group);
}

/// getSectionPrefixForGlobal - Return the section prefix name used by options
Expand All @@ -224,7 +242,6 @@ static StringRef getSectionPrefixForGlobal(SectionKind Kind) {
return ".data.rel.ro.";
}


const MCSection *TargetLoweringObjectFileELF::
SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
Mangler &Mang, const TargetMachine &TM) const {
Expand All @@ -238,7 +255,7 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,

// If this global is linkonce/weak and the target handles this by emitting it
// into a 'uniqued' section name, create and return the section now.
if ((GV->isWeakForLinker() || EmitUniquedSection) &&
if ((GV->isWeakForLinker() || EmitUniquedSection || GV->hasComdat()) &&
!Kind.isCommon()) {
StringRef Prefix = getSectionPrefixForGlobal(Kind);

Expand All @@ -247,8 +264,11 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,

StringRef Group = "";
unsigned Flags = getELFSectionFlags(Kind);
if (GV->isWeakForLinker()) {
Group = Name.substr(Prefix.size());
if (GV->isWeakForLinker() || GV->hasComdat()) {
if (const Comdat *C = getELFComdat(GV))
Group = C->getName();
else
Group = Name.substr(Prefix.size());
Flags |= ELF::SHF_GROUP;
}

Expand Down Expand Up @@ -482,13 +502,25 @@ emitModuleFlags(MCStreamer &Streamer,
Streamer.AddBlankLine();
}

static void checkMachOComdat(const GlobalValue *GV) {
const Comdat *C = GV->getComdat();
if (!C)
return;

report_fatal_error("MachO doesn't support COMDATs, '" + C->getName() +
"' cannot be lowered.");
}

const MCSection *TargetLoweringObjectFileMachO::getExplicitSectionGlobal(
const GlobalValue *GV, SectionKind Kind, Mangler &Mang,
const TargetMachine &TM) const {
// Parse the section specifier and create it if valid.
StringRef Segment, Section;
unsigned TAA = 0, StubSize = 0;
bool TAAParsed;

checkMachOComdat(GV);

std::string ErrorCode =
MCSectionMachO::ParseSectionSpecifier(GV->getSection(), Segment, Section,
TAA, TAAParsed, StubSize);
Expand Down Expand Up @@ -559,6 +591,7 @@ bool TargetLoweringObjectFileMachO::isSectionAtomizableBySymbols(
const MCSection *TargetLoweringObjectFileMachO::
SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
Mangler &Mang, const TargetMachine &TM) const {
checkMachOComdat(GV);

// Handle thread local data.
if (Kind.isThreadBSS()) return TLSBSSSection;
Expand Down Expand Up @@ -727,18 +760,72 @@ getCOFFSectionFlags(SectionKind K) {
return Flags;
}

const GlobalValue *getComdatGVForCOFF(const GlobalValue *GV) {
const Comdat *C = GV->getComdat();
assert(C && "expected GV to have a Comdat!");

StringRef ComdatGVName = C->getName();
const GlobalValue *ComdatGV = GV->getParent()->getNamedValue(ComdatGVName);
if (!ComdatGV)
report_fatal_error("Associative COMDAT symbol '" + ComdatGVName +
"' does not exist.");

if (ComdatGV->getComdat() != C)
report_fatal_error("Associative COMDAT symbol '" + ComdatGVName +
"' is not a key for it's COMDAT.");

return ComdatGV;
}

static int getSelectionForCOFF(const GlobalValue *GV) {
if (const Comdat *C = GV->getComdat()) {
const GlobalValue *ComdatKey = getComdatGVForCOFF(GV);
if (const auto *GA = dyn_cast<GlobalAlias>(ComdatKey))
ComdatKey = GA->getBaseObject();
if (ComdatKey == GV) {
switch (C->getSelectionKind()) {
case Comdat::Any:
return COFF::IMAGE_COMDAT_SELECT_ANY;
case Comdat::ExactMatch:
return COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH;
case Comdat::Largest:
return COFF::IMAGE_COMDAT_SELECT_LARGEST;
case Comdat::NoDuplicates:
return COFF::IMAGE_COMDAT_SELECT_NODUPLICATES;
case Comdat::SameSize:
return COFF::IMAGE_COMDAT_SELECT_SAME_SIZE;
}
} else {
return COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE;
}
} else if (GV->isWeakForLinker()) {
return COFF::IMAGE_COMDAT_SELECT_ANY;
}
return 0;
}

const MCSection *TargetLoweringObjectFileCOFF::getExplicitSectionGlobal(
const GlobalValue *GV, SectionKind Kind, Mangler &Mang,
const TargetMachine &TM) const {
int Selection = 0;
unsigned Characteristics = getCOFFSectionFlags(Kind);
StringRef Name = GV->getSection();
StringRef COMDATSymName = "";
if (GV->isWeakForLinker()) {
Selection = COFF::IMAGE_COMDAT_SELECT_ANY;
Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT;
MCSymbol *Sym = TM.getSymbol(GV, Mang);
COMDATSymName = Sym->getName();
if ((GV->isWeakForLinker() || GV->hasComdat()) && !Kind.isCommon()) {
Selection = getSelectionForCOFF(GV);
const GlobalValue *ComdatGV;
if (Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
ComdatGV = getComdatGVForCOFF(GV);
else
ComdatGV = GV;

if (!ComdatGV->hasPrivateLinkage()) {
MCSymbol *Sym = TM.getSymbol(ComdatGV, Mang);
COMDATSymName = Sym->getName();
Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT;
} else {
Selection = 0;
}
}
return getContext().getCOFFSection(Name,
Characteristics,
Expand Down Expand Up @@ -775,17 +862,27 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
// into a 'uniqued' section name, create and return the section now.
// Section names depend on the name of the symbol which is not feasible if the
// symbol has private linkage.
if ((GV->isWeakForLinker() || EmitUniquedSection) &&
!GV->hasPrivateLinkage() && !Kind.isCommon()) {
if ((GV->isWeakForLinker() || EmitUniquedSection || GV->hasComdat()) &&
!Kind.isCommon()) {
const char *Name = getCOFFSectionNameForUniqueGlobal(Kind);
unsigned Characteristics = getCOFFSectionFlags(Kind);

Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT;
MCSymbol *Sym = TM.getSymbol(GV, Mang);
return getContext().getCOFFSection(
Name, Characteristics, Kind, Sym->getName(),
GV->isWeakForLinker() ? COFF::IMAGE_COMDAT_SELECT_ANY
: COFF::IMAGE_COMDAT_SELECT_NODUPLICATES);
int Selection = getSelectionForCOFF(GV);
if (!Selection)
Selection = COFF::IMAGE_COMDAT_SELECT_NODUPLICATES;
const GlobalValue *ComdatGV;
if (GV->hasComdat())
ComdatGV = getComdatGVForCOFF(GV);
else
ComdatGV = GV;

if (!ComdatGV->hasPrivateLinkage()) {
MCSymbol *Sym = TM.getSymbol(ComdatGV, Mang);
StringRef COMDATSymName = Sym->getName();
return getContext().getCOFFSection(Name, Characteristics, Kind,
COMDATSymName, Selection);
}
}

if (Kind.isText())
Expand Down
67 changes: 65 additions & 2 deletions llvm/lib/IR/AsmWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ static void PrintEscapedString(StringRef Name, raw_ostream &Out) {

enum PrefixType {
GlobalPrefix,
ComdatPrefix,
LabelPrefix,
LocalPrefix,
NoPrefix
Expand All @@ -119,6 +120,7 @@ static void PrintLLVMName(raw_ostream &OS, StringRef Name, PrefixType Prefix) {
switch (Prefix) {
case NoPrefix: break;
case GlobalPrefix: OS << '@'; break;
case ComdatPrefix: OS << '$'; break;
case LabelPrefix: break;
case LocalPrefix: OS << '%'; break;
}
Expand Down Expand Up @@ -1165,8 +1167,15 @@ static void WriteAsOperandInternal(raw_ostream &Out, const Value *V,
}

void AssemblyWriter::init() {
if (TheModule)
TypePrinter.incorporateTypes(*TheModule);
if (!TheModule)
return;
TypePrinter.incorporateTypes(*TheModule);
for (const Function &F : *TheModule)
if (const Comdat *C = F.getComdat())
Comdats.insert(C);
for (const GlobalVariable &GV : TheModule->globals())
if (const Comdat *C = GV.getComdat())
Comdats.insert(C);
}


Expand Down Expand Up @@ -1308,6 +1317,15 @@ void AssemblyWriter::printModule(const Module *M) {

printTypeIdentities();

// Output all comdats.
if (!Comdats.empty())
Out << '\n';
for (const Comdat *C : Comdats) {
printComdat(C);
if (C != Comdats.back())
Out << '\n';
}

// Output all globals.
if (!M->global_empty()) Out << '\n';
for (Module::const_global_iterator I = M->global_begin(), E = M->global_end();
Expand Down Expand Up @@ -1470,6 +1488,10 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) {
PrintEscapedString(GV->getSection(), Out);
Out << '"';
}
if (GV->hasComdat()) {
Out << ", comdat ";
PrintLLVMName(Out, GV->getComdat()->getName(), ComdatPrefix);
}
if (GV->getAlignment())
Out << ", align " << GV->getAlignment();

Expand Down Expand Up @@ -1506,10 +1528,19 @@ void AssemblyWriter::printAlias(const GlobalAlias *GA) {
writeOperand(Aliasee, !isa<ConstantExpr>(Aliasee));
}

if (GA->hasComdat()) {
Out << ", comdat ";
PrintLLVMName(Out, GA->getComdat()->getName(), ComdatPrefix);
}

printInfoComment(*GA);
Out << '\n';
}

void AssemblyWriter::printComdat(const Comdat *C) {
C->print(Out);
}

void AssemblyWriter::printTypeIdentities() {
if (TypePrinter.NumberedTypes.empty() &&
TypePrinter.NamedTypes.empty())
Expand Down Expand Up @@ -1647,6 +1678,10 @@ void AssemblyWriter::printFunction(const Function *F) {
PrintEscapedString(F->getSection(), Out);
Out << '"';
}
if (F->hasComdat()) {
Out << " comdat ";
PrintLLVMName(Out, F->getComdat()->getName(), ComdatPrefix);
}
if (F->getAlignment())
Out << " align " << F->getAlignment();
if (F->hasGC())
Expand Down Expand Up @@ -2158,6 +2193,31 @@ void NamedMDNode::print(raw_ostream &ROS) const {
W.printNamedMDNode(this);
}

void Comdat::print(raw_ostream &ROS) const {
PrintLLVMName(ROS, getName(), ComdatPrefix);
ROS << " = comdat ";

switch (getSelectionKind()) {
case Comdat::Any:
ROS << "any";
break;
case Comdat::ExactMatch:
ROS << "exactmatch";
break;
case Comdat::Largest:
ROS << "largest";
break;
case Comdat::NoDuplicates:
ROS << "noduplicates";
break;
case Comdat::SameSize:
ROS << "samesize";
break;
}

ROS << '\n';
}

void Type::print(raw_ostream &OS) const {
TypePrinting TP;
TP.print(const_cast<Type*>(this), OS);
Expand Down Expand Up @@ -2241,5 +2301,8 @@ void Type::dump() const { print(dbgs()); }
// Module::dump() - Allow printing of Modules from the debugger.
void Module::dump() const { print(dbgs(), nullptr); }

// \brief Allow printing of Comdats from the debugger.
void Comdat::dump() const { print(dbgs()); }

// NamedMDNode::dump() - Allow printing of NamedMDNodes from the debugger.
void NamedMDNode::dump() const { print(dbgs()); }
4 changes: 4 additions & 0 deletions llvm/lib/IR/AsmWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define LLVM_IR_ASSEMBLYWRITER_H

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/TypeFinder.h"
Expand All @@ -26,6 +27,7 @@ namespace llvm {
class BasicBlock;
class Function;
class GlobalValue;
class Comdat;
class Module;
class NamedMDNode;
class Value;
Expand Down Expand Up @@ -70,6 +72,7 @@ class AssemblyWriter {
SlotTracker &Machine;
TypePrinting TypePrinter;
AssemblyAnnotationWriter *AnnotationWriter;
SetVector<const Comdat *> Comdats;

public:
/// Construct an AssemblyWriter with an external SlotTracker
Expand Down Expand Up @@ -101,6 +104,7 @@ class AssemblyWriter {
void printTypeIdentities();
void printGlobal(const GlobalVariable *GV);
void printAlias(const GlobalAlias *GV);
void printComdat(const Comdat *C);
void printFunction(const Function *F);
void printArgument(const Argument *FA, AttributeSet Attrs, unsigned Idx);
void printBasicBlock(const BasicBlock *BB);
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ add_llvm_library(LLVMCore
Attributes.cpp
AutoUpgrade.cpp
BasicBlock.cpp
Comdat.cpp
ConstantFold.cpp
ConstantRange.cpp
Constants.cpp
Expand Down
25 changes: 25 additions & 0 deletions llvm/lib/IR/Comdat.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===-- Comdat.cpp - Implement Metadata classes --------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Comdat class.
//
//===----------------------------------------------------------------------===//

#include "llvm/IR/Comdat.h"
#include "llvm/ADT/StringMap.h"
using namespace llvm;

Comdat::Comdat(SelectionKind SK, StringMapEntry<Comdat> *Name)
: Name(Name), SK(SK) {}

Comdat::Comdat(Comdat &&C) : Name(C.Name), SK(C.SK) {}

Comdat::Comdat() : Name(nullptr), SK(Comdat::Any) {}

StringRef Comdat::getName() const { return Name->first(); }
19 changes: 12 additions & 7 deletions llvm/lib/IR/Globals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,10 @@ void GlobalValue::copyAttributesFrom(const GlobalValue *Src) {
setDLLStorageClass(Src->getDLLStorageClass());
}

static const GlobalObject *getBaseObject(const Constant &C) {
// FIXME: We should probably return a base + offset pair for non-zero GEPs.
return dyn_cast<GlobalObject>(C.stripPointerCasts());
}

unsigned GlobalValue::getAlignment() const {
if (auto *GA = dyn_cast<GlobalAlias>(this)) {
// In general we cannot compute this at the IR level, but we try.
if (const GlobalObject *GO = getBaseObject(*GA->getAliasee()))
if (const GlobalObject *GO = GA->getBaseObject())
return GO->getAlignment();

// FIXME: we should also be able to handle:
Expand Down Expand Up @@ -96,13 +91,23 @@ void GlobalObject::copyAttributesFrom(const GlobalValue *Src) {
const char *GlobalValue::getSection() const {
if (auto *GA = dyn_cast<GlobalAlias>(this)) {
// In general we cannot compute this at the IR level, but we try.
if (const GlobalObject *GO = getBaseObject(*GA->getAliasee()))
if (const GlobalObject *GO = GA->getBaseObject())
return GO->getSection();
return "";
}
return cast<GlobalObject>(this)->getSection();
}

Comdat *GlobalValue::getComdat() {
if (auto *GA = dyn_cast<GlobalAlias>(this)) {
// In general we cannot compute this at the IR level, but we try.
if (const GlobalObject *GO = GA->getBaseObject())
return const_cast<GlobalObject *>(GO)->getComdat();
return nullptr;
}
return cast<GlobalObject>(this)->getComdat();
}

void GlobalObject::setSection(StringRef S) { Section = S; }

bool GlobalValue::isDeclaration() const {
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/IR/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,3 +453,11 @@ unsigned Module::getDwarfVersion() const {
return dwarf::DWARF_VERSION;
return cast<ConstantInt>(Val)->getZExtValue();
}

Comdat *Module::getOrInsertComdat(StringRef Name) {
Comdat C;
StringMapEntry<Comdat> &Entry =
ComdatSymTab.GetOrCreateValue(Name, std::move(C));
Entry.second.Name = &Entry;
return &Entry.second;
}
33 changes: 33 additions & 0 deletions llvm/lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ struct VerifierSupport {
OS << ' ' << *T;
}

void WriteComdat(const Comdat *C) {
if (!C)
return;
OS << *C;
}

// CheckFailed - A check failed, so print out the condition and the message
// that failed. This provides a nice place to put a breakpoint if you want
// to see why something is not correct.
Expand Down Expand Up @@ -138,6 +144,12 @@ struct VerifierSupport {
WriteType(T3);
Broken = true;
}

void CheckFailed(const Twine &Message, const Comdat *C) {
OS << Message.str() << "\n";
WriteComdat(C);
Broken = true;
}
};
class Verifier : public InstVisitor<Verifier>, VerifierSupport {
friend class InstVisitor<Verifier>;
Expand Down Expand Up @@ -230,6 +242,9 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
I != E; ++I)
visitNamedMDNode(*I);

for (const StringMapEntry<Comdat> &SMEC : M.getComdatSymbolTable())
visitComdat(SMEC.getValue());

visitModuleFlags(M);
visitModuleIdents(M);

Expand All @@ -246,6 +261,7 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
const GlobalAlias &A, const Constant &C);
void visitNamedMDNode(const NamedMDNode &NMD);
void visitMDNode(MDNode &MD, Function *F);
void visitComdat(const Comdat &C);
void visitModuleIdents(const Module &M);
void visitModuleFlags(const Module &M);
void visitModuleFlag(const MDNode *Op,
Expand Down Expand Up @@ -387,6 +403,7 @@ void Verifier::visitGlobalVariable(const GlobalVariable &GV) {
"'common' global must have a zero initializer!", &GV);
Assert1(!GV.isConstant(), "'common' global may not be marked constant!",
&GV);
Assert1(!GV.hasComdat(), "'common' global may not be in a Comdat!", &GV);
}
} else {
Assert1(GV.hasExternalLinkage() || GV.hasExternalWeakLinkage(),
Expand Down Expand Up @@ -578,6 +595,22 @@ void Verifier::visitMDNode(MDNode &MD, Function *F) {
}
}

void Verifier::visitComdat(const Comdat &C) {
// All Comdat::SelectionKind values other than Comdat::Any require a
// GlobalValue with the same name as the Comdat.
const GlobalValue *GV = M->getNamedValue(C.getName());
if (C.getSelectionKind() != Comdat::Any)
Assert1(GV,
"comdat selection kind requires a global value with the same name",
&C);
// The Module is invalid if the GlobalValue has local linkage. Allowing
// otherwise opens us up to seeing the underling global value get renamed if
// collisions occur.
if (GV)
Assert1(!GV->hasLocalLinkage(), "comdat global value has local linkage",
GV);
}

void Verifier::visitModuleIdents(const Module &M) {
const NamedMDNode *Idents = M.getNamedMetadata("llvm.ident");
if (!Idents)
Expand Down
292 changes: 243 additions & 49 deletions llvm/lib/Linker/LinkModules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,18 @@ namespace {
return true;
}

bool getComdatLeader(Module *M, StringRef ComdatName,
const GlobalVariable *&GVar);
bool computeResultingSelectionKind(StringRef ComdatName,
Comdat::SelectionKind Src,
Comdat::SelectionKind Dst,
Comdat::SelectionKind &Result,
bool &LinkFromSrc);
std::map<const Comdat *, std::pair<Comdat::SelectionKind, bool>>
ComdatsChosen;
bool getComdatResult(const Comdat *SrcC, Comdat::SelectionKind &SK,
bool &LinkFromSrc);

/// getLinkageResult - This analyzes the two global values and determines
/// what the result will look like in the destination module.
bool getLinkageResult(GlobalValue *Dest, const GlobalValue *Src,
Expand Down Expand Up @@ -534,6 +546,115 @@ Value *ValueMaterializerTy::materializeValueFor(Value *V) {
return DF;
}

bool ModuleLinker::getComdatLeader(Module *M, StringRef ComdatName,
const GlobalVariable *&GVar) {
const GlobalValue *GVal = M->getNamedValue(ComdatName);
if (const auto *GA = dyn_cast_or_null<GlobalAlias>(GVal)) {
GVal = GA->getBaseObject();
if (!GVal)
// We cannot resolve the size of the aliasee yet.
return emitError("Linking COMDATs named '" + ComdatName +
"': COMDAT key involves incomputable alias size.");
}

GVar = dyn_cast_or_null<GlobalVariable>(GVal);
if (!GVar)
return emitError(
"Linking COMDATs named '" + ComdatName +
"': GlobalVariable required for data dependent selection!");

return false;
}

bool ModuleLinker::computeResultingSelectionKind(StringRef ComdatName,
Comdat::SelectionKind Src,
Comdat::SelectionKind Dst,
Comdat::SelectionKind &Result,
bool &LinkFromSrc) {
// The ability to mix Comdat::SelectionKind::Any with
// Comdat::SelectionKind::Largest is a behavior that comes from COFF.
bool DstAnyOrLargest = Dst == Comdat::SelectionKind::Any ||
Dst == Comdat::SelectionKind::Largest;
bool SrcAnyOrLargest = Src == Comdat::SelectionKind::Any ||
Src == Comdat::SelectionKind::Largest;
if (DstAnyOrLargest && SrcAnyOrLargest) {
if (Dst == Comdat::SelectionKind::Largest ||
Src == Comdat::SelectionKind::Largest)
Result = Comdat::SelectionKind::Largest;
else
Result = Comdat::SelectionKind::Any;
} else if (Src == Dst) {
Result = Dst;
} else {
return emitError("Linking COMDATs named '" + ComdatName +
"': invalid selection kinds!");
}

switch (Result) {
case Comdat::SelectionKind::Any:
// Go with Dst.
LinkFromSrc = false;
break;
case Comdat::SelectionKind::NoDuplicates:
return emitError("Linking COMDATs named '" + ComdatName +
"': noduplicates has been violated!");
case Comdat::SelectionKind::ExactMatch:
case Comdat::SelectionKind::Largest:
case Comdat::SelectionKind::SameSize: {
const GlobalVariable *DstGV;
const GlobalVariable *SrcGV;
if (getComdatLeader(DstM, ComdatName, DstGV) ||
getComdatLeader(SrcM, ComdatName, SrcGV))
return true;

const DataLayout *DstDL = DstM->getDataLayout();
const DataLayout *SrcDL = SrcM->getDataLayout();
if (!DstDL || !SrcDL) {
return emitError(
"Linking COMDATs named '" + ComdatName +
"': can't do size dependent selection without DataLayout!");
}
uint64_t DstSize =
DstDL->getTypeAllocSize(DstGV->getType()->getPointerElementType());
uint64_t SrcSize =
SrcDL->getTypeAllocSize(SrcGV->getType()->getPointerElementType());
if (Result == Comdat::SelectionKind::ExactMatch) {
if (SrcGV->getInitializer() != DstGV->getInitializer())
return emitError("Linking COMDATs named '" + ComdatName +
"': ExactMatch violated!");
LinkFromSrc = false;
} else if (Result == Comdat::SelectionKind::Largest) {
LinkFromSrc = SrcSize > DstSize;
} else if (Result == Comdat::SelectionKind::SameSize) {
if (SrcSize != DstSize)
return emitError("Linking COMDATs named '" + ComdatName +
"': SameSize violated!");
LinkFromSrc = false;
} else {
llvm_unreachable("unknown selection kind");
}
break;
}
}

return false;
}

bool ModuleLinker::getComdatResult(const Comdat *SrcC,
Comdat::SelectionKind &Result,
bool &LinkFromSrc) {
StringRef ComdatName = SrcC->getName();
Module::ComdatSymTabType &ComdatSymTab = DstM->getComdatSymbolTable();
Module::ComdatSymTabType::iterator DstCI = ComdatSymTab.find(ComdatName);
if (DstCI != ComdatSymTab.end()) {
const Comdat *DstC = &DstCI->second;
Comdat::SelectionKind SSK = SrcC->getSelectionKind();
Comdat::SelectionKind DSK = DstC->getSelectionKind();
if (computeResultingSelectionKind(ComdatName, SSK, DSK, Result, LinkFromSrc))
return true;
}
return false;
}

/// getLinkageResult - This analyzes the two global values and determines what
/// the result will look like in the destination module. In particular, it
Expand Down Expand Up @@ -764,34 +885,47 @@ bool ModuleLinker::linkGlobalProto(GlobalVariable *SGV) {
llvm::Optional<GlobalValue::VisibilityTypes> NewVisibility;
bool HasUnnamedAddr = SGV->hasUnnamedAddr();

bool LinkFromSrc = false;
Comdat *DC = nullptr;
if (const Comdat *SC = SGV->getComdat()) {
Comdat::SelectionKind SK;
std::tie(SK, LinkFromSrc) = ComdatsChosen[SC];
DC = DstM->getOrInsertComdat(SC->getName());
DC->setSelectionKind(SK);
}

if (DGV) {
// Concatenation of appending linkage variables is magic and handled later.
if (DGV->hasAppendingLinkage() || SGV->hasAppendingLinkage())
return linkAppendingVarProto(cast<GlobalVariable>(DGV), SGV);

// Determine whether linkage of these two globals follows the source
// module's definition or the destination module's definition.
GlobalValue::LinkageTypes NewLinkage = GlobalValue::InternalLinkage;
GlobalValue::VisibilityTypes NV;
bool LinkFromSrc = false;
if (getLinkageResult(DGV, SGV, NewLinkage, NV, LinkFromSrc))
return true;
NewVisibility = NV;
HasUnnamedAddr = HasUnnamedAddr && DGV->hasUnnamedAddr();
if (!DC) {
// Concatenation of appending linkage variables is magic and handled later.
if (DGV->hasAppendingLinkage() || SGV->hasAppendingLinkage())
return linkAppendingVarProto(cast<GlobalVariable>(DGV), SGV);

// Determine whether linkage of these two globals follows the source
// module's definition or the destination module's definition.
GlobalValue::LinkageTypes NewLinkage = GlobalValue::InternalLinkage;
GlobalValue::VisibilityTypes NV;
if (getLinkageResult(DGV, SGV, NewLinkage, NV, LinkFromSrc))
return true;
NewVisibility = NV;
HasUnnamedAddr = HasUnnamedAddr && DGV->hasUnnamedAddr();

// If we're not linking from the source, then keep the definition that we
// have.
if (!LinkFromSrc) {
// Special case for const propagation.
if (GlobalVariable *DGVar = dyn_cast<GlobalVariable>(DGV))
if (DGVar->isDeclaration() && SGV->isConstant() &&
!DGVar->isConstant())
DGVar->setConstant(true);

// Set calculated linkage, visibility and unnamed_addr.
DGV->setLinkage(NewLinkage);
DGV->setVisibility(*NewVisibility);
DGV->setUnnamedAddr(HasUnnamedAddr);
}
}

// If we're not linking from the source, then keep the definition that we
// have.
if (!LinkFromSrc) {
// Special case for const propagation.
if (GlobalVariable *DGVar = dyn_cast<GlobalVariable>(DGV))
if (DGVar->isDeclaration() && SGV->isConstant() && !DGVar->isConstant())
DGVar->setConstant(true);

// Set calculated linkage, visibility and unnamed_addr.
DGV->setLinkage(NewLinkage);
DGV->setVisibility(*NewVisibility);
DGV->setUnnamedAddr(HasUnnamedAddr);

// Make sure to remember this mapping.
ValueMap[SGV] = ConstantExpr::getBitCast(DGV,TypeMap.get(SGV->getType()));

Expand All @@ -803,6 +937,12 @@ bool ModuleLinker::linkGlobalProto(GlobalVariable *SGV) {
}
}

// If the Comdat this variable was inside of wasn't selected, skip it.
if (DC && !DGV && !LinkFromSrc) {
DoNotLinkFromSource.insert(SGV);
return false;
}

// No linking to be performed or linking from the source: simply create an
// identical version of the symbol over in the dest module... the
// initializer will be filled in later by LinkGlobalInits.
Expand All @@ -818,6 +958,9 @@ bool ModuleLinker::linkGlobalProto(GlobalVariable *SGV) {
NewDGV->setVisibility(*NewVisibility);
NewDGV->setUnnamedAddr(HasUnnamedAddr);

if (DC)
NewDGV->setComdat(DC);

if (DGV) {
DGV->replaceAllUsesWith(ConstantExpr::getBitCast(NewDGV, DGV->getType()));
DGV->eraseFromParent();
Expand All @@ -835,21 +978,33 @@ bool ModuleLinker::linkFunctionProto(Function *SF) {
llvm::Optional<GlobalValue::VisibilityTypes> NewVisibility;
bool HasUnnamedAddr = SF->hasUnnamedAddr();

bool LinkFromSrc = false;
Comdat *DC = nullptr;
if (const Comdat *SC = SF->getComdat()) {
Comdat::SelectionKind SK;
std::tie(SK, LinkFromSrc) = ComdatsChosen[SC];
DC = DstM->getOrInsertComdat(SC->getName());
DC->setSelectionKind(SK);
}

if (DGV) {
GlobalValue::LinkageTypes NewLinkage = GlobalValue::InternalLinkage;
bool LinkFromSrc = false;
GlobalValue::VisibilityTypes NV;
if (getLinkageResult(DGV, SF, NewLinkage, NV, LinkFromSrc))
return true;
NewVisibility = NV;
HasUnnamedAddr = HasUnnamedAddr && DGV->hasUnnamedAddr();
if (!DC) {
GlobalValue::LinkageTypes NewLinkage = GlobalValue::InternalLinkage;
GlobalValue::VisibilityTypes NV;
if (getLinkageResult(DGV, SF, NewLinkage, NV, LinkFromSrc))
return true;
NewVisibility = NV;
HasUnnamedAddr = HasUnnamedAddr && DGV->hasUnnamedAddr();

if (!LinkFromSrc) {
// Set calculated linkage
DGV->setLinkage(NewLinkage);
DGV->setVisibility(*NewVisibility);
DGV->setUnnamedAddr(HasUnnamedAddr);
}
}

if (!LinkFromSrc) {
// Set calculated linkage
DGV->setLinkage(NewLinkage);
DGV->setVisibility(*NewVisibility);
DGV->setUnnamedAddr(HasUnnamedAddr);

// Make sure to remember this mapping.
ValueMap[SF] = ConstantExpr::getBitCast(DGV, TypeMap.get(SF->getType()));

Expand All @@ -869,6 +1024,12 @@ bool ModuleLinker::linkFunctionProto(Function *SF) {
return false;
}

// If the Comdat this function was inside of wasn't selected, skip it.
if (DC && !DGV && !LinkFromSrc) {
DoNotLinkFromSource.insert(SF);
return false;
}

// If there is no linkage to be performed or we are linking from the source,
// bring SF over.
Function *NewDF = Function::Create(TypeMap.get(SF->getFunctionType()),
Expand All @@ -878,6 +1039,9 @@ bool ModuleLinker::linkFunctionProto(Function *SF) {
NewDF->setVisibility(*NewVisibility);
NewDF->setUnnamedAddr(HasUnnamedAddr);

if (DC)
NewDF->setComdat(DC);

if (DGV) {
// Any uses of DF need to change to NewDF, with cast.
DGV->replaceAllUsesWith(ConstantExpr::getBitCast(NewDF, DGV->getType()));
Expand All @@ -895,21 +1059,33 @@ bool ModuleLinker::linkAliasProto(GlobalAlias *SGA) {
llvm::Optional<GlobalValue::VisibilityTypes> NewVisibility;
bool HasUnnamedAddr = SGA->hasUnnamedAddr();

bool LinkFromSrc = false;
Comdat *DC = nullptr;
if (const Comdat *SC = SGA->getComdat()) {
Comdat::SelectionKind SK;
std::tie(SK, LinkFromSrc) = ComdatsChosen[SC];
DC = DstM->getOrInsertComdat(SC->getName());
DC->setSelectionKind(SK);
}

if (DGV) {
GlobalValue::LinkageTypes NewLinkage = GlobalValue::InternalLinkage;
GlobalValue::VisibilityTypes NV;
bool LinkFromSrc = false;
if (getLinkageResult(DGV, SGA, NewLinkage, NV, LinkFromSrc))
return true;
NewVisibility = NV;
HasUnnamedAddr = HasUnnamedAddr && DGV->hasUnnamedAddr();
if (!DC) {
GlobalValue::LinkageTypes NewLinkage = GlobalValue::InternalLinkage;
GlobalValue::VisibilityTypes NV;
if (getLinkageResult(DGV, SGA, NewLinkage, NV, LinkFromSrc))
return true;
NewVisibility = NV;
HasUnnamedAddr = HasUnnamedAddr && DGV->hasUnnamedAddr();

if (!LinkFromSrc) {
// Set calculated linkage.
DGV->setLinkage(NewLinkage);
DGV->setVisibility(*NewVisibility);
DGV->setUnnamedAddr(HasUnnamedAddr);
}
}

if (!LinkFromSrc) {
// Set calculated linkage.
DGV->setLinkage(NewLinkage);
DGV->setVisibility(*NewVisibility);
DGV->setUnnamedAddr(HasUnnamedAddr);

// Make sure to remember this mapping.
ValueMap[SGA] = ConstantExpr::getBitCast(DGV,TypeMap.get(SGA->getType()));

Expand All @@ -920,6 +1096,12 @@ bool ModuleLinker::linkAliasProto(GlobalAlias *SGA) {
}
}

// If the Comdat this alias was inside of wasn't selected, skip it.
if (DC && !DGV && !LinkFromSrc) {
DoNotLinkFromSource.insert(SGA);
return false;
}

// If there is no linkage to be performed or we're linking from the source,
// bring over SGA.
auto *PTy = cast<PointerType>(TypeMap.get(SGA->getType()));
Expand Down Expand Up @@ -1254,6 +1436,18 @@ bool ModuleLinker::run() {
// Loop over all of the linked values to compute type mappings.
computeTypeMapping();

ComdatsChosen.clear();
for (const StringMapEntry<llvm::Comdat> &SMEC : SrcM->getComdatSymbolTable()) {
const Comdat &C = SMEC.getValue();
if (ComdatsChosen.count(&C))
continue;
Comdat::SelectionKind SK;
bool LinkFromSrc;
if (getComdatResult(&C, SK, LinkFromSrc))
return true;
ComdatsChosen[&C] = std::make_pair(SK, LinkFromSrc);
}

// Insert all of the globals in src into the DstM module... without linking
// initializers (which could refer to functions not yet mapped over).
for (Module::global_iterator I = SrcM->global_begin(),
Expand Down
41 changes: 34 additions & 7 deletions llvm/lib/Transforms/IPO/GlobalDCE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,31 +77,58 @@ bool GlobalDCE::runOnModule(Module &M) {
// Remove empty functions from the global ctors list.
Changed |= optimizeGlobalCtorsList(M, isEmptyFunction);

typedef std::multimap<const Comdat *, GlobalValue *> ComdatGVPairsTy;
ComdatGVPairsTy ComdatGVPairs;

// Loop over the module, adding globals which are obviously necessary.
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
Changed |= RemoveUnusedGlobalValue(*I);
// Functions with external linkage are needed if they have a body
if (!I->isDiscardableIfUnused() &&
!I->isDeclaration() && !I->hasAvailableExternallyLinkage())
GlobalIsNeeded(I);
if (!I->isDeclaration() && !I->hasAvailableExternallyLinkage()) {
if (!I->isDiscardableIfUnused())
GlobalIsNeeded(I);
else if (const Comdat *C = I->getComdat())
ComdatGVPairs.insert(std::make_pair(C, I));
}
}

for (Module::global_iterator I = M.global_begin(), E = M.global_end();
I != E; ++I) {
Changed |= RemoveUnusedGlobalValue(*I);
// Externally visible & appending globals are needed, if they have an
// initializer.
if (!I->isDiscardableIfUnused() &&
!I->isDeclaration() && !I->hasAvailableExternallyLinkage())
GlobalIsNeeded(I);
if (!I->isDeclaration() && !I->hasAvailableExternallyLinkage()) {
if (!I->isDiscardableIfUnused())
GlobalIsNeeded(I);
else if (const Comdat *C = I->getComdat())
ComdatGVPairs.insert(std::make_pair(C, I));
}
}

for (Module::alias_iterator I = M.alias_begin(), E = M.alias_end();
I != E; ++I) {
Changed |= RemoveUnusedGlobalValue(*I);
// Externally visible aliases are needed.
if (!I->isDiscardableIfUnused())
if (!I->isDiscardableIfUnused()) {
GlobalIsNeeded(I);
} else if (const Comdat *C = I->getComdat()) {
ComdatGVPairs.insert(std::make_pair(C, I));
}
}

for (ComdatGVPairsTy::iterator I = ComdatGVPairs.begin(),
E = ComdatGVPairs.end();
I != E;) {
ComdatGVPairsTy::iterator UB = ComdatGVPairs.upper_bound(I->first);
bool CanDiscard = std::all_of(I, UB, [](ComdatGVPairsTy::value_type Pair) {
return Pair.second->isDiscardableIfUnused();
});
if (!CanDiscard) {
std::for_each(I, UB, [this](ComdatGVPairsTy::value_type Pair) {
GlobalIsNeeded(Pair.second);
});
}
I = UB;
}

// Now that all globals which are needed are in the AliveGlobals set, we loop
Expand Down
18 changes: 14 additions & 4 deletions llvm/lib/Transforms/IPO/GlobalOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/ConstantFolding.h"
Expand Down Expand Up @@ -1699,9 +1700,6 @@ static bool TryToShrinkGlobalToBoolean(GlobalVariable *GV, Constant *OtherVal) {
/// possible. If we make a change, return true.
bool GlobalOpt::ProcessGlobal(GlobalVariable *GV,
Module::global_iterator &GVI) {
if (!GV->isDiscardableIfUnused())
return false;

// Do more involved optimizations if the global is internal.
GV->removeDeadConstantUsers();

Expand Down Expand Up @@ -1944,6 +1942,13 @@ bool GlobalOpt::OptimizeFunctions(Module &M) {

bool GlobalOpt::OptimizeGlobalVars(Module &M) {
bool Changed = false;

SmallSet<const Comdat *, 8> NotDiscardableComdats;
for (const GlobalVariable &GV : M.globals())
if (const Comdat *C = GV.getComdat())
if (!GV.isDiscardableIfUnused())
NotDiscardableComdats.insert(C);

for (Module::global_iterator GVI = M.global_begin(), E = M.global_end();
GVI != E; ) {
GlobalVariable *GV = GVI++;
Expand All @@ -1958,7 +1963,12 @@ bool GlobalOpt::OptimizeGlobalVars(Module &M) {
GV->setInitializer(New);
}

Changed |= ProcessGlobal(GV, GVI);
if (GV->isDiscardableIfUnused()) {
if (const Comdat *C = GV->getComdat())
if (NotDiscardableComdats.count(C))
continue;
Changed |= ProcessGlobal(GV, GVI);
}
}
return Changed;
}
Expand Down
4 changes: 4 additions & 0 deletions llvm/test/Assembler/invalid-comdat.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s

@v = global i32 0, comdat $v
; CHECK: use of undefined comdat '$v'
5 changes: 5 additions & 0 deletions llvm/test/Assembler/invalid-comdat2.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s

$v = comdat any
$v = comdat any
; CHECK: redefinition of comdat '$v'
92 changes: 92 additions & 0 deletions llvm/test/CodeGen/X86/coff-comdat.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
; RUN: llc -mtriple i386-pc-win32 < %s | FileCheck %s

$f1 = comdat any
@v1 = global i32 0, comdat $f1
define void @f1() comdat $f1 {
ret void
}

$f2 = comdat exactmatch
@v2 = global i32 0, comdat $f2
define void @f2() comdat $f2 {
ret void
}

$f3 = comdat largest
@v3 = global i32 0, comdat $f3
define void @f3() comdat $f3 {
ret void
}

$f4 = comdat noduplicates
@v4 = global i32 0, comdat $f4
define void @f4() comdat $f4 {
ret void
}

$f5 = comdat samesize
@v5 = global i32 0, comdat $f5
define void @f5() comdat $f5 {
ret void
}

$f6 = comdat samesize
@v6 = global i32 0, comdat $f6
@f6 = global i32 0, comdat $f6

$"\01@f7@0" = comdat any
define x86_fastcallcc void @"\01@v7@0"() comdat $"\01@f7@0" {
ret void
}
define x86_fastcallcc void @"\01@f7@0"() comdat $"\01@f7@0" {
ret void
}

$f8 = comdat any
define x86_fastcallcc void @v8() comdat $f8 {
ret void
}
define x86_fastcallcc void @f8() comdat $f8 {
ret void
}

$vftable = comdat largest

@some_name = private unnamed_addr constant [2 x i8*] zeroinitializer, comdat $vftable
@vftable = alias getelementptr([2 x i8*]* @some_name, i32 0, i32 1)

; CHECK: .section .text,"xr",discard,_f1
; CHECK: .globl _f1
; CHECK: .section .text,"xr",same_contents,_f2
; CHECK: .globl _f2
; CHECK: .section .text,"xr",largest,_f3
; CHECK: .globl _f3
; CHECK: .section .text,"xr",one_only,_f4
; CHECK: .globl _f4
; CHECK: .section .text,"xr",same_size,_f5
; CHECK: .globl _f5
; CHECK: .section .text,"xr",associative,@f7@0
; CHECK: .globl @v7@0
; CHECK: .section .text,"xr",discard,@f7@0
; CHECK: .globl @f7@0
; CHECK: .section .text,"xr",associative,@f8@0
; CHECK: .globl @v8@0
; CHECK: .section .text,"xr",discard,@f8@0
; CHECK: .globl @f8@0
; CHECK: .section .bss,"bw",associative,_f1
; CHECK: .globl _v1
; CHECK: .section .bss,"bw",associative,_f2
; CHECK: .globl _v2
; CHECK: .section .bss,"bw",associative,_f3
; CHECK: .globl _v3
; CHECK: .section .bss,"bw",associative,_f4
; CHECK: .globl _v4
; CHECK: .section .bss,"bw",associative,_f5
; CHECK: .globl _v5
; CHECK: .section .bss,"bw",associative,_f6
; CHECK: .globl _v6
; CHECK: .section .bss,"bw",same_size,_f6
; CHECK: .globl _f6
; CHECK: .section .rdata,"rd",largest,_vftable
; CHECK: .globl _vftable
; CHECK: _vftable = L_some_name+4
156 changes: 156 additions & 0 deletions llvm/test/CodeGen/X86/coff-comdat.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
.text
.def @feat.00;
.scl 3;
.type 0;
.endef
.globl @feat.00
@feat.00 = 1
.def _f1;
.scl 2;
.type 32;
.endef
.section .text,"xr",discard,_f1
.globl _f1
.align 16, 0x90
_f1: # @f1
# BB#0:
retl

.def _f2;
.scl 2;
.type 32;
.endef
.section .text,"xr",same_contents,_f2
.globl _f2
.align 16, 0x90
_f2: # @f2
# BB#0:
retl

.def _f3;
.scl 2;
.type 32;
.endef
.section .text,"xr",largest,_f3
.globl _f3
.align 16, 0x90
_f3: # @f3
# BB#0:
retl

.def _f4;
.scl 2;
.type 32;
.endef
.section .text,"xr",one_only,_f4
.globl _f4
.align 16, 0x90
_f4: # @f4
# BB#0:
retl

.def _f5;
.scl 2;
.type 32;
.endef
.section .text,"xr",same_size,_f5
.globl _f5
.align 16, 0x90
_f5: # @f5
# BB#0:
retl

.def @v7@0;
.scl 2;
.type 32;
.endef
.section .text,"xr",associative,@f7@0
.globl @v7@0
.align 16, 0x90
@v7@0: # @"\01@v7@0"
# BB#0:
retl

.def @f7@0;
.scl 2;
.type 32;
.endef
.section .text,"xr",discard,@f7@0
.globl @f7@0
.align 16, 0x90
@f7@0: # @"\01@f7@0"
# BB#0:
retl

.def @v8@0;
.scl 2;
.type 32;
.endef
.section .text,"xr",associative,@f8@0
.globl @v8@0
.align 16, 0x90
@v8@0: # @v8
# BB#0:
retl

.def @f8@0;
.scl 2;
.type 32;
.endef
.section .text,"xr",discard,@f8@0
.globl @f8@0
.align 16, 0x90
@f8@0: # @f8
# BB#0:
retl

.section .bss,"bw",associative,_f1
.globl _v1 # @v1
.align 4
_v1:
.long 0 # 0x0

.section .bss,"bw",associative,_f2
.globl _v2 # @v2
.align 4
_v2:
.long 0 # 0x0

.section .bss,"bw",associative,_f3
.globl _v3 # @v3
.align 4
_v3:
.long 0 # 0x0

.section .bss,"bw",associative,_f4
.globl _v4 # @v4
.align 4
_v4:
.long 0 # 0x0

.section .bss,"bw",associative,_f5
.globl _v5 # @v5
.align 4
_v5:
.long 0 # 0x0

.section .bss,"bw",associative,_f6
.globl _v6 # @v6
.align 4
_v6:
.long 0 # 0x0

.section .bss,"bw",same_size,_f6
.globl _f6 # @f6
.align 4
_f6:
.long 0 # 0x0

.section .rdata,"rd"
.align 4 # @some_name
L_some_name:
.zero 8


.globl _vftable
_vftable = L_some_name+4
9 changes: 9 additions & 0 deletions llvm/test/CodeGen/X86/coff-comdat2.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
; RUN: not llc %s -o /dev/null 2>&1 | FileCheck %s

target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
target triple = "i686-pc-windows-msvc"

$foo = comdat largest
@foo = global i32 0
@bar = global i32 0, comdat $foo
; CHECK: Associative COMDAT symbol 'foo' is not a key for it's COMDAT.
8 changes: 8 additions & 0 deletions llvm/test/CodeGen/X86/coff-comdat3.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
; RUN: not llc %s -o /dev/null 2>&1 | FileCheck %s

target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
target triple = "i686-pc-windows-msvc"

$foo = comdat largest
@bar = global i32 0, comdat $foo
; CHECK: Associative COMDAT symbol 'foo' does not exist.
11 changes: 11 additions & 0 deletions llvm/test/CodeGen/X86/elf-comdat.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
; RUN: llc -mtriple x86_64-pc-linux-gnu < %s | FileCheck %s

$f = comdat any
@v = global i32 0, comdat $f
define void @f() comdat $f {
ret void
}
; CHECK: .section .text.f,"axG",@progbits,f,comdat
; CHECK: .globl f
; CHECK: .section .bss.v,"aGw",@nobits,f,comdat
; CHECK: .globl v
12 changes: 12 additions & 0 deletions llvm/test/CodeGen/X86/elf-comdat2.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
; RUN: llc -mtriple x86_64-pc-linux-gnu < %s | FileCheck %s

$foo = comdat any
@bar = global i32 42, comdat $foo
@foo = global i32 42

; CHECK: .type bar,@object
; CHECK-NEXT: .section .data.bar,"aGw",@progbits,foo,comdat
; CHECK-NEXT: .globl bar
; CHECK: .type foo,@object
; CHECK-NEXT: .data
; CHECK-NEXT: .globl foo
6 changes: 6 additions & 0 deletions llvm/test/CodeGen/X86/macho-comdat.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
; RUN: not llc -mtriple x86_64-apple-darwin < %s 2> %t
; RUN: FileCheck < %t %s

$f = comdat any
@v = global i32 0, comdat $f
; CHECK: LLVM ERROR: MachO doesn't support COMDATs, 'f' cannot be lowered.
15 changes: 15 additions & 0 deletions llvm/test/Feature/comdat.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
; RUN: llvm-as < %s | llvm-dis | FileCheck %s

$f = comdat any
; CHECK: $f = comdat any

$f2 = comdat any
; CHECK-NOT: f2

@v = global i32 0, comdat $f
; CHECK: @v = global i32 0, comdat $f

define void @f() comdat $f {
ret void
}
; CHECK: define void @f() comdat $f
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@.str_noinst = private unnamed_addr constant [4 x i8] c"aaa\00", section "llvm.metadata"
@.str_inst = private unnamed_addr constant [4 x i8] c"aaa\00",
@.str_inst = private unnamed_addr constant [4 x i8] c"aaa\00"

; CHECK-NOT: {{asan_gen.*str_noinst}}
; CHECK: {{asan_gen.*str_inst}}
Expand Down
20 changes: 20 additions & 0 deletions llvm/test/Linker/Inputs/comdat.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
target triple = "i686-pc-windows-msvc"

$foo = comdat largest
@foo = global i64 43, comdat $foo

define i32 @bar() comdat $foo {
ret i32 43
}

$qux = comdat largest
@qux = global i32 13, comdat $qux
@in_unselected_group = global i32 13, comdat $qux

define i32 @baz() comdat $qux {
ret i32 13
}

$any = comdat any
@any = global i64 7, comdat $any
2 changes: 2 additions & 0 deletions llvm/test/Linker/Inputs/comdat2.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
$foo = comdat largest
@foo = global i64 43, comdat $foo
2 changes: 2 additions & 0 deletions llvm/test/Linker/Inputs/comdat3.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
$foo = comdat noduplicates
@foo = global i64 43, comdat $foo
5 changes: 5 additions & 0 deletions llvm/test/Linker/Inputs/comdat4.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
target triple = "i686-pc-windows-msvc"

$foo = comdat samesize
@foo = global i64 42, comdat $foo
15 changes: 15 additions & 0 deletions llvm/test/Linker/Inputs/comdat5.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
target triple = "i686-pc-windows-msvc"

%MSRTTICompleteObjectLocator = type { i32, i32, i32, i8*, %MSRTTIClassHierarchyDescriptor* }
%MSRTTIClassHierarchyDescriptor = type { i32, i32, i32, %MSRTTIBaseClassDescriptor** }
%MSRTTIBaseClassDescriptor = type { i8*, i32, i32, i32, i32, i32, %MSRTTIClassHierarchyDescriptor* }
%struct.S = type { i32 (...)** }

$"\01??_7S@@6B@" = comdat largest

@"\01??_R4S@@6B@" = external constant %MSRTTICompleteObjectLocator
@some_name = private unnamed_addr constant [2 x i8*] [i8* bitcast (%MSRTTICompleteObjectLocator* @"\01??_R4S@@6B@" to i8*), i8* bitcast (void (%struct.S*, i32)* @"\01??_GS@@UAEPAXI@Z" to i8*)], comdat $"\01??_7S@@6B@"
@"\01??_7S@@6B@" = alias getelementptr([2 x i8*]* @some_name, i32 0, i32 1)

declare x86_thiscallcc void @"\01??_GS@@UAEPAXI@Z"(%struct.S*, i32) unnamed_addr
32 changes: 32 additions & 0 deletions llvm/test/Linker/comdat.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
; RUN: llvm-link %s %p/Inputs/comdat.ll -S -o - | FileCheck %s
target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
target triple = "i686-pc-windows-msvc"

$foo = comdat largest
@foo = global i32 42, comdat $foo

define i32 @bar() comdat $foo {
ret i32 42
}

$qux = comdat largest
@qux = global i64 12, comdat $qux

define i32 @baz() comdat $qux {
ret i32 12
}

$any = comdat any
@any = global i64 6, comdat $any

; CHECK: $qux = comdat largest
; CHECK: $foo = comdat largest
; CHECK: $any = comdat any

; CHECK: @qux = global i64 12, comdat $qux
; CHECK: @any = global i64 6, comdat $any
; CHECK: @foo = global i64 43, comdat $foo
; CHECK-NOT: @in_unselected_group = global i32 13, comdat $qux

; CHECK: define i32 @baz() comdat $qux
; CHECK: define i32 @bar() comdat $foo
7 changes: 7 additions & 0 deletions llvm/test/Linker/comdat2.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
; RUN: not llvm-link %s %p/Inputs/comdat.ll -S -o - 2>&1 | FileCheck %s
target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
target triple = "i686-pc-windows-msvc"

$foo = comdat samesize
@foo = global i32 42, comdat $foo
; CHECK: Linking COMDATs named 'foo': invalid selection kinds!
5 changes: 5 additions & 0 deletions llvm/test/Linker/comdat3.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
; RUN: not llvm-link %s %p/Inputs/comdat2.ll -S -o - 2>&1 | FileCheck %s

$foo = comdat largest
@foo = global i32 43, comdat $foo
; CHECK: Linking COMDATs named 'foo': can't do size dependent selection without DataLayout!
5 changes: 5 additions & 0 deletions llvm/test/Linker/comdat4.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
; RUN: not llvm-link %s %p/Inputs/comdat3.ll -S -o - 2>&1 | FileCheck %s

$foo = comdat noduplicates
@foo = global i64 43, comdat $foo
; CHECK: Linking COMDATs named 'foo': noduplicates has been violated!
7 changes: 7 additions & 0 deletions llvm/test/Linker/comdat5.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
; RUN: not llvm-link %s %p/Inputs/comdat4.ll -S -o - 2>&1 | FileCheck %s
target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
target triple = "i686-pc-windows-msvc"

$foo = comdat samesize
@foo = global i32 42, comdat $foo
; CHECK: Linking COMDATs named 'foo': SameSize violated!
13 changes: 13 additions & 0 deletions llvm/test/Linker/comdat6.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
; RUN: llvm-link %s %p/Inputs/comdat5.ll -S -o - 2>&1 | FileCheck %s
; RUN: llvm-link %p/Inputs/comdat5.ll %s -S -o - 2>&1 | FileCheck %s
target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
target triple = "i686-pc-windows-msvc"

%struct.S = type { i32 (...)** }

$"\01??_7S@@6B@" = comdat largest
@"\01??_7S@@6B@" = linkonce_odr unnamed_addr constant [1 x i8*] [i8* bitcast (void (%struct.S*, i32)* @"\01??_GS@@UAEPAXI@Z" to i8*)], comdat $"\01??_7S@@6B@"

; CHECK: @"\01??_7S@@6B@" = alias getelementptr inbounds ([2 x i8*]* @some_name, i32 0, i32 1)

declare x86_thiscallcc void @"\01??_GS@@UAEPAXI@Z"(%struct.S*, i32) unnamed_addr
9 changes: 9 additions & 0 deletions llvm/test/Linker/comdat7.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
; RUN: not llvm-link %s %p/Inputs/comdat5.ll -S -o - 2>&1 | FileCheck %s
target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
target triple = "i686-pc-windows-msvc"

$"\01??_7S@@6B@" = comdat largest
define void @"\01??_7S@@6B@"() {
ret void
}
; CHECK: GlobalVariable required for data dependent selection!
10 changes: 10 additions & 0 deletions llvm/test/Linker/comdat8.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
; RUN: not llvm-link %s %p/Inputs/comdat5.ll -S -o - 2>&1 | FileCheck %s
target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
target triple = "i686-pc-windows-msvc"

$"\01??_7S@@6B@" = comdat largest
define void @some_name() {
ret void
}
@"\01??_7S@@6B@" = alias i8* inttoptr (i32 ptrtoint (void ()* @some_name to i32) to i8*)
; CHECK: COMDAT key involves incomputable alias size.
5 changes: 5 additions & 0 deletions llvm/test/Verifier/comdat.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s

$v = comdat any
@v = common global i32 0, comdat $v
; CHECK: 'common' global may not be in a Comdat!
5 changes: 5 additions & 0 deletions llvm/test/Verifier/comdat2.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s

$v = comdat any
@v = private global i32 0, comdat $v
; CHECK: comdat global value has local linkage