r242198 - Add a "maximum TLS alignment" characteristic to the target info, so it

Paul Robinson paul_robinson at playstation.sony.com
Tue Jul 14 13:52:32 PDT 2015


Author: probinson
Date: Tue Jul 14 15:52:32 2015
New Revision: 242198

URL: http://llvm.org/viewvc/llvm-project?rev=242198&view=rev
Log:
Add a "maximum TLS alignment" characteristic to the target info, so it
can be different from the normal variable maximum.
Add an error diagnostic for when TLS variables exceed maximum TLS alignment.
Currenty only PS4 sets an explicit maximum TLS alignment.

Patch by Charles Li!

Added:
    cfe/trunk/test/Sema/tls_alignment.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/TargetInfo.h
    cfe/trunk/lib/Basic/TargetInfo.cpp
    cfe/trunk/lib/Basic/Targets.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=242198&r1=242197&r2=242198&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jul 14 15:52:32 2015
@@ -2161,6 +2161,10 @@ def warn_objc_redundant_literal_use : Wa
 def err_attr_tlsmodel_arg : Error<"tls_model must be \"global-dynamic\", "
   "\"local-dynamic\", \"initial-exec\" or \"local-exec\"">;
 
+def err_tls_var_aligned_over_maximum : Error<
+  "alignment (%0) of thread-local variable %1 is greater than the maximum supported "
+  "alignment (%2) for a thread-local variable on this target">;
+
 def err_only_annotate_after_access_spec : Error<
   "access specifier can only have annotation attributes">;
 

Modified: cfe/trunk/include/clang/Basic/TargetInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TargetInfo.h?rev=242198&r1=242197&r2=242198&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TargetInfo.h (original)
+++ cfe/trunk/include/clang/Basic/TargetInfo.h Tue Jul 14 15:52:32 2015
@@ -70,6 +70,7 @@ protected:
   unsigned char MinGlobalAlign;
   unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth;
   unsigned short MaxVectorAlign;
+  unsigned short MaxTLSAlign;
   unsigned short SimdDefaultAlign;
   const char *DescriptionString;
   const char *UserLabelPrefix;
@@ -809,6 +810,14 @@ public:
     return TLSSupported;
   }
 
+  /// \brief Return the maximum alignment (in bits) of a TLS variable
+  ///
+  /// Gets the maximum alignment (in bits) of a TLS variable on this target.
+  /// Returns zero if there is no such constraint.
+  unsigned short getMaxTLSAlign() const {
+    return MaxTLSAlign;
+  }
+
   /// \brief Whether the target supports SEH __try.
   bool isSEHTrySupported() const {
     return getTriple().isOSWindows() &&

Modified: cfe/trunk/lib/Basic/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/TargetInfo.cpp?rev=242198&r1=242197&r2=242198&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/TargetInfo.cpp (original)
+++ cfe/trunk/lib/Basic/TargetInfo.cpp Tue Jul 14 15:52:32 2015
@@ -50,6 +50,7 @@ TargetInfo::TargetInfo(const llvm::Tripl
   LargeArrayAlign = 0;
   MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0;
   MaxVectorAlign = 0;
+  MaxTLSAlign = 0;
   SimdDefaultAlign = 0;
   SizeType = UnsignedLong;
   PtrDiffType = SignedLong;

Modified: cfe/trunk/lib/Basic/Targets.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Targets.cpp?rev=242198&r1=242197&r2=242198&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Targets.cpp (original)
+++ cfe/trunk/lib/Basic/Targets.cpp Tue Jul 14 15:52:32 2015
@@ -580,6 +580,8 @@ public:
   PS4OSTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
     this->WCharType = this->UnsignedShort;
 
+    // On PS4, TLS variable cannot be aligned to more than 32 bytes (256 bits).
+    this->MaxTLSAlign = 256;
     this->UserLabelPrefix = "";
 
     switch (Triple.getArch()) {

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=242198&r1=242197&r2=242198&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Jul 14 15:52:32 2015
@@ -9828,6 +9828,16 @@ void Sema::CheckCompleteVariableDeclarat
     FinalizeVarWithDestructor(var, recordType);
 }
 
+/// \brief Determines if a variable's alignment is dependent.
+static bool hasDependentAlignment(VarDecl *VD) {
+  if (VD->getType()->isDependentType())
+    return true;
+  for (auto *I : VD->specific_attrs<AlignedAttr>())
+    if (I->isAlignmentDependent())
+      return true;
+  return false;
+}
+
 /// FinalizeDeclaration - called by ParseDeclarationAfterDeclarator to perform
 /// any semantic actions necessary after any initializer has been attached.
 void
@@ -9841,6 +9851,22 @@ Sema::FinalizeDeclaration(Decl *ThisDecl
 
   checkAttributesAfterMerging(*this, *VD);
 
+  // Perform TLS alignment check here after attributes attached to the variable
+  // which may affect the alignment have been processed. Only perform the check
+  // if the target has a maximum TLS alignment (zero means no constraints).
+  if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) {
+    // Protect the check so that it's not performed on dependent types and
+    // dependent alignments (we can't determine the alignment in that case).
+    if (VD->getTLSKind() && !hasDependentAlignment(VD)) {
+      CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign);
+      if (Context.getDeclAlign(VD) > MaxAlignChars) {
+        Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum)
+          << (unsigned)Context.getDeclAlign(VD).getQuantity() << VD
+          << (unsigned)MaxAlignChars.getQuantity();
+      }
+    }
+  }
+
   // Static locals inherit dll attributes from their function.
   if (VD->isStaticLocal()) {
     if (FunctionDecl *FD =

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=242198&r1=242197&r2=242198&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Jul 14 15:52:32 2015
@@ -2985,11 +2985,27 @@ void Sema::AddAlignedAttr(SourceRange At
   //      specifier shall have no effect
   // C11 6.7.5p6:
   //   An alignment specification of zero has no effect.
-  if (!(TmpAttr.isAlignas() && !Alignment) &&
-      !llvm::isPowerOf2_64(Alignment.getZExtValue())) {
-    Diag(AttrLoc, diag::err_alignment_not_power_of_two)
-      << E->getSourceRange();
-    return;
+  if (!(TmpAttr.isAlignas() && !Alignment)) {
+    if(!llvm::isPowerOf2_64(Alignment.getZExtValue())) {
+      Diag(AttrLoc, diag::err_alignment_not_power_of_two)
+        << E->getSourceRange();
+      return;
+    }
+    if (Context.getTargetInfo().isTLSSupported()) {
+      if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) {
+        if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+          if (VD->getTLSKind()) {
+            CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign);
+            if (Alignment.getSExtValue() > MaxAlignChars.getQuantity()) {
+              Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum)
+                << (unsigned)Alignment.getZExtValue() << VD
+                << (unsigned)MaxAlignChars.getQuantity();
+              return;
+            }
+          }
+        }
+      }
+    }
   }
 
   // Alignment calculations can wrap around if it's greater than 2**28.

