Blame SOURCES/gcc48-rh1469697-9.patch

4dd737
commit b49f8fb8a97e9af8e6ba2b65d18195099cd1bb79
4dd737
Author: law <law@138bc75d-0d04-0410-961f-82ee72b054a4>
4dd737
Date:   Thu Sep 21 04:30:16 2017 +0000
4dd737
4dd737
            * config/s390/s390.c (MIN_UNROLL_PROBES): Define.
4dd737
            (allocate_stack_space): New function, partially extracted from
4dd737
            s390_emit_prologue.
4dd737
            (s390_emit_prologue): Track offset to most recent stack probe.
4dd737
            Code to allocate space moved into allocate_stack_space.
4dd737
            Dump actions when no stack is allocated.
4dd737
            (s390_prologue_plus_offset): New function.
4dd737
            (s390_emit_stack_probe): Likewise.
4dd737
    
4dd737
            * gcc.dg/stack-check-5.c:  Add argument for s390.
4dd737
            * lib/target-supports.exp:
4dd737
            (check_effective_target_supports_stack_clash_protection): Enable for
4dd737
            s390/s390x targets.
4dd737
    
4dd737
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@253049 138bc75d-0d04-0410-961f-82ee72b054a4
4dd737
4dd737
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
4dd737
index 3c04781f947..45998bc7516 100644
4dd737
--- a/gcc/config/s390/s390.c
4dd737
+++ b/gcc/config/s390/s390.c
4dd737
@@ -10350,6 +10350,184 @@ s390_emit_stack_tie (void)
4dd737
   emit_insn (gen_stack_tie (mem));
4dd737
 }
4dd737
 
