return false;
}
-static bool hasImplicitComdat(size_t Val) {
- switch (Val) {
- default:
- return false;
- case 1: // Old WeakAnyLinkage
- case 4: // Old LinkOnceAnyLinkage
- case 10: // Old WeakODRLinkage
- case 11: // Old LinkOnceODRLinkage
- return true;
- }
-}
-
static GlobalValue::LinkageTypes getDecodedLinkage(unsigned Val) {
switch (Val) {
default: // Map unknown/new linkages to external
case 0:
return GlobalValue::ExternalLinkage;
+ case 1:
+ return GlobalValue::WeakAnyLinkage;
case 2:
return GlobalValue::AppendingLinkage;
case 3:
return GlobalValue::InternalLinkage;
+ case 4:
+ return GlobalValue::LinkOnceAnyLinkage;
case 5:
return GlobalValue::ExternalLinkage; // Obsolete DLLImportLinkage
case 6:
return GlobalValue::CommonLinkage;
case 9:
return GlobalValue::PrivateLinkage;
+ case 10:
+ return GlobalValue::WeakODRLinkage;
+ case 11:
+ return GlobalValue::LinkOnceODRLinkage;
case 12:
return GlobalValue::AvailableExternallyLinkage;
case 13:
return GlobalValue::PrivateLinkage; // Obsolete LinkerPrivateWeakLinkage
case 15:
return GlobalValue::ExternalLinkage; // Obsolete LinkOnceODRAutoHideLinkage
- case 1: // Old value with implicit comdat.
- case 16:
- return GlobalValue::WeakAnyLinkage;
- case 10: // Old value with implicit comdat.
- case 17:
- return GlobalValue::WeakODRLinkage;
- case 4: // Old value with implicit comdat.
- case 18:
- return GlobalValue::LinkOnceAnyLinkage;
- case 11: // Old value with implicit comdat.
- case 19:
- return GlobalValue::LinkOnceODRLinkage;
}
}
Value *V = ValueList[ValueID];
V->setName(StringRef(ValueName.data(), ValueName.size()));
- if (auto *GO = dyn_cast<GlobalObject>(V)) {
- if (GO->getComdat() == reinterpret_cast<Comdat *>(1))
- GO->setComdat(TheModule->getOrInsertComdat(V->getName()));
- }
ValueName.clear();
break;
}
Ty = cast<PointerType>(Ty)->getElementType();
bool isConstant = Record[1];
- uint64_t RawLinkage = Record[3];
- GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage);
+ GlobalValue::LinkageTypes Linkage = getDecodedLinkage(Record[3]);
unsigned Alignment = (1 << Record[4]) >> 1;
std::string Section;
if (Record[5]) {
if (Record.size() > 10)
NewGV->setDLLStorageClass(GetDecodedDLLStorageClass(Record[10]));
else
- UpgradeDLLImportExportLinkage(NewGV, RawLinkage);
+ UpgradeDLLImportExportLinkage(NewGV, Record[3]);
ValueList.push_back(NewGV);
if (unsigned InitID = Record[2])
GlobalInits.push_back(std::make_pair(NewGV, InitID-1));
- if (Record.size() > 11) {
+ if (Record.size() > 11)
if (unsigned ComdatID = Record[11]) {
assert(ComdatID <= ComdatList.size());
NewGV->setComdat(ComdatList[ComdatID - 1]);
}
- } else if (hasImplicitComdat(RawLinkage)) {
- NewGV->setComdat(reinterpret_cast<Comdat *>(1));
- }
break;
}
// FUNCTION: [type, callingconv, isproto, linkage, paramattr,
Func->setCallingConv(static_cast<CallingConv::ID>(Record[1]));
bool isProto = Record[2];
- uint64_t RawLinkage = Record[3];
- Func->setLinkage(getDecodedLinkage(RawLinkage));
+ Func->setLinkage(getDecodedLinkage(Record[3]));
Func->setAttributes(getAttributes(Record[4]));
Func->setAlignment((1 << Record[5]) >> 1);
if (Record.size() > 11)
Func->setDLLStorageClass(GetDecodedDLLStorageClass(Record[11]));
else
- UpgradeDLLImportExportLinkage(Func, RawLinkage);
+ UpgradeDLLImportExportLinkage(Func, Record[3]);
- if (Record.size() > 12) {
+ if (Record.size() > 12)
if (unsigned ComdatID = Record[12]) {
assert(ComdatID <= ComdatList.size());
Func->setComdat(ComdatList[ComdatID - 1]);
}
- } else if (hasImplicitComdat(RawLinkage)) {
- Func->setComdat(reinterpret_cast<Comdat *>(1));
- }
if (Record.size() > 13 && Record[13] != 0)
FunctionPrefixes.push_back(std::make_pair(Func, Record[13]-1));
case GlobalValue::ExternalLinkage:
return 0;
case GlobalValue::WeakAnyLinkage:
- return 16;
+ return 1;
case GlobalValue::AppendingLinkage:
return 2;
case GlobalValue::InternalLinkage:
return 3;
case GlobalValue::LinkOnceAnyLinkage:
- return 18;
+ return 4;
case GlobalValue::ExternalWeakLinkage:
return 7;
case GlobalValue::CommonLinkage:
case GlobalValue::PrivateLinkage:
return 9;
case GlobalValue::WeakODRLinkage:
- return 17;
+ return 10;
case GlobalValue::LinkOnceODRLinkage:
- return 19;
+ return 11;
case GlobalValue::AvailableExternallyLinkage:
return 12;
}
Log2_32_Ceil(MaxGlobalType+1)));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Constant.
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Initializer.
- Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 5)); // Linkage.
+ Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // Linkage.
if (MaxAlignment == 0) // Alignment.
Abbv->Add(BitCodeAbbrevOp(0));
else {
// 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 ((EmitUniquedSection && !Kind.isCommon()) || GV->hasComdat()) {
+ if ((GV->isWeakForLinker() || EmitUniquedSection || GV->hasComdat()) &&
+ !Kind.isCommon()) {
StringRef Prefix = getSectionPrefixForGlobal(Kind);
SmallString<128> Name(Prefix);
StringRef Group = "";
unsigned Flags = getELFSectionFlags(Kind);
- if (const Comdat *C = getELFComdat(GV)) {
+ if (GV->isWeakForLinker() || GV->hasComdat()) {
+ if (const Comdat *C = getELFComdat(GV))
+ Group = C->getName();
+ else
+ Group = Name.substr(Prefix.size());
Flags |= ELF::SHF_GROUP;
- Group = C->getName();
}
return getContext().getELFSection(Name.str(),
unsigned Characteristics = getCOFFSectionFlags(Kind);
StringRef Name = GV->getSection();
StringRef COMDATSymName = "";
- if (GV->hasComdat()) {
+ if ((GV->isWeakForLinker() || GV->hasComdat()) && !Kind.isCommon()) {
Selection = getSelectionForCOFF(GV);
const GlobalValue *ComdatGV;
if (Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
else
EmitUniquedSection = TM.getDataSections();
- if ((EmitUniquedSection && !Kind.isCommon()) || GV->hasComdat()) {
+ // 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.
+ // Section names depend on the name of the symbol which is not feasible if the
+ // symbol has private linkage.
+ if ((GV->isWeakForLinker() || EmitUniquedSection || GV->hasComdat()) &&
+ !Kind.isCommon()) {
const char *Name = getCOFFSectionNameForUniqueGlobal(Kind);
unsigned Characteristics = getCOFFSectionFlags(Kind);
OutContext));
if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() ||
GV->hasCommonLinkage()) {
+ // TODO Use COMDAT groups for LinkOnceLinkage
OutStreamer.EmitSymbolAttribute(SymGlob, MCSA_Weak);
}
}
emitArrayBound(GVSym, GV);
OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global);
+ // TODO Use COMDAT groups for LinkOnceLinkage
if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() ||
GV->hasCommonLinkage())
OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Weak);
; CHECK: @available_externally.var = available_externally constant i32 0{{$}}
@linkonce.var = linkonce constant i32 0
-; CHECK: @linkonce.var = linkonce constant i32 0, comdat{{$}}
+; CHECK: @linkonce.var = linkonce constant i32 0{{$}}
@weak.var = weak constant i32 0
-; CHECK: @weak.var = weak constant i32 0, comdat{{$}}
+; CHECK: @weak.var = weak constant i32 0{{$}}
@linkonce_odr.var = linkonce_odr constant i32 0
-; CHECK: @linkonce_odr.var = linkonce_odr constant i32 0, comdat{{$}}
+; CHECK: @linkonce_odr.var = linkonce_odr constant i32 0{{$}}
@linkonce_odr_auto_hide.var = linkonce_odr_auto_hide constant i32 0
; CHECK: @linkonce_odr_auto_hide.var = constant i32 0{{$}}
}
define linkonce void @linkonce()
-; CHECK: define linkonce void @linkonce() comdat {
+; CHECK: define linkonce void @linkonce() {
{
ret void
}
define weak void @weak()
-; CHECK: define weak void @weak() comdat {
+; CHECK: define weak void @weak() {
{
ret void
}
define linkonce_odr void @linkonce_odr()
-; CHECK: define linkonce_odr void @linkonce_odr() comdat {
+; CHECK: define linkonce_odr void @linkonce_odr() {
{
ret void
}
--- /dev/null
+; RUN: llc < %s -mtriple=arm-linux-gnueabi | FileCheck %s -check-prefix=ARMGNUEABI
+
+; Checking that a comdat group gets generated correctly for a static member
+; of instantiated C++ templates.
+; see http://sourcery.mentor.com/public/cxx-abi/abi.html#vague-itemplate
+; section 5.2.6 Instantiated templates
+; "Any static member data object is emitted in a COMDAT identified by its mangled
+; name, in any object file with a reference to its name symbol."
+
+; Case 1: variable is not explicitly initialized, and ends up in a .bss section
+; ARMGNUEABI: .section .bss._ZN1CIiE1iE,"aGw",%nobits,_ZN1CIiE1iE,comdat
+@_ZN1CIiE1iE = weak_odr global i32 0, align 4
+
+; Case 2: variable is explicitly initialized, and ends up in a .data section
+; ARMGNUEABI: .section .data._ZN1CIiE1jE,"aGw",%progbits,_ZN1CIiE1jE,comdat
+@_ZN1CIiE1jE = weak_odr global i32 12, align 4
ret void
}
-; CHECK: .text
+; CHECK: .section .text.test3,"axG",%progbits,test3,comdat
; CHECK: .weak test3
; CHECK: .type test3,%function
define linkonce_odr void @test3() {
ret void
}
+; CHECK: .section .text,"xr",discard,lnk1
; CHECK: .globl lnk1
define linkonce_odr dllexport void @lnk1() {
ret void
}
+; CHECK: .section .text,"xr",discard,lnk2
; CHECK: .globl lnk2
define linkonce_odr dllexport void @lnk2() alwaysinline {
ret void
}
+; CHECK: .section .text,"xr",discard,weak1
; CHECK: .globl weak1
define weak_odr dllexport void @weak1() {
ret void
; CHECK: .comm Var3
@Var3 = common dllexport global i32 0, align 4
+; CHECK: .section .data,"wd",discard,WeakVar1
; CHECK: .globl WeakVar1
@WeakVar1 = weak_odr dllexport global i32 1, align 4
+; CHECK: .section .rdata,"rd",discard,WeakVar2
; CHECK: .globl WeakVar2
@WeakVar2 = weak_odr dllexport unnamed_addr constant i32 1
ret void
}
+; CHECK: .section .text,"xr",discard,_lnk1
; CHECK: .globl _lnk1
define linkonce_odr dllexport void @lnk1() {
ret void
}
+; CHECK: .section .text,"xr",discard,_lnk2
; CHECK: .globl _lnk2
define linkonce_odr dllexport void @lnk2() alwaysinline {
ret void
}
+; CHECK: .section .text,"xr",discard,_weak1
; CHECK: .globl _weak1
define weak_odr dllexport void @weak1() {
ret void
; CHECK: .comm _Var3
@Var3 = common dllexport global i32 0, align 4
+; CHECK: .section .data,"wd",discard,_WeakVar1
; CHECK: .globl _WeakVar1
@WeakVar1 = weak_odr dllexport global i32 1, align 4
+; CHECK: .section .rdata,"rd",discard,_WeakVar2
; CHECK: .globl _WeakVar2
@WeakVar2 = weak_odr dllexport unnamed_addr constant i32 1
@"foo bar" = linkonce global i32 42
; LINUX: .type "foo bar",@object
+; LINUX: .section ".data.foo bar","aGw",@progbits,"foo bar",comdat
; LINUX: .weak "foo bar"
; LINUX: "foo bar":
@G6 = weak_odr unnamed_addr constant [1 x i8] c"\01"
; LINUX: .type G6,@object
+; LINUX: .section .rodata.G6,"aG",@progbits,G6,comdat
; LINUX: .weak G6
; LINUX: G6:
; LINUX: .byte 1
--- /dev/null
+; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s -check-prefix=X86LINUX
+
+; Checking that a comdat group gets generated correctly for a static member
+; of instantiated C++ templates.
+; see http://sourcery.mentor.com/public/cxx-abi/abi.html#vague-itemplate
+; section 5.2.6 Instantiated templates
+; "Any static member data object is emitted in a COMDAT identified by its mangled
+; name, in any object file with a reference to its name symbol."
+
+; Case 1: variable is not explicitly initialized, and ends up in a .bss section
+; X86LINUX: .section .bss._ZN1CIiE1iE,"aGw",@nobits,_ZN1CIiE1iE,comdat
+@_ZN1CIiE1iE = weak_odr global i32 0, align 4
+
+; Case 2: variable is explicitly initialized, and ends up in a .data section
+; X86LINUX: .section .data._ZN1CIiE1jE,"aGw",@progbits,_ZN1CIiE1jE,comdat
+@_ZN1CIiE1jE = weak_odr global i32 12, align 4
declare void @_Z3bari(i32)
-; CHECK-LINUX: _Z3fooILi1EEvi:
+; CHECK-LINUX: .text._Z3fooILi1EEvi,"axG",@progbits,_Z3fooILi1EEvi,comdat
define linkonce void @_Z3fooILi1EEvi(i32 %Y) nounwind {
entry:
; CHECK: L0$pb
@"\01?thingy@@3Ufoo@@B" = global %struct.foo zeroinitializer, align 4
; CHECK: .bss
-$thingy_linkonce = comdat any
-@thingy_linkonce = linkonce_odr global %struct.foo zeroinitializer, comdat, align 4
+@thingy_linkonce = linkonce_odr global %struct.foo zeroinitializer, align 4
; CHECK: .section .bss,"wb",discard,_thingy_linkonce
; CHECK: .section .CRT$XLB,"rd"
@weak_array = weak_odr unnamed_addr constant [1 x i8*] [i8* bitcast (void ()* @f to i8*)]
-; CHECK: .section .rdata,"rd"
+; CHECK: .section .rdata,"rd",discard,weak_array
--- /dev/null
+; Test that weak functions and globals are placed into selectany COMDAT\r
+; sections with the mangled name as suffix. Ensure that the weak linkage\r
+; type is not ignored by the backend if the section was specialized.\r
+;\r
+; RUN: llc -mtriple=i686-pc-win32 %s -o - | FileCheck %s --check-prefix=X86\r
+; RUN: llc -mtriple=i686-pc-mingw32 %s -o - | FileCheck %s --check-prefix=X86\r
+; RUN: llc -mtriple=x86_64-pc-win32 %s -o - | FileCheck %s --check-prefix=X64\r
+; RUN: llc -mtriple=x86_64-pc-mingw32 %s -o - | FileCheck %s --check-prefix=X64\r
+\r
+; Mangled function\r
+; X86: .section .text,"xr",discard,__Z3foo\r
+; X86: .globl __Z3foo\r
+;\r
+; X64: .section .text,"xr",discard,_Z3foo\r
+; X64: .globl _Z3foo\r
+define weak void @_Z3foo() {\r
+ ret void\r
+}\r
+\r
+; Unmangled function\r
+; X86: .section .sect,"xr",discard,_f\r
+; X86: .globl _f\r
+;\r
+; X64: .section .sect,"xr",discard,f\r
+; X64: .globl f\r
+define weak void @f() section ".sect" {\r
+ ret void\r
+}\r
+\r
+; Weak global\r
+; X86: .section .data,"rd",discard,_a\r
+; X86: .globl _a\r
+; X86: .zero 12\r
+;\r
+; X64: .section .data,"rd",discard,a\r
+; X64: .globl a\r
+; X64: .zero 12\r
+@a = weak unnamed_addr constant { i32, i32, i32 } { i32 0, i32 0, i32 0}, section ".data"\r
+\r
+; X86: .section .tls$,"wd",discard,_b\r
+; X86: .globl _b\r
+; X86: .long 0\r
+;\r
+; X64: .section .tls$,"wd",discard,b\r
+; X64: .globl b\r
+; X64: .long 0\r
+\r
+@b = weak_odr thread_local global i32 0, align 4\r