Added: cfe/trunk/test/Sema/tls_alignment.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/tls_alignment.cpp?rev=242198&view=auto
==============================================================================
--- cfe/trunk/test/Sema/tls_alignment.cpp (added)
+++ cfe/trunk/test/Sema/tls_alignment.cpp Tue Jul 14 15:52:32 2015
@@ -0,0 +1,75 @@
+// TLS variable cannot be aligned to more than 32 bytes on PS4.
+
+// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -verify %s
+
+
+// A non-aligned type.
+struct non_aligned_struct {
+    int some_data[16]; // 64 bytes of stuff, non aligned.
+};
+
+// An aligned type.
+struct __attribute__(( aligned(64) )) aligned_struct {
+    int some_data[12]; // 48 bytes of stuff, aligned to 64.
+};
+
+// A type with an aligned field.
+struct  struct_with_aligned_field {
+    int some_aligned_data[12] __attribute__(( aligned(64) )); // 48 bytes of stuff, aligned to 64.
+};
+
+// A typedef of the aligned struct.
+typedef aligned_struct another_aligned_struct;
+
+// A typedef to redefine a non-aligned struct as aligned.
+typedef __attribute__(( aligned(64) )) non_aligned_struct yet_another_aligned_struct;
+
+// Non aligned variable doesn't cause an error.
+__thread non_aligned_struct foo;
+
+// Variable aligned because of its type should cause an error.
+__thread aligned_struct                    bar; // expected-error{{alignment (64) of thread-local variable}}
+
+// Variable explicitly aligned in the declaration should cause an error.
+__thread non_aligned_struct                bar2 __attribute__(( aligned(64) )); // expected-error{{alignment (64) of thread-local variable}}
+
+// Variable aligned because of one of its fields should cause an error.
+__thread struct_with_aligned_field         bar3; // expected-error{{alignment (64) of thread-local variable}}
+
+// Variable aligned because of typedef, first case.
+__thread another_aligned_struct            bar4; // expected-error{{alignment (64) of thread-local variable}}
+
+// Variable aligned because of typedef, second case.
+__thread yet_another_aligned_struct        bar5; // expected-error{{alignment (64) of thread-local variable}}
+
+int baz ()
+{
+    return foo.some_data[0] + bar.some_data[1] + bar2.some_data[2] +
+           bar3.some_aligned_data[3] + bar4.some_data[4] +
+           bar5.some_data[5];
+}
+
+
+// Verify alignment check where a dependent type is involved.
+// The check is (correctly) not performed on "t", but the check still is
+// performed on the structure as a whole once it has been instantiated.
+
+template<class T> struct templated_tls {
+    static __thread T t;
+    T other_t __attribute__(( aligned(64) ));
+};
+__thread templated_tls<int> blah; // expected-error{{alignment (64) of thread-local variable}}
+
+int blag() {
+    return blah.other_t * 2;
+}
+
+
+// Verify alignment check where the alignment is a template parameter.
+// The check is only performed during instantiation.
+template <int N>
+struct S {
+  static int __thread __attribute__((aligned(N))) x; // expected-error{{alignment (64) of thread-local variable}}
+};
+
+S<64> s_instance; // expected-note{{in instantiation of template class 'S<64>' requested here}}





More information about the cfe-commits mailing list