diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 22ac5e431214e23139272589eb1a212341cda878..5488a5dc5e8ae07735b6b8dbb173432423a85613 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -4106,6 +4106,18 @@ s390_cannot_force_const_mem (machine_mode mode, rtx x)
       /* Accept all non-symbolic constants.  */
       return false;
 
+    case NEG:
+      /* Accept an unary '-' only on scalar numeric constants.  */
+      switch (GET_CODE (XEXP (x, 0)))
+	{
+	case CONST_INT:
+	case CONST_DOUBLE:
+	case CONST_WIDE_INT:
+	  return false;
+	default:
+	  return true;
+	}
+
     case LABEL_REF:
       /* Labels are OK iff we are non-PIC.  */
       return flag_pic != 0;
@@ -5268,6 +5280,7 @@ legitimize_tls_address (rtx addr, rtx reg)
     {
       switch (XINT (XEXP (addr, 0), 1))
 	{
+	case UNSPEC_NTPOFF:
 	case UNSPEC_INDNTPOFF:
 	  new_rtx = addr;
 	  break;
@@ -5290,6 +5303,18 @@ legitimize_tls_address (rtx addr, rtx reg)
       new_rtx = force_operand (new_rtx, 0);
     }
 
+  /* (const (neg (unspec (symbol_ref)))) -> (neg (const (unspec (symbol_ref)))) */
+  else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == NEG)
+    {
+      new_rtx = XEXP (XEXP (addr, 0), 0);
+      if (GET_CODE (new_rtx) != SYMBOL_REF)
+	new_rtx = gen_rtx_CONST (Pmode, new_rtx);
+
+      new_rtx = legitimize_tls_address (new_rtx, reg);
+      new_rtx = gen_rtx_NEG (Pmode, new_rtx);
+      new_rtx = force_operand (new_rtx, 0);
+    }
+
   else
     gcc_unreachable ();  /* for now ... */
 
diff --git a/gcc/testsuite/g++.dg/pr96308.C b/gcc/testsuite/g++.dg/pr96308.C
new file mode 100644
index 0000000000000000000000000000000000000000..9009bba5e8296f255d03a925f92bcda1d1ff6f9f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr96308.C
@@ -0,0 +1,7 @@
+// { dg-do compile }
+// { dg-options "-Os -fno-move-loop-invariants -std=c++11" }
+
+struct NonTrivial3 {
+  ~NonTrivial3();
+};
+void i() { thread_local NonTrivial3 tlarr[10]; }