4dd737
+/* Calculate TARGET = REG + OFFSET as s390_emit_prologue would do it.
4dd737
+   - push too big immediates to the literal pool and annotate the refs
4dd737
+   - emit frame related notes for stack pointer changes.  */
4dd737
+
4dd737
+static rtx
4dd737
+s390_prologue_plus_offset (rtx target, rtx reg, rtx offset, bool frame_related_p)
4dd737
+{
4dd737
+  rtx insn;
4dd737
+  rtx orig_offset = offset;
4dd737
+
4dd737
+  gcc_assert (REG_P (target));
4dd737
+  gcc_assert (REG_P (reg));
4dd737
+  gcc_assert (CONST_INT_P (offset));
4dd737
+
4dd737
+  if (offset == const0_rtx)                               /* lr/lgr */
4dd737
+    {
4dd737
+      insn = emit_move_insn (target, reg);
4dd737
+    }
4dd737
+  else if (DISP_IN_RANGE (INTVAL (offset)))               /* la */
4dd737
+    {
4dd737
+      insn = emit_move_insn (target, gen_rtx_PLUS (Pmode, reg,
4dd737
+						   offset));
4dd737
+    }
4dd737
+  else
4dd737
+    {
4dd737
+      if (!satisfies_constraint_K (offset)                /* ahi/aghi */
4dd737
+	  && (!TARGET_EXTIMM
4dd737
+	      || (!satisfies_constraint_Op (offset)       /* alfi/algfi */
4dd737
+		  && !satisfies_constraint_On (offset)))) /* slfi/slgfi */
4dd737
+	offset = force_const_mem (Pmode, offset);
4dd737
+
4dd737
+      if (target != reg)
4dd737
+	{
4dd737
+	  insn = emit_move_insn (target, reg);
4dd737
+	  RTX_FRAME_RELATED_P (insn) = frame_related_p ? 1 : 0;
4dd737
+	}
4dd737
+
4dd737
+      insn = emit_insn (gen_add2_insn (target, offset));
4dd737
+
4dd737
+      if (!CONST_INT_P (offset))
4dd737
+	{
4dd737
+	  annotate_constant_pool_refs (&PATTERN (insn));
4dd737
+
4dd737
+	  if (frame_related_p)
4dd737
+	    add_reg_note (insn, REG_FRAME_RELATED_EXPR,
4dd737
+			  gen_rtx_SET (VOIDmode, target,
4dd737
+				       gen_rtx_PLUS (Pmode, target,
4dd737
+						     orig_offset)));
4dd737
+	}
4dd737
+    }
4dd737
+
4dd737
+  RTX_FRAME_RELATED_P (insn) = frame_related_p ? 1 : 0;
4dd737
+
4dd737
+  /* If this is a stack adjustment and we are generating a stack clash
4dd737
+     prologue, then add a REG_STACK_CHECK note to signal that this insn
4dd737
+     should be left alone.  */
4dd737
+  if (flag_stack_clash_protection && target == stack_pointer_rtx)
4dd737
+    add_reg_note (insn, REG_STACK_CHECK, const0_rtx);
4dd737
+
4dd737
+  return insn;
4dd737
+}
4dd737
+
4dd737
+/* Emit a compare instruction with a volatile memory access as stack
4dd737
+   probe.  It does not waste store tags and does not clobber any
4dd737
+   registers apart from the condition code.  */
4dd737
+static void
4dd737
+s390_emit_stack_probe (rtx addr)
4dd737
+{
4dd737
+  rtx tmp = gen_rtx_MEM (Pmode, addr);
4dd737
+  MEM_VOLATILE_P (tmp) = 1;
4dd737
+  s390_emit_compare (EQ, gen_rtx_REG (Pmode, 0), tmp);
4dd737
+  emit_insn (gen_blockage ());
4dd737
+}
4dd737
+
4dd737
+/* Use a runtime loop if we have to emit more probes than this.  */
4dd737
+#define MIN_UNROLL_PROBES 3
4dd737
+
4dd737
+/* Allocate SIZE bytes of stack space, using TEMP_REG as a temporary
4dd737
+   if necessary.  LAST_PROBE_OFFSET contains the offset of the closest
4dd737
+   probe relative to the stack pointer.
4dd737
+
4dd737
+   Note that SIZE is negative.
4dd737
+
4dd737
+   The return value is true if TEMP_REG has been clobbered.  */
4dd737
+static bool
4dd737
+allocate_stack_space (rtx size, HOST_WIDE_INT last_probe_offset,
4dd737
+		      rtx temp_reg)
4dd737
+{
4dd737
+  bool temp_reg_clobbered_p = false;
4dd737
+  HOST_WIDE_INT probe_interval
4dd737
+    = 1 << PARAM_VALUE (PARAM_STACK_CLASH_PROTECTION_PROBE_INTERVAL);
4dd737
+  HOST_WIDE_INT guard_size
4dd737
+    = 1 << PARAM_VALUE (PARAM_STACK_CLASH_PROTECTION_GUARD_SIZE);
4dd737
+
4dd737
+  if (flag_stack_clash_protection)
4dd737
+    {
4dd737
+      if (last_probe_offset + -INTVAL (size) < guard_size)
4dd737
+	dump_stack_clash_frame_info (NO_PROBE_SMALL_FRAME, true);
4dd737
+      else
4dd737
+	{
4dd737
+	  rtx offset = GEN_INT (probe_interval - UNITS_PER_LONG);
4dd737
+	  HOST_WIDE_INT rounded_size = -INTVAL (size) & -probe_interval;
4dd737
+	  HOST_WIDE_INT num_probes = rounded_size / probe_interval;
4dd737
+	  HOST_WIDE_INT residual = -INTVAL (size) - rounded_size;
4dd737
+
4dd737
+	  if (num_probes < MIN_UNROLL_PROBES)
4dd737
+	    {
4dd737
+	      /* Emit unrolled probe statements.  */
4dd737
+
4dd737
+	      for (unsigned int i = 0; i < num_probes; i++)
4dd737
+		{
4dd737
+		  s390_prologue_plus_offset (stack_pointer_rtx,
4dd737
+					     stack_pointer_rtx,
4dd737
+					     GEN_INT (-probe_interval), true);
4dd737
+		  s390_emit_stack_probe (gen_rtx_PLUS (Pmode,
4dd737
+						       stack_pointer_rtx,
4dd737
+						       offset));
4dd737
+		}
4dd737
+	      dump_stack_clash_frame_info (PROBE_INLINE, residual != 0);
4dd737
+	    }
4dd737
+	  else
4dd737
+	    {
4dd737
+	      /* Emit a loop probing the pages.  */
4dd737
+
4dd737
+	      rtx loop_start_label = gen_label_rtx ();
4dd737
+
4dd737
+	      /* From now on temp_reg will be the CFA register.  */
4dd737
+	      s390_prologue_plus_offset (temp_reg, stack_pointer_rtx,
4dd737
+					 GEN_INT (-rounded_size), true);
4dd737
+	      emit_label (loop_start_label);
4dd737
+
4dd737
+	      s390_prologue_plus_offset (stack_pointer_rtx,
4dd737
+					 stack_pointer_rtx,
4dd737
+					 GEN_INT (-probe_interval), false);
4dd737
+	      s390_emit_stack_probe (gen_rtx_PLUS (Pmode,
4dd737
+						   stack_pointer_rtx,
4dd737
+						   offset));
4dd737
+	      emit_cmp_and_jump_insns (stack_pointer_rtx, temp_reg,
4dd737
+				       GT, NULL_RTX,
4dd737
+				       Pmode, 1, loop_start_label);
4dd737
+
4dd737
+	      /* Without this make_edges ICEes.  */
4dd737
+	      JUMP_LABEL (get_last_insn ()) = loop_start_label;
4dd737
+	      LABEL_NUSES (loop_start_label) = 1;
4dd737
+
4dd737
+	      /* That's going to be a NOP since stack pointer and
4dd737
+		 temp_reg are supposed to be the same here.  We just
4dd737
+		 emit it to set the CFA reg back to r15.  */
4dd737
+	      s390_prologue_plus_offset (stack_pointer_rtx, temp_reg,
4dd737
+					 const0_rtx, true);
4dd737
+	      temp_reg_clobbered_p = true;
4dd737
+	      dump_stack_clash_frame_info (PROBE_LOOP, residual != 0);
4dd737
+	    }
4dd737
+
4dd737
+	  /* Handle any residual allocation request.  */
4dd737
+	  s390_prologue_plus_offset (stack_pointer_rtx,
4dd737
+				     stack_pointer_rtx,
4dd737
+				     GEN_INT (-residual), true);
4dd737
+	  last_probe_offset += residual;
4dd737
+	  if (last_probe_offset >= probe_interval)
4dd737
+	    s390_emit_stack_probe (gen_rtx_PLUS (Pmode,
4dd737
+						 stack_pointer_rtx,
4dd737
+						 GEN_INT (residual
4dd737
+							  - UNITS_PER_LONG)));
4dd737
+
4dd737
+	  return temp_reg_clobbered_p;
4dd737
+	}
4dd737
+    }
4dd737
+
4dd737
+  /* Subtract frame size from stack pointer.  */
4dd737
+  s390_prologue_plus_offset (stack_pointer_rtx,
4dd737
+			     stack_pointer_rtx,
4dd737
+			     size, true);
4dd737
+
4dd737
+  return temp_reg_clobbered_p;
4dd737
+}
4dd737
+
4dd737
+
4dd737
 /* Expand the prologue into a bunch of separate insns.  */
