diff --git include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/DiagnosticSemaKinds.td
index 71cba01..52771df 100644
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2140,6 +2140,10 @@ def warn_objc_redundant_literal_use : Warning<
 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">;
 
diff --git include/clang/Basic/TargetInfo.h include/clang/Basic/TargetInfo.h
index e415733..48b07c7 100644
--- include/clang/Basic/TargetInfo.h
+++ include/clang/Basic/TargetInfo.h
@@ -70,6 +70,7 @@ protected:
   unsigned char MinGlobalAlign;
   unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth;
   unsigned short MaxVectorAlign;
+  unsigned short MaxTLSAlign;
   const char *DescriptionString;
   const char *UserLabelPrefix;
   const char *MCountName;
@@ -801,6 +802,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 Return true if {|} are normal characters in the asm string.
   ///
   /// If this returns false (the default), then {abc|xyz} is syntax
diff --git lib/Basic/TargetInfo.cpp lib/Basic/TargetInfo.cpp
index 330258b..159172c 100644
--- lib/Basic/TargetInfo.cpp
+++ lib/Basic/TargetInfo.cpp
@@ -50,6 +50,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
   LargeArrayAlign = 0;
   MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0;
   MaxVectorAlign = 0;
+  MaxTLSAlign = 0;
   SizeType = UnsignedLong;
   PtrDiffType = SignedLong;
   IntMaxType = SignedLongLong;
diff --git lib/Basic/Targets.cpp lib/Basic/Targets.cpp
index 8975c91..6fab336 100644
--- lib/Basic/Targets.cpp
+++ lib/Basic/Targets.cpp
@@ -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()) {
diff --git lib/Sema/SemaDecl.cpp lib/Sema/SemaDecl.cpp
index 347d807..93ac643 100644
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -9736,6 +9736,17 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
     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
@@ -9749,6 +9760,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 (const 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)) {
+      const 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 =
diff --git lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaDeclAttr.cpp
index ab3e0ab..94f72b7 100644
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -2984,11 +2984,27 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
   //      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 (const unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) {
+        if ( VarDecl *VD = dyn_cast<VarDecl>(D) ) {
+          if ( VD->getTLSKind() ) {
+            const 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.
diff --git test/Sema/tls_alignment.cpp test/Sema/tls_alignment.cpp
new file mode 100644
index 0000000..5a7bb2c
--- /dev/null
+++ test/Sema/tls_alignment.cpp
@@ -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}}
