Index: clang/lib/Basic/Targets/OSTargets.h =================================================================== --- clang/lib/Basic/Targets/OSTargets.h +++ clang/lib/Basic/Targets/OSTargets.h @@ -553,6 +553,8 @@ this->MCountName = ".mcount"; this->NewAlign = 256; this->SuitableAlign = 256; + this->resetDataLayout(std::string(this->getDataLayoutString()) + "-T" + + std::to_string(this->MaxTLSAlign)); } TargetInfo::CallingConvCheckResult Index: clang/test/CodeGen/ps-datalayout.c =================================================================== --- /dev/null +++ clang/test/CodeGen/ps-datalayout.c @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -triple x86_64-scei-ps4 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-scei-ps5 -emit-llvm %s -o - | FileCheck %s +int i; + +// CHECK: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128-T256" + Index: llvm/include/llvm/IR/DataLayout.h =================================================================== --- llvm/include/llvm/IR/DataLayout.h +++ llvm/include/llvm/IR/DataLayout.h @@ -124,6 +124,7 @@ unsigned AllocaAddrSpace; MaybeAlign StackNaturalAlign; + MaybeAlign MaxTLSAlign; unsigned ProgramAddrSpace; unsigned DefaultGlobalsAddrSpace; @@ -216,6 +217,7 @@ BigEndian = DL.isBigEndian(); AllocaAddrSpace = DL.AllocaAddrSpace; StackNaturalAlign = DL.StackNaturalAlign; + MaxTLSAlign = DL.MaxTLSAlign; FunctionPtrAlign = DL.FunctionPtrAlign; TheFunctionPtrAlignType = DL.TheFunctionPtrAlignType; ProgramAddrSpace = DL.ProgramAddrSpace; @@ -279,6 +281,16 @@ return *StackNaturalAlign; } + /// Returns true if the given alignment exceeds the maximum TLS alignment. + bool exceedsMaxTLSAlign(Align Alignment) const { + return MaxTLSAlign && (Alignment > *MaxTLSAlign); + } + + Align getMaxTLSAlign() const { + assert(MaxTLSAlign && "MaxTLSAlign must be defined"); + return *MaxTLSAlign; + } + unsigned getAllocaAddrSpace() const { return AllocaAddrSpace; } /// Returns the alignment of function pointers, which may or may not be Index: llvm/lib/IR/DataLayout.cpp =================================================================== --- llvm/lib/IR/DataLayout.cpp +++ llvm/lib/IR/DataLayout.cpp @@ -443,13 +443,18 @@ return Err; } break; - case 'S': { // Stack natural alignment. + case 'S': // Stack natural alignment. + case 'T': { // Maximum TLS alignment. uint64_t Alignment; if (Error Err = getIntInBytes(Tok, Alignment)) return Err; if (Alignment != 0 && !llvm::isPowerOf2_64(Alignment)) return reportError("Alignment is neither 0 nor a power of 2"); - StackNaturalAlign = MaybeAlign(Alignment); + switch (Specifier) { + default: llvm_unreachable("Unexpected specifier!"); + case 'S': StackNaturalAlign = MaybeAlign(Alignment); break; + case 'T': MaxTLSAlign = MaybeAlign(Alignment); break; + } break; } case 'F': { Index: llvm/lib/Target/X86/X86TargetMachine.cpp =================================================================== --- llvm/lib/Target/X86/X86TargetMachine.cpp +++ llvm/lib/Target/X86/X86TargetMachine.cpp @@ -159,6 +159,10 @@ else Ret += "-S128"; + // Some platforms have a maximum alignment for TLS variables. + if (TT.isPS()) + Ret += "-T256"; + return Ret; } Index: llvm/lib/Transforms/Utils/Local.cpp =================================================================== --- llvm/lib/Transforms/Utils/Local.cpp +++ llvm/lib/Transforms/Utils/Local.cpp @@ -1422,6 +1422,9 @@ if (!GO->canIncreaseAlignment()) return CurrentAlign; + if (GO->isThreadLocal() && DL.exceedsMaxTLSAlign(PrefAlign)) + PrefAlign = Align(DL.getMaxTLSAlign()); + GO->setAlignment(PrefAlign); return PrefAlign; } Index: llvm/test/CodeGen/X86/tls-align.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/tls-align.ll @@ -0,0 +1,60 @@ +; REQUIRES: x86-registered-target +; RUN: opt -mtriple=x86_64-unknown \ +; RUN: --data-layout=e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128 \ +; RUN: -mattr=+avx,+avx2 -O3 -S < %s | FileCheck --check-prefixes=GENERIC %s +; RUN: opt -mtriple=x86_64-unknown \ +; RUN: --data-layout=e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128-T256 \ +; RUN: -mattr=+avx,+avx2 -O3 -S < %s | FileCheck --check-prefixes=PS %s + +; This test is mainly concerned about the loop vectorization pass, because it can promote +; alignments to a high value (64 bytes). For this reason the IR in this test is somewhat lengthy. + +%class.Arr = type <{ [160 x %class.Derived], i32, [4 x i8] }> +%class.Derived = type { %class.Base, ptr } +%class.Base = type { ptr } + +$_ZTV4Base = comdat any + +@array = hidden thread_local local_unnamed_addr global %class.Arr zeroinitializer, align 8 +; Make sure optimization passes (particularly the vectorizer) do not set the alignment +; of the TLS variable to something larger than the target allows. For the PS target this means +; that the alignment should not exceed 32 bytes. +; GENERIC: @array{{.*}}align 64 +; PS: @array{{.*}}align {{8|16|32}} + +@_ZTV4Base = linkonce_odr hidden unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr null, ptr @_ZN4BaseD2Ev, ptr @_ZN4BaseD0Ev] }, comdat, align 8 + +declare void @_ZN4BaseD2Ev() +declare void @_ZN4BaseD0Ev() + +define void @__cxx_global_var_init() local_unnamed_addr #0 { +entry: + br label %arrayctor.loop.i + +arrayctor.loop.i: + %arrayctor.cur.idx.i = phi i64 [ 0, %entry ], [ %arrayctor.cur.add.i, %arrayctor.loop.i ] + %arrayctor.cur.ptr.i = getelementptr inbounds %class.Derived, ptr @array, i64 %arrayctor.cur.idx.i + store ptr getelementptr inbounds ({ [4 x ptr] }, ptr @_ZTV4Base, i64 0, inrange i32 0, i64 2), ptr %arrayctor.cur.ptr.i, align 8 + %ptr.i.i = getelementptr inbounds %class.Derived, ptr @array, i64 %arrayctor.cur.idx.i, i32 1 + store ptr null, ptr %ptr.i.i, align 8 + %arrayctor.cur.add.i = add nuw nsw i64 %arrayctor.cur.idx.i, 1 + %arrayctor.done.i = icmp eq i64 %arrayctor.cur.add.i, 160 + br i1 %arrayctor.done.i, label %arrayctor.cont.i, label %arrayctor.loop.i + +arrayctor.cont.i: + store i32 160, ptr getelementptr inbounds (%class.Arr, ptr @array, i64 0, i32 1), align 8 + br label %for.body.i + +for.body.i: + %indvars.iv.i = phi i64 [ 0, %arrayctor.cont.i ], [ %indvars.iv.next.i, %for.body.i ] + %arrayidx.i = getelementptr inbounds [160 x %class.Derived], ptr @array, i64 0, i64 %indvars.iv.i + store ptr getelementptr inbounds ({ [4 x ptr] }, ptr @_ZTV4Base, i64 0, inrange i32 0, i64 2), ptr %arrayidx.i, align 8 + %ptr.i4.i = getelementptr inbounds [160 x %class.Derived], ptr @array, i64 0, i64 %indvars.iv.i, i32 1 + store ptr null, ptr %ptr.i4.i, align 8 + %indvars.iv.next.i = add nuw nsw i64 %indvars.iv.i, 1 + %exitcond.not.i = icmp eq i64 %indvars.iv.next.i, 160 + br i1 %exitcond.not.i, label %_ZN3ArrI7DerivedLi160EEC2Ei.exit, label %for.body.i + +_ZN3ArrI7DerivedLi160EEC2Ei.exit: + ret void +}