4dd737
 
4dd737
 void
4dd737
@@ -10391,6 +10569,19 @@ s390_emit_prologue (void)
4dd737
   else
4dd737
     temp_reg = gen_rtx_REG (Pmode, 1);
4dd737
 
4dd737
+  /* When probing for stack-clash mitigation, we have to track the distance
4dd737
+     between the stack pointer and closest known reference.
4dd737
+
4dd737
+     Most of the time we have to make a worst cast assumption.  The
4dd737
+     only exception is when TARGET_BACKCHAIN is active, in which case
4dd737
+     we know *sp (offset 0) was written.  */
4dd737
+  HOST_WIDE_INT probe_interval
4dd737
+    = 1 << PARAM_VALUE (PARAM_STACK_CLASH_PROTECTION_PROBE_INTERVAL);
4dd737
+  HOST_WIDE_INT last_probe_offset
4dd737
+    = (TARGET_BACKCHAIN
4dd737
+       ? (TARGET_PACKED_STACK ? STACK_POINTER_OFFSET - UNITS_PER_LONG : 0)
4dd737
+       : probe_interval - (STACK_BOUNDARY / UNITS_PER_WORD));
4dd737
+
4dd737
   /* Save call saved gprs.  */
4dd737
   if (cfun_frame_layout.first_save_gpr != -1)
4dd737
     {
4dd737
@@ -10400,6 +10591,14 @@ s390_emit_prologue (void)
4dd737
 					  - cfun_frame_layout.first_save_gpr_slot),
4dd737
 			cfun_frame_layout.first_save_gpr,
