diff --git a/llvm/include/llvm/MC/SectionKind.h b/llvm/include/llvm/MC/SectionKind.h --- a/llvm/include/llvm/MC/SectionKind.h +++ b/llvm/include/llvm/MC/SectionKind.h @@ -82,6 +82,9 @@ /// ThreadData - Initialized TLS data objects. ThreadData, + /// ThreadBSSLocal - Zero-initialized TLS data objects with local linkage. + ThreadBSSLocal, + /// GlobalWriteableData - Writeable data that is global (not thread /// local). @@ -146,11 +149,12 @@ } bool isThreadLocal() const { - return K == ThreadData || K == ThreadBSS; + return K == ThreadData || K == ThreadBSS || K == ThreadBSSLocal; } - bool isThreadBSS() const { return K == ThreadBSS; } + bool isThreadBSS() const { return K == ThreadBSS || K == ThreadBSSLocal; } bool isThreadData() const { return K == ThreadData; } + bool isThreadBSSLocal() const { return K == ThreadBSSLocal; } bool isGlobalWriteableData() const { return isBSS() || isCommon() || isData() || isReadOnlyWithRel(); @@ -194,6 +198,7 @@ static SectionKind getMergeableConst32() { return get(MergeableConst32); } static SectionKind getThreadBSS() { return get(ThreadBSS); } static SectionKind getThreadData() { return get(ThreadData); } + static SectionKind getThreadBSSLocal() { return get(ThreadBSSLocal); } static SectionKind getBSS() { return get(BSS); } static SectionKind getBSSLocal() { return get(BSSLocal); } static SectionKind getBSSExtern() { return get(BSSExtern); } diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -2136,8 +2136,8 @@ return cast( getSectionForFunctionDescriptor(cast(GO), TM)) ->getQualNameSymbol(); - if ((TM.getDataSections() && !GO->hasSection()) || GOKind.isCommon() || - GOKind.isBSSLocal()) + if ((TM.getDataSections() && !GO->hasSection()) || GO->hasCommonLinkage() || + GOKind.isBSSLocal() || GOKind.isThreadBSSLocal()) return cast(SectionForGlobal(GO, GOKind, TM)) ->getQualNameSymbol(); } @@ -2175,24 +2175,31 @@ SmallString<128> Name; getNameWithPrefix(Name, GO, TM); + XCOFF::StorageMappingClass SMC = + isa(GO) ? XCOFF::XMC_DS : XCOFF::XMC_UA; + if (GO->isThreadLocal()) + SMC = XCOFF::XMC_UL; + // Externals go into a csect of type ER. return getContext().getXCOFFSection( Name, SectionKind::getMetadata(), - XCOFF::CsectProperties(isa(GO) ? XCOFF::XMC_DS : XCOFF::XMC_UA, - XCOFF::XTY_ER)); + XCOFF::CsectProperties(SMC, XCOFF::XTY_ER)); } MCSection *TargetLoweringObjectFileXCOFF::SelectSectionForGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { // Common symbols go into a csect with matching name which will get mapped // into the .bss section. - if (Kind.isBSSLocal() || Kind.isCommon()) { + // Uninitialized local TLS symbols go into a csect with matching name which + // will get mapped into the .tbss section. + if (Kind.isBSSLocal() || GO->hasCommonLinkage() || Kind.isThreadBSSLocal()) { SmallString<128> Name; getNameWithPrefix(Name, GO, TM); + XCOFF::StorageMappingClass SMC = Kind.isBSSLocal() ? XCOFF::XMC_BS + : Kind.isCommon() ? XCOFF::XMC_RW + : XCOFF::XMC_UL; return getContext().getXCOFFSection( - Name, Kind, - XCOFF::CsectProperties( - Kind.isBSSLocal() ? XCOFF::XMC_BS : XCOFF::XMC_RW, XCOFF::XTY_CM)); + Name, Kind, XCOFF::CsectProperties(SMC, XCOFF::XTY_CM)); } if (Kind.isMergeableCString()) { @@ -2249,6 +2256,21 @@ return ReadOnlySection; } + if (Kind.isThreadLocal()) { + if (TM.getDataSections()) { + SmallString<128> Name; + getNameWithPrefix(Name, GO, TM); + return getContext().getXCOFFSection( + Name, + Kind.isThreadData() ? SectionKind::getThreadData() + : SectionKind::getThreadBSS(), + XCOFF::CsectProperties(Kind.isThreadData() ? XCOFF::XMC_TL + : XCOFF::XMC_UL, + XCOFF::XTY_SD)); + } + return Kind.isThreadData() ? TLSDataSection : TLSBSSSection; + } + report_fatal_error("XCOFF other section types not yet implemented."); } diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp --- a/llvm/lib/MC/MCObjectFileInfo.cpp +++ b/llvm/lib/MC/MCObjectFileInfo.cpp @@ -888,6 +888,16 @@ XCOFF::CsectProperties(XCOFF::StorageMappingClass::XMC_RO, XCOFF::XTY_SD), /* MultiSymbolsAllowed*/ true); + TLSDataSection = Ctx->getXCOFFSection( + ".tdata", SectionKind::getThreadData(), + XCOFF::CsectProperties(XCOFF::StorageMappingClass::XMC_TL, XCOFF::XTY_SD), + /* MultiSymbolsAllowed*/ true); + + TLSBSSSection = Ctx->getXCOFFSection( + ".tbss", SectionKind::getThreadBSS(), + XCOFF::CsectProperties(XCOFF::StorageMappingClass::XMC_UL, XCOFF::XTY_SD), + /* MultiSymbolsAllowed*/ true); + TOCBaseSection = Ctx->getXCOFFSection( "TOC", SectionKind::getData(), XCOFF::CsectProperties(XCOFF::StorageMappingClass::XMC_TC0, diff --git a/llvm/lib/MC/MCSectionXCOFF.cpp b/llvm/lib/MC/MCSectionXCOFF.cpp --- a/llvm/lib/MC/MCSectionXCOFF.cpp +++ b/llvm/lib/MC/MCSectionXCOFF.cpp @@ -38,6 +38,16 @@ return; } + // Initialized TLS data. + if (getKind().isThreadData()) { + // We only expect XMC_TL here because XMC_UL is for uninitialized TLS + // data only. + if (getMappingClass() != XCOFF::XMC_TL) + report_fatal_error("Unhandled storage-mapping class for .tdata csect."); + printCsectDirective(OS); + return; + } + if (getKind().isData()) { switch (getMappingClass()) { case XCOFF::XMC_RW: @@ -57,16 +67,30 @@ return; } - if (getKind().isBSSLocal() || getKind().isCommon()) { + // Common csect type (uninitialized storage) does not have to print csect + // directive for section switching + if (getCSectType() == XCOFF::XTY_CM ) { assert((getMappingClass() == XCOFF::XMC_RW || - getMappingClass() == XCOFF::XMC_BS) && - "Generated a storage-mapping class for a common/bss csect we don't " + getMappingClass() == XCOFF::XMC_BS || + getMappingClass() == XCOFF::XMC_UL) && + "Generated a storage-mapping class for a common/bss/tbss csect we " + "don't " "understand how to switch to."); - assert(getCSectType() == XCOFF::XTY_CM && - "wrong csect type for .bss csect"); - // Don't have to print a directive for switching to section for commons. - // '.comm' and '.lcomm' directives for the variable will create the needed - // csect. + assert(getKind().isBSSLocal() || getKind().isCommon() || + getKind().isThreadBSS() && + "wrong symbol type for .bss/.tbss csect"); + // Don't have to print a directive for switching to section for commons and + // uninitialized TLS data. '.comm' and '.lcomm' directives for the variable + // will create the needed csect. + return; + } + + // uninitialized TLS data not eligible for common csect type (like + // weak/external linkage) + if (getKind().isThreadBSS()) { + if (getMappingClass() != XCOFF::XMC_UL) + report_fatal_error("Unhandled storage-mapping class for .tbss csect."); + printCsectDirective(OS); return; } diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -193,7 +193,6 @@ /// sinit/sterm function names. std::string FormatIndicatorAndUniqueModId; - static void ValidateGV(const GlobalVariable *GV); // Record a list of GlobalAlias associated with a GlobalObject. // This is used for AIX's extra-label-at-definition aliasing strategy. DenseMap> @@ -2051,15 +2050,6 @@ #undef GENVALUECOMMENT } -void PPCAIXAsmPrinter::ValidateGV(const GlobalVariable *GV) { - // Early error checking limiting what is supported. - if (GV->isThreadLocal()) - report_fatal_error("Thread local not yet supported on AIX."); - - if (GV->hasComdat()) - report_fatal_error("COMDAT not yet supported by AIX."); -} - static bool isSpecialLLVMGlobalArrayToSkip(const GlobalVariable *GV) { return GV->hasAppendingLinkage() && StringSwitch(GV->getName()) @@ -2085,7 +2075,9 @@ assert(!GV->getName().startswith("llvm.") && "Unhandled intrinsic global variable."); - ValidateGV(GV); + + if (GV->hasComdat()) + report_fatal_error("COMDAT not yet supported by AIX."); MCSymbolXCOFF *GVSym = cast(getSymbol(GV)); @@ -2095,7 +2087,8 @@ } SectionKind GVKind = getObjFileLowering().getKindForGlobal(GV, TM); - if (!GVKind.isGlobalWriteableData() && !GVKind.isReadOnly()) + if (!GVKind.isGlobalWriteableData() && !GVKind.isReadOnly() && + !GVKind.isThreadLocal()) // Checks for both ThreadData and ThreadBSS. report_fatal_error("Encountered a global variable kind that is " "not supported yet."); @@ -2107,14 +2100,14 @@ const DataLayout &DL = GV->getParent()->getDataLayout(); - // Handle common symbols. - if (GVKind.isCommon() || GVKind.isBSSLocal()) { + // Handle common and uninitialized local symbols + if (GV->hasCommonLinkage() || GVKind.isBSSLocal() || GVKind.isThreadBSSLocal()) { Align Alignment = GV->getAlign().getValueOr(DL.getPreferredAlign(GV)); uint64_t Size = DL.getTypeAllocSize(GV->getType()->getElementType()); GVSym->setStorageClass( TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GV)); - if (GVKind.isBSSLocal()) + if (GVKind.isBSSLocal() || GVKind.isThreadBSSLocal()) OutStreamer->emitXCOFFLocalCommonSymbol( OutContext.getOrCreateSymbol(GVSym->getSymbolTableName()), Size, GVSym, Alignment.value()); diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -3117,6 +3117,8 @@ SDValue PPCTargetLowering::LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const { + if (Subtarget.isAIXABI()) + report_fatal_error("TLS is not yet supported on AIX."); // FIXME: TLS addresses currently use medium model code sequences, // which is the most useful form. Eventually support for small and // large models could be added if users need it, at the cost of diff --git a/llvm/lib/Target/TargetLoweringObjectFile.cpp b/llvm/lib/Target/TargetLoweringObjectFile.cpp --- a/llvm/lib/Target/TargetLoweringObjectFile.cpp +++ b/llvm/lib/Target/TargetLoweringObjectFile.cpp @@ -217,8 +217,12 @@ // Handle thread-local data first. if (GVar->isThreadLocal()) { - if (isSuitableForBSS(GVar) && !TM.Options.NoZerosInBSS) + if (isSuitableForBSS(GVar) && !TM.Options.NoZerosInBSS) { + if (GVar->hasLocalLinkage()) { + return SectionKind::getThreadBSSLocal(); + } return SectionKind::getThreadBSS(); + } return SectionKind::getThreadData(); } diff --git a/llvm/test/CodeGen/PowerPC/aix-tls-checks.ll b/llvm/test/CodeGen/PowerPC/aix-tls-checks.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-tls-checks.ll @@ -0,0 +1,13 @@ +; RUN: not --crash llc -verify-machineinstrs -mcpu=pwr7 -mattr=-altivec \ +; RUN: -mtriple powerpc-ibm-aix-xcoff < %s - 2>&1 | FileCheck %s +; RUN: not --crash llc -verify-machineinstrs -mcpu=pwr7 -mattr=-altivec \ +; RUN: -mtriple powerpc64-ibm-aix-xcoff < %s - 2>&1 | FileCheck %s + +; CHECK: TLS is not yet supported on AIX + +@tls1 = thread_local global i32 0, align 4 + +define i32* @getTls1Addr() { +entry: + ret i32* @tls1 +} diff --git a/llvm/test/CodeGen/PowerPC/aix-tls-variables-ppc32.ll b/llvm/test/CodeGen/PowerPC/aix-tls-variables-ppc32.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-tls-variables-ppc32.ll @@ -0,0 +1,262 @@ +; This file tests 32 bit TLS variable generation. + +; RUN: llc -verify-machineinstrs -mcpu=pwr7 -mattr=-altivec -mtriple \ +; RUN: powerpc-ibm-aix-xcoff < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mcpu=pwr7 -mattr=-altivec -mtriple \ +; RUN: powerpc-ibm-aix-xcoff -data-sections=false < %s | FileCheck %s \ +; RUN: --check-prefix=NODATASEC + +; When data-sections is true (default), we emit data into separate sections. +; When data-sections is false, we emit data into the .data / .tdata / .tbss sections. + +; Int global variable, TLS/Non-TLS, Local/external/weak/common linkage, initialized/uninitialized +; CHECK: .csect global_int_external_TL[RW],2 +; CHECK-NEXT: .globl global_int_external_TL[RW] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 1 + +; NODATASEC: .csect .data[RW],3 +; NODATASEC-NEXT: .globl global_int_external_TL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:global_int_external_TL: +; NODATASEC-NEXT: .vbyte 4, 1 +@global_int_external_TL = global i32 1, align 4 + +; CHECK-NEXT: .csect global_int_external_UL[RW],2 +; CHECK-NEXT: .globl global_int_external_UL[RW] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 0 + +; NODATASEC-NEXT: .globl global_int_external_UL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:global_int_external_UL: +; NODATASEC-NEXT: .vbyte 4, 0 +@global_int_external_UL = global i32 0, align 4 + +; CHECK-NEXT: .csect tls_global_int_external_TL[TL],2 +; CHECK-NEXT: .globl tls_global_int_external_TL[TL] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 1 + +; NODATASEC-NEXT: .csect .tdata[TL],3 +; NODATASEC-NEXT: .globl tls_global_int_external_TL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:tls_global_int_external_TL: +; NODATASEC-NEXT: .vbyte 4, 1 +@tls_global_int_external_TL = thread_local global i32 1, align 4 + +; CHECK-NEXT: .csect tls_global_int_external_UL[UL],2 +; CHECK-NEXT: .globl tls_global_int_external_UL[UL] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 0 + +; NODATASEC-NEXT: .csect .tbss[UL],3 +; NODATASEC-NEXT: .globl tls_global_int_external_UL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:tls_global_int_external_UL: +; NODATASEC-NEXT: .vbyte 4, 0 +@tls_global_int_external_UL = thread_local global i32 0, align 4 + +; CHECK-NEXT: .csect global_int_local_TL[RW],2 +; CHECK-NEXT: .lglobl global_int_local_TL[RW] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 2 + +; NODATASEC-NEXT: .csect .data[RW],3 +; NODATASEC-NEXT: .lglobl global_int_local_TL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:global_int_local_TL: +; NODATASEC-NEXT: .vbyte 4, 2 +@global_int_local_TL = internal global i32 2, align 4 + +; CHECK-NEXT: .csect tls_global_int_local_TL[TL],2 +; CHECK-NEXT: .lglobl tls_global_int_local_TL[TL] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 2 + +; NODATASEC-NEXT: .csect .tdata[TL],3 +; NODATASEC-NEXT: .lglobl tls_global_int_local_TL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:tls_global_int_local_TL: +; NODATASEC-NEXT: .vbyte 4, 2 +@tls_global_int_local_TL = internal thread_local global i32 2, align 4 + +; CHECK-NEXT: .lcomm global_int_local_UL,4,global_int_local_UL[BS],2 +; NODATASEC-NEXT: .lcomm global_int_local_UL,4,global_int_local_UL[BS],2 +@global_int_local_UL = internal global i32 0, align 4 + +; CHECK-NEXT: .lcomm tls_global_int_local_UL,4,tls_global_int_local_UL[UL],2 +; NODATASEC-NEXT: .lcomm tls_global_int_local_UL,4,tls_global_int_local_UL[UL],2 +@tls_global_int_local_UL = internal thread_local global i32 0, align 4 + +; CHECK-NEXT: .csect global_int_weak_UL[RW],2 +; CHECK-NEXT: .weak global_int_weak_UL[RW] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 0 + +; NODATASEC-NEXT: .csect .data[RW],3 +; NODATASEC-NEXT: .weak global_int_weak_UL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:global_int_weak_UL: +; NODATASEC-NEXT: .vbyte 4, 0 +@global_int_weak_UL = weak global i32 0, align 4 + +; CHECK-NEXT: .csect tls_global_int_weak_UL[UL],2 +; CHECK-NEXT: .weak tls_global_int_weak_UL[UL] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 0 + +; NODATASEC-NEXT: .csect .tbss[UL],3 +; NODATASEC-NEXT: .weak tls_global_int_weak_UL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:tls_global_int_weak_UL: +; NODATASEC-NEXT: .vbyte 4, 0 +@tls_global_int_weak_UL = weak thread_local global i32 0, align 4 + +; CHECK-NEXT: .comm global_int_common_UL[RW],4,2 +; NODATASEC-NEXT: .comm global_int_common_UL[RW],4,2 +@global_int_common_UL = common global i32 0, align 4 + +; CHECK-NEXT: .comm tls_global_int_common_UL[UL],4,2 +; NODATASEC-NEXT: .comm tls_global_int_common_UL[UL],4,2 +@tls_global_int_common_UL = common thread_local global i32 0, align 4 + +; CHECK-NEXT: .csect global_int_weak_TL[RW],2 +; CHECK-NEXT: .weak global_int_weak_TL[RW] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 1 + +; NODATASEC-NEXT: .csect .data[RW],3 +; NODATASEC-NEXT: .weak global_int_weak_TL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:global_int_weak_TL: +; NODATASEC-NEXT: .vbyte 4, 1 +@global_int_weak_TL = weak global i32 1, align 4 + +; CHECK-NEXT: .csect tls_global_int_weak_TL[TL],2 +; CHECK-NEXT: .weak tls_global_int_weak_TL[TL] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 1 + +; NODATASEC-NEXT: .csect .tdata[TL],3 +; NODATASEC-NEXT: .weak tls_global_int_weak_TL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:tls_global_int_weak_TL: +; NODATASEC-NEXT: .vbyte 4, 1 +@tls_global_int_weak_TL = weak thread_local global i32 1, align 4 + +; CHECK-NEXT: .extern global_int_external_declaration[UA] +; NODATASEC-NEXT: .extern global_int_external_declaration[UA] +@global_int_external_declaration = external global i32, align 4 + +; CHECK-NEXT: .extern tls_global_int_external_declaration[UL] +; NODATASEC-NEXT: .extern tls_global_int_external_declaration[UL] +@tls_global_int_external_declaration = external thread_local global i32, align 4 + + +; double global variable, TLS/Non-TLS, common/external linkage + +; CHECK-NEXT: .comm global_double_common_UL[RW],8,3 +; NODATASEC-NEXT: .comm global_double_common_UL[RW],8,3 +@global_double_common_UL = common global double 0.000000e+00, align 8 + +; CHECK-NEXT: .comm tls_global_double_common_UL[UL],8,3 +; NODATASEC-NEXT: .comm tls_global_double_common_UL[UL],8,3 +@tls_global_double_common_UL = common thread_local global double 0.000000e+00, align 8 + +; CHECK-NEXT: .extern global_double_external[UA] +; NODATASEC-NEXT: .extern global_double_external[UA] +@global_double_external = external global i64, align 8 + +; CHECK-NEXT: .extern tls_global_double_external[UL] +; NODATASEC-NEXT: .extern tls_global_double_external[UL] +@tls_global_double_external = external thread_local global i64, align 8 + + +; Long long global variable, TLS/Non-TLS, local/weak linkage + +; CHECK-NEXT: .csect global_long_long_internal_TL[RW],3 +; CHECK-NEXT: .lglobl global_long_long_internal_TL[RW] +; CHECK-NEXT: .align 3 +; CHECK-NEXT: .vbyte 4, 0 +; CHECK-NEXT: .vbyte 4, 1 +; NODATASEC-NEXT: .csect .data[RW],3 +; NODATASEC-NEXT: .lglobl global_long_long_internal_TL +; NODATASEC-NEXT: .align 3 +; NODATASEC-NEXT:global_long_long_internal_TL: +; NODATASEC-NEXT: .vbyte 4, 0 +; NODATASEC-NEXT: .vbyte 4, 1 +@global_long_long_internal_TL = internal global i64 1, align 8 + +; CHECK-NEXT: .csect tls_global_long_long_internal_TL[TL],3 +; CHECK-NEXT: .lglobl tls_global_long_long_internal_TL[TL] +; CHECK-NEXT: .align 3 +; CHECK-NEXT: .vbyte 4, 0 +; CHECK-NEXT: .vbyte 4, 1 +; NODATASEC-NEXT: .csect .tdata[TL],3 +; NODATASEC-NEXT: .lglobl tls_global_long_long_internal_TL +; NODATASEC-NEXT: .align 3 +; NODATASEC-NEXT:tls_global_long_long_internal_TL: +; NODATASEC-NEXT: .vbyte 4, 0 +; NODATASEC-NEXT: .vbyte 4, 1 +@tls_global_long_long_internal_TL = internal thread_local global i64 1, align 8 + +; CHECK-NEXT: .lcomm global_long_long_internal_UL,8,global_long_long_internal_UL[BS],3 +; NODATASEC-NEXT: .lcomm global_long_long_internal_UL,8,global_long_long_internal_UL[BS],3 +@global_long_long_internal_UL = internal global i64 0, align 8 + +; CHECK-NEXT: .lcomm tls_global_long_long_internal_UL,8,tls_global_long_long_internal_UL[UL],3 +; NODATASEC-NEXT: .lcomm tls_global_long_long_internal_UL,8,tls_global_long_long_internal_UL[UL],3 +@tls_global_long_long_internal_UL = internal thread_local global i64 0, align 8 + +; CHECK-NEXT: .csect global_long_long_weak_TL[RW],3 +; CHECK-NEXT: .weak global_long_long_weak_TL[RW] +; CHECK-NEXT: .align 3 +; CHECK-NEXT: .vbyte 4, 0 +; CHECK-NEXT: .vbyte 4, 1 +; NODATASEC-NEXT: .csect .data[RW],3 +; NODATASEC-NEXT: .weak global_long_long_weak_TL +; NODATASEC-NEXT: .align 3 +; NODATASEC-NEXT:global_long_long_weak_TL: +; NODATASEC-NEXT: .vbyte 4, 0 +; NODATASEC-NEXT: .vbyte 4, 1 +@global_long_long_weak_TL = weak global i64 1, align 8 + +; CHECK-NEXT: .csect tls_global_long_long_weak_TL[TL],3 +; CHECK-NEXT: .weak tls_global_long_long_weak_TL[TL] +; CHECK-NEXT: .align 3 +; CHECK-NEXT: .vbyte 4, 0 +; CHECK-NEXT: .vbyte 4, 1 +; NODATASEC-NEXT: .csect .tdata[TL],3 +; NODATASEC-NEXT: .weak tls_global_long_long_weak_TL +; NODATASEC-NEXT: .align 3 +; NODATASEC-NEXT:tls_global_long_long_weak_TL: +; NODATASEC-NEXT: .vbyte 4, 0 +; NODATASEC-NEXT: .vbyte 4, 1 +@tls_global_long_long_weak_TL = weak thread_local global i64 1, align 8 + +; CHECK-NEXT: .csect global_long_long_weak_UL[RW],3 +; CHECK-NEXT: .weak global_long_long_weak_UL[RW] +; CHECK-NEXT: .align 3 +; CHECK-NEXT: .vbyte 4, 0 +; CHECK-NEXT: .vbyte 4, 0 +; NODATASEC-NEXT: .csect .data[RW],3 +; NODATASEC-NEXT: .weak global_long_long_weak_UL +; NODATASEC-NEXT: .align 3 +; NODATASEC-NEXT:global_long_long_weak_UL: +; NODATASEC-NEXT: .vbyte 4, 0 +; NODATASEC-NEXT: .vbyte 4, 0 +@global_long_long_weak_UL = weak global i64 0, align 8 + +; CHECK-NEXT: .csect tls_global_long_long_weak_UL[UL],3 +; CHECK-NEXT: .weak tls_global_long_long_weak_UL[UL] +; CHECK-NEXT: .align 3 +; CHECK-NEXT: .vbyte 4, 0 +; CHECK-NEXT: .vbyte 4, 0 +; NODATASEC-NEXT: .csect .tbss[UL],3 +; NODATASEC-NEXT: .weak tls_global_long_long_weak_UL +; NODATASEC-NEXT: .align 3 +; NODATASEC-NEXT:tls_global_long_long_weak_UL: +; NODATASEC-NEXT: .vbyte 4, 0 +; NODATASEC-NEXT: .vbyte 4, 0 +@tls_global_long_long_weak_UL = weak thread_local global i64 0, align 8 diff --git a/llvm/test/CodeGen/PowerPC/aix-tls-variables-ppc64.ll b/llvm/test/CodeGen/PowerPC/aix-tls-variables-ppc64.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-tls-variables-ppc64.ll @@ -0,0 +1,250 @@ +; This file tests 64 bit TLS variable generation + +; RUN: llc -verify-machineinstrs -mcpu=pwr7 -mattr=-altivec -mtriple \ +; RUN: powerpc64-ibm-aix-xcoff < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mcpu=pwr7 -mattr=-altivec -mtriple \ +; RUN: powerpc64-ibm-aix-xcoff -data-sections=false < %s | FileCheck %s \ +; RUN: --check-prefix=NODATASEC + +; When data-sections is true (default), we emit data into separate sections. +; When data-sections is false, we emit data into the .data / .tdata / .tbss sections. + +; Int global variable, TLS/Non-TLS, Local/external/weak/common linkage, initialized/uninitialized +; CHECK: .csect global_int_external_TL[RW],2 +; CHECK-NEXT: .globl global_int_external_TL[RW] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 1 + +; NODATASEC: .csect .data[RW],3 +; NODATASEC-NEXT: .globl global_int_external_TL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:global_int_external_TL: +; NODATASEC-NEXT: .vbyte 4, 1 +@global_int_external_TL = global i32 1, align 4 + +; CHECK-NEXT: .csect global_int_external_UL[RW],2 +; CHECK-NEXT: .globl global_int_external_UL[RW] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 0 + +; NODATASEC-NEXT: .globl global_int_external_UL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:global_int_external_UL: +; NODATASEC-NEXT: .vbyte 4, 0 +@global_int_external_UL = global i32 0, align 4 + +; CHECK-NEXT: .csect tls_global_int_external_TL[TL],2 +; CHECK-NEXT: .globl tls_global_int_external_TL[TL] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 1 + +; NODATASEC-NEXT: .csect .tdata[TL],3 +; NODATASEC-NEXT: .globl tls_global_int_external_TL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:tls_global_int_external_TL: +; NODATASEC-NEXT: .vbyte 4, 1 +@tls_global_int_external_TL = thread_local global i32 1, align 4 + +; CHECK-NEXT: .csect tls_global_int_external_UL[UL],2 +; CHECK-NEXT: .globl tls_global_int_external_UL[UL] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 0 + +; NODATASEC-NEXT: .csect .tbss[UL],3 +; NODATASEC-NEXT: .globl tls_global_int_external_UL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:tls_global_int_external_UL: +; NODATASEC-NEXT: .vbyte 4, 0 +@tls_global_int_external_UL = thread_local global i32 0, align 4 + +; CHECK-NEXT: .csect global_int_local_TL[RW],2 +; CHECK-NEXT: .lglobl global_int_local_TL[RW] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 2 + +; NODATASEC-NEXT: .csect .data[RW],3 +; NODATASEC-NEXT: .lglobl global_int_local_TL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:global_int_local_TL: +; NODATASEC-NEXT: .vbyte 4, 2 +@global_int_local_TL = internal global i32 2, align 4 + +; CHECK-NEXT: .csect tls_global_int_local_TL[TL],2 +; CHECK-NEXT: .lglobl tls_global_int_local_TL[TL] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 2 + +; NODATASEC-NEXT: .csect .tdata[TL],3 +; NODATASEC-NEXT: .lglobl tls_global_int_local_TL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:tls_global_int_local_TL: +; NODATASEC-NEXT: .vbyte 4, 2 +@tls_global_int_local_TL = internal thread_local global i32 2, align 4 + +; CHECK-NEXT: .lcomm global_int_local_UL,4,global_int_local_UL[BS],2 +; NODATASEC-NEXT: .lcomm global_int_local_UL,4,global_int_local_UL[BS],2 +@global_int_local_UL = internal global i32 0, align 4 + +; CHECK-NEXT: .lcomm tls_global_int_local_UL,4,tls_global_int_local_UL[UL],2 +; NODATASEC-NEXT: .lcomm tls_global_int_local_UL,4,tls_global_int_local_UL[UL],2 +@tls_global_int_local_UL = internal thread_local global i32 0, align 4 + +; CHECK-NEXT: .csect global_int_weak_UL[RW],2 +; CHECK-NEXT: .weak global_int_weak_UL[RW] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 0 + +; NODATASEC-NEXT: .csect .data[RW],3 +; NODATASEC-NEXT: .weak global_int_weak_UL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:global_int_weak_UL: +; NODATASEC-NEXT: .vbyte 4, 0 +@global_int_weak_UL = weak global i32 0, align 4 + +; CHECK-NEXT: .csect tls_global_int_weak_UL[UL],2 +; CHECK-NEXT: .weak tls_global_int_weak_UL[UL] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 0 + +; NODATASEC-NEXT: .csect .tbss[UL],3 +; NODATASEC-NEXT: .weak tls_global_int_weak_UL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:tls_global_int_weak_UL: +; NODATASEC-NEXT: .vbyte 4, 0 +@tls_global_int_weak_UL = weak thread_local global i32 0, align 4 + +; CHECK-NEXT: .comm global_int_common_UL[RW],4,2 +; NODATASEC-NEXT: .comm global_int_common_UL[RW],4,2 +@global_int_common_UL = common global i32 0, align 4 + +; CHECK-NEXT: .comm tls_global_int_common_UL[UL],4,2 +; NODATASEC-NEXT: .comm tls_global_int_common_UL[UL],4,2 +@tls_global_int_common_UL = common thread_local global i32 0, align 4 + +; CHECK-NEXT: .csect global_int_weak_TL[RW],2 +; CHECK-NEXT: .weak global_int_weak_TL[RW] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 1 + +; NODATASEC-NEXT: .csect .data[RW],3 +; NODATASEC-NEXT: .weak global_int_weak_TL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:global_int_weak_TL: +; NODATASEC-NEXT: .vbyte 4, 1 +@global_int_weak_TL = weak global i32 1, align 4 + +; CHECK-NEXT: .csect tls_global_int_weak_TL[TL],2 +; CHECK-NEXT: .weak tls_global_int_weak_TL[TL] +; CHECK-NEXT: .align 2 +; CHECK-NEXT: .vbyte 4, 1 + +; NODATASEC-NEXT: .csect .tdata[TL],3 +; NODATASEC-NEXT: .weak tls_global_int_weak_TL +; NODATASEC-NEXT: .align 2 +; NODATASEC-NEXT:tls_global_int_weak_TL: +; NODATASEC-NEXT: .vbyte 4, 1 +@tls_global_int_weak_TL = weak thread_local global i32 1, align 4 + +; CHECK-NEXT: .extern global_int_external_declaration[UA] +; NODATASEC-NEXT: .extern global_int_external_declaration[UA] +@global_int_external_declaration = external global i32, align 4 + +; CHECK-NEXT: .extern tls_global_int_external_declaration[UL] +; NODATASEC-NEXT: .extern tls_global_int_external_declaration[UL] +@tls_global_int_external_declaration = external thread_local global i32, align 4 + + +; double global variable, TLS/Non-TLS, common/external linkage + +; CHECK-NEXT: .comm global_double_common_UL[RW],8,3 +; NODATASEC-NEXT: .comm global_double_common_UL[RW],8,3 +@global_double_common_UL = common global double 0.000000e+00, align 8 + +; CHECK-NEXT: .comm tls_global_double_common_UL[UL],8,3 +; NODATASEC-NEXT: .comm tls_global_double_common_UL[UL],8,3 +@tls_global_double_common_UL = common thread_local global double 0.000000e+00, align 8 + +; CHECK-NEXT: .extern global_double_external[UA] +; NODATASEC-NEXT: .extern global_double_external[UA] +@global_double_external = external global i64, align 8 + +; CHECK-NEXT: .extern tls_global_double_external[UL] +; NODATASEC-NEXT: .extern tls_global_double_external[UL] +@tls_global_double_external = external thread_local global i64, align 8 + + +; Long long global variable, TLS/Non-TLS, local/weak linkage + +; CHECK-NEXT: .csect global_long_long_internal_TL[RW],3 +; CHECK-NEXT: .lglobl global_long_long_internal_TL[RW] +; CHECK-NEXT: .align 3 +; CHECK-NEXT: .vbyte 8, 1 +; NODATASEC-NEXT: .csect .data[RW],3 +; NODATASEC-NEXT: .lglobl global_long_long_internal_TL +; NODATASEC-NEXT: .align 3 +; NODATASEC-NEXT:global_long_long_internal_TL: +; NODATASEC-NEXT: .vbyte 8, 1 +@global_long_long_internal_TL = internal global i64 1, align 8 + +; CHECK-NEXT: .csect tls_global_long_long_internal_TL[TL],3 +; CHECK-NEXT: .lglobl tls_global_long_long_internal_TL[TL] +; CHECK-NEXT: .align 3 +; CHECK-NEXT: .vbyte 8, 1 +; NODATASEC-NEXT: .csect .tdata[TL],3 +; NODATASEC-NEXT: .lglobl tls_global_long_long_internal_TL +; NODATASEC-NEXT: .align 3 +; NODATASEC-NEXT:tls_global_long_long_internal_TL: +; NODATASEC-NEXT: .vbyte 8, 1 +@tls_global_long_long_internal_TL = internal thread_local global i64 1, align 8 + +; CHECK-NEXT: .lcomm global_long_long_internal_UL,8,global_long_long_internal_UL[BS],3 +; NODATASEC-NEXT: .lcomm global_long_long_internal_UL,8,global_long_long_internal_UL[BS],3 +@global_long_long_internal_UL = internal global i64 0, align 8 + +; CHECK-NEXT: .lcomm tls_global_long_long_internal_UL,8,tls_global_long_long_internal_UL[UL],3 +; NODATASEC-NEXT: .lcomm tls_global_long_long_internal_UL,8,tls_global_long_long_internal_UL[UL],3 +@tls_global_long_long_internal_UL = internal thread_local global i64 0, align 8 + +; CHECK-NEXT: .csect global_long_long_weak_TL[RW],3 +; CHECK-NEXT: .weak global_long_long_weak_TL[RW] +; CHECK-NEXT: .align 3 +; CHECK-NEXT: .vbyte 8, 1 +; NODATASEC-NEXT: .csect .data[RW],3 +; NODATASEC-NEXT: .weak global_long_long_weak_TL +; NODATASEC-NEXT: .align 3 +; NODATASEC-NEXT:global_long_long_weak_TL: +; NODATASEC-NEXT: .vbyte 8, 1 +@global_long_long_weak_TL = weak global i64 1, align 8 + +; CHECK-NEXT: .csect tls_global_long_long_weak_TL[TL],3 +; CHECK-NEXT: .weak tls_global_long_long_weak_TL[TL] +; CHECK-NEXT: .align 3 +; CHECK-NEXT: .vbyte 8, 1 +; NODATASEC-NEXT: .csect .tdata[TL],3 +; NODATASEC-NEXT: .weak tls_global_long_long_weak_TL +; NODATASEC-NEXT: .align 3 +; NODATASEC-NEXT:tls_global_long_long_weak_TL: +; NODATASEC-NEXT: .vbyte 8, 1 +@tls_global_long_long_weak_TL = weak thread_local global i64 1, align 8 + +; CHECK-NEXT: .csect global_long_long_weak_UL[RW],3 +; CHECK-NEXT: .weak global_long_long_weak_UL[RW] +; CHECK-NEXT: .align 3 +; CHECK-NEXT: .vbyte 8, 0 +; NODATASEC-NEXT: .csect .data[RW],3 +; NODATASEC-NEXT: .weak global_long_long_weak_UL +; NODATASEC-NEXT: .align 3 +; NODATASEC-NEXT:global_long_long_weak_UL: +; NODATASEC-NEXT: .vbyte 8, 0 +@global_long_long_weak_UL = weak global i64 0, align 8 + +; CHECK-NEXT: .csect tls_global_long_long_weak_UL[UL],3 +; CHECK-NEXT: .weak tls_global_long_long_weak_UL[UL] +; CHECK-NEXT: .align 3 +; CHECK-NEXT: .vbyte 8, 0 +; NODATASEC-NEXT: .csect .tbss[UL],3 +; NODATASEC-NEXT: .weak tls_global_long_long_weak_UL +; NODATASEC-NEXT: .align 3 +; NODATASEC-NEXT:tls_global_long_long_weak_UL: +; NODATASEC-NEXT: .vbyte 8, 0 +@tls_global_long_long_weak_UL = weak thread_local global i64 0, align 8