4dd737
 			cfun_frame_layout.last_save_gpr);
4dd737
+
4dd737
+      /* This is not 100% correct.  If we have more than one register saved,
4dd737
+	 then LAST_PROBE_OFFSET can move even closer to sp.  */
4dd737
+      last_probe_offset
4dd737
+	= (cfun_frame_layout.gprs_offset +
4dd737
+	   UNITS_PER_LONG * (cfun_frame_layout.first_save_gpr
4dd737
+			     - cfun_frame_layout.first_save_gpr_slot));
4dd737
+
4dd737
       emit_insn (insn);
4dd737
     }
4dd737
 
4dd737
@@ -10416,6 +10615,8 @@ s390_emit_prologue (void)
4dd737
       if (cfun_fpr_bit_p (i))
4dd737
 	{
4dd737
 	  save_fpr (stack_pointer_rtx, offset, i + 16);
4dd737
+	  if (offset < last_probe_offset)
4dd737
+	    last_probe_offset = offset;
4dd737
 	  offset += 8;
4dd737
 	}
4dd737
       else if (!TARGET_PACKED_STACK)
4dd737
@@ -10429,6 +10630,8 @@ s390_emit_prologue (void)
4dd737
       if (cfun_fpr_bit_p (i))
4dd737
 	{
4dd737
 	  insn = save_fpr (stack_pointer_rtx, offset, i + 16);
4dd737
+	  if (offset < last_probe_offset)
4dd737
+	    last_probe_offset = offset;
4dd737
 	  offset += 8;
4dd737
 
4dd737
 	  /* If f4 and f6 are call clobbered they are saved due to stdargs and
4dd737
@@ -10451,6 +10654,8 @@ s390_emit_prologue (void)
4dd737
 	if (cfun_fpr_bit_p (i))
4dd737
 	  {
4dd737
 	    insn = save_fpr (stack_pointer_rtx, offset, i + 16);
4dd737
+	    if (offset < last_probe_offset)
4dd737
+	      last_probe_offset = offset;
4dd737
 
4dd737
 	    RTX_FRAME_RELATED_P (insn) = 1;
4dd737
 	    offset -= 8;
4dd737
@@ -10470,10 +10675,11 @@ s390_emit_prologue (void)
4dd737
   if (cfun_frame_layout.frame_size > 0)
4dd737
     {
4dd737
       rtx frame_off = GEN_INT (-cfun_frame_layout.frame_size);
4dd737
-      rtx real_frame_off;
4dd737
+      rtx stack_pointer_backup_loc;
4dd737
+      bool temp_reg_clobbered_p;
4dd737
 
4dd737
       if (s390_stack_size)
4dd737
-  	{
4dd737
+	{
4dd737
 	  HOST_WIDE_INT stack_guard;
4dd737
 
4dd737
 	  if (s390_stack_guard)
4dd737
@@ -10538,35 +10744,36 @@ s390_emit_prologue (void)
4dd737
       if (s390_warn_dynamicstack_p && cfun->calls_alloca)
4dd737
 	warning (0, "%qs uses dynamic stack allocation", current_function_name ());
4dd737
 
4dd737
-      /* Save incoming stack pointer into temp reg.  */
4dd737
-      if (TARGET_BACKCHAIN || next_fpr)
4dd737
-	insn = emit_insn (gen_move_insn (temp_reg, stack_pointer_rtx));
4dd737
+      /* Save the location where we could backup the incoming stack
4dd737
+	 pointer.  */
4dd737
+      stack_pointer_backup_loc = get_last_insn ();
4dd737
 
4dd737
-      /* Subtract frame size from stack pointer.  */
4dd737
+      temp_reg_clobbered_p = allocate_stack_space (frame_off, last_probe_offset,
4dd737
+						   temp_reg);
4dd737
 
4dd737
-      if (DISP_IN_RANGE (INTVAL (frame_off)))
4dd737
-	{
4dd737
-	  insn = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
4dd737
-			      gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4dd737
-					    frame_off));
4dd737
-	  insn = emit_insn (insn);
4dd737
-	}
4dd737
-      else
4dd737
+      if (TARGET_BACKCHAIN || next_fpr)
4dd737
 	{
4dd737
-	  if (!CONST_OK_FOR_K (INTVAL (frame_off)))
4dd737
-	    frame_off = force_const_mem (Pmode, frame_off);
4dd737
-
4dd737
-          insn = emit_insn (gen_add2_insn (stack_pointer_rtx, frame_off));
4dd737
-	  annotate_constant_pool_refs (&PATTERN (insn));
4dd737
+	  if (temp_reg_clobbered_p)
4dd737
+	    {
4dd737
+	      /* allocate_stack_space had to make use of temp_reg and
4dd737
+		 we need it to hold a backup of the incoming stack
4dd737
+		 pointer.  Calculate back that value from the current
4dd737
+		 stack pointer.  */
4dd737
+	      s390_prologue_plus_offset (temp_reg, stack_pointer_rtx,
4dd737
+					 GEN_INT (cfun_frame_layout.frame_size),
4dd737
+					 false);
4dd737
+	    }
4dd737
+	  else
4dd737
+	    {
4dd737
+	      /* allocate_stack_space didn't actually required
4dd737
+		 temp_reg.  Insert the stack pointer backup insn
4dd737
+		 before the stack pointer decrement code - knowing now
4dd737
+		 that the value will survive.  */
4dd737
+	      emit_insn_after (gen_move_insn (temp_reg, stack_pointer_rtx),
4dd737
+			       stack_pointer_backup_loc);
4dd737
+	    }
4dd737
 	}
4dd737
 
4dd737
-      RTX_FRAME_RELATED_P (insn) = 1;
4dd737
-      real_frame_off = GEN_INT (-cfun_frame_layout.frame_size);
4dd737
-      add_reg_note (insn, REG_FRAME_RELATED_EXPR,
4dd737
-		    gen_rtx_SET (VOIDmode, stack_pointer_rtx,
4dd737
-				 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4dd737
-					       real_frame_off)));
4dd737
-
4dd737
       /* Set backchain.  */
4dd737
 
4dd737
       if (TARGET_BACKCHAIN)
4dd737
@@ -10590,6 +10797,8 @@ s390_emit_prologue (void)
4dd737
 	  emit_clobber (addr);
4dd737
 	}
4dd737
     }
4dd737
+  else if (flag_stack_clash_protection)
4dd737
+    dump_stack_clash_frame_info (NO_PROBE_NO_FRAME, false);
4dd737
 
4dd737
   /* Save fprs 8 - 15 (64 bit ABI).  */
4dd737
 
4dd737
diff --git a/gcc/testsuite/gcc.dg/stack-check-5.c b/gcc/testsuite/gcc.dg/stack-check-5.c
4dd737
index 2171d9b6c23..3178f5d8ce5 100644
4dd737
--- a/gcc/testsuite/gcc.dg/stack-check-5.c
4dd737
+++ b/gcc/testsuite/gcc.dg/stack-check-5.c
4dd737
@@ -3,6 +3,10 @@
4dd737
 /* { dg-require-effective-target supports_stack_clash_protection } */
4dd737
 
4dd737
 
4dd737
+/* Otherwise the S/390 back-end might save the stack pointer in f2 ()
4dd737
+   into an FPR.  */
4dd737
+/* { dg-additional-options "-msoft-float" { target { s390x-*-* } } } */
4dd737
+
4dd737
 extern void foo (char *);
4dd737
 extern void bar (void);
4dd737
 
4dd737
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
4dd737
index 2c669a9822f..f24c5c6e0ac 100644
4dd737
--- a/gcc/testsuite/lib/target-supports.exp
4dd737
+++ b/gcc/testsuite/lib/target-supports.exp
4dd737
@@ -5422,12 +5422,12 @@ proc check_effective_target_supports_stack_clash_protection { } {
4dd737
 
4dd737
    # Temporary until the target bits are fully ACK'd.
4dd737
 #  if { [istarget aarch*-*-*]
4dd737
-#       || [istarget s390*-*-*]
4dd737
 #       || [istarget powerpc*-*-*] || [istarget rs6000*-*-*] } {
4dd737
 #	return 1
4dd737
 #  }
4dd737
 
4dd737
-    if { [istarget x86_64-*-*] || [istarget i?86-*-*] } {
4dd737
+    if { [istarget x86_64-*-*] || [istarget i?86-*-*] 
4dd737
+	  || [istarget s390*-*-*] } {
4dd737
 	return 1
4dd737
     }
4dd737
   return 0