Blame SOURCES/gcc48-rh1469697-14.patch

4dd737
commit 21397732bbcef3347c0d5ff8a0ee5163e803e2fb
4dd737
Author: Jeff Law <law@redhat.com>
4dd737
Date:   Mon Oct 2 12:30:26 2017 -0600
4dd737
4dd737
    Dependencies for aarch64 work
4dd737
4dd737
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
4dd737
index 07ff7031b35..91dd5b7fc02 100644
4dd737
--- a/gcc/config/aarch64/aarch64-protos.h
4dd737
+++ b/gcc/config/aarch64/aarch64-protos.h
4dd737
@@ -181,6 +181,7 @@ unsigned aarch64_dbx_register_number (unsigned);
4dd737
 unsigned aarch64_trampoline_size (void);
4dd737
 void aarch64_asm_output_labelref (FILE *, const char *);
4dd737
 void aarch64_elf_asm_named_section (const char *, unsigned, tree);
4dd737
+const char * aarch64_output_probe_stack_range (rtx, rtx);
4dd737
 void aarch64_expand_epilogue (bool);
4dd737
 void aarch64_expand_mov_immediate (rtx, rtx);
4dd737
 void aarch64_expand_prologue (void);
4dd737
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
4dd737
index 5afc167d569..cadf193cfcf 100644
4dd737
--- a/gcc/config/aarch64/aarch64.c
4dd737
+++ b/gcc/config/aarch64/aarch64.c
4dd737
@@ -969,6 +969,199 @@ aarch64_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
4dd737
   return true;
4dd737
 }
4dd737
 
4dd737
+static int
4dd737
+aarch64_internal_mov_immediate (rtx dest, rtx imm, bool generate,
4dd737
+				enum machine_mode mode)
4dd737
+{
4dd737
+  int i;
4dd737
+  unsigned HOST_WIDE_INT val, val2, mask;
4dd737
+  int one_match, zero_match;
4dd737
+  int num_insns;
4dd737
+
4dd737
+  val = INTVAL (imm);
4dd737
+
4dd737
+  if (aarch64_move_imm (val, mode))
4dd737
+    {
4dd737
+      if (generate)
4dd737
+	emit_insn (gen_rtx_SET (VOIDmode, dest, imm));
4dd737
+      return 1;
4dd737
+    }
4dd737
+
4dd737
+  /* Check to see if the low 32 bits are either 0xffffXXXX or 0xXXXXffff
4dd737
+     (with XXXX non-zero). In that case check to see if the move can be done in
4dd737
+     a smaller mode.  */
4dd737
+  val2 = val & 0xffffffff;
4dd737
+  if (mode == DImode
4dd737
+      && aarch64_move_imm (val2, SImode)
4dd737
+      && (((val >> 32) & 0xffff) == 0 || (val >> 48) == 0))
4dd737
+    {
4dd737
+      if (generate)
4dd737
+	emit_insn (gen_rtx_SET (VOIDmode, dest, GEN_INT (val2)));
4dd737
+
4dd737
+      /* Check if we have to emit a second instruction by checking to see
4dd737
+         if any of the upper 32 bits of the original DI mode value is set.  */
4dd737
+      if (val == val2)
4dd737
+	return 1;
4dd737
+
4dd737
+      i = (val >> 48) ? 48 : 32;
4dd737
+
4dd737
+      if (generate)
4dd737
+	 emit_insn (gen_insv_immdi (dest, GEN_INT (i),
4dd737
+				    GEN_INT ((val >> i) & 0xffff)));
4dd737
+
4dd737
+      return 2;
4dd737
+    }
4dd737
+
4dd737
+  if ((val >> 32) == 0 || mode == SImode)
4dd737
+    {
4dd737
+      if (generate)
4dd737
+	{
4dd737
+	  emit_insn (gen_rtx_SET (VOIDmode, dest, GEN_INT (val & 0xffff)));
4dd737
+	  if (mode == SImode)
4dd737
+	    emit_insn (gen_insv_immsi (dest, GEN_INT (16),
4dd737
+				       GEN_INT ((val >> 16) & 0xffff)));
4dd737
+	  else
4dd737
+	    emit_insn (gen_insv_immdi (dest, GEN_INT (16),
4dd737
+				       GEN_INT ((val >> 16) & 0xffff)));
4dd737
+	}
4dd737
+      return 2;
4dd737
+    }
4dd737
+
4dd737
+  /* Remaining cases are all for DImode.  */
4dd737
+
4dd737
+  mask = 0xffff;
4dd737
+  zero_match = ((val & mask) == 0) + ((val & (mask << 16)) == 0) +
4dd737
+    ((val & (mask << 32)) == 0) + ((val & (mask << 48)) == 0);
4dd737
+  one_match = ((~val & mask) == 0) + ((~val & (mask << 16)) == 0) +
4dd737
+    ((~val & (mask << 32)) == 0) + ((~val & (mask << 48)) == 0);
4dd737
+
4dd737
+  if (zero_match != 2 && one_match != 2)
4dd737
+    {
4dd737
+      /* Try emitting a bitmask immediate with a movk replacing 16 bits.
4dd737
+	 For a 64-bit bitmask try whether changing 16 bits to all ones or
4dd737
+	 zeroes creates a valid bitmask.  To check any repeated bitmask,
4dd737
+	 try using 16 bits from the other 32-bit half of val.  */
4dd737
+
4dd737
+      for (i = 0; i < 64; i += 16, mask <<= 16)
4dd737
+	{
4dd737
+	  val2 = val & ~mask;
4dd737
+	  if (val2 != val && aarch64_bitmask_imm (val2, mode))
4dd737
+	    break;
4dd737
+	  val2 = val | mask;
4dd737
+	  if (val2 != val && aarch64_bitmask_imm (val2, mode))
4dd737
+	    break;
4dd737
+	  val2 = val2 & ~mask;
4dd737
+	  val2 = val2 | (((val2 >> 32) | (val2 << 32)) & mask);
4dd737
+	  if (val2 != val && aarch64_bitmask_imm (val2, mode))
4dd737
+	    break;
4dd737
+	}
4dd737
+      if (i != 64)
4dd737
+	{
4dd737
+	  if (generate)
4dd737
+	    {
4dd737
+	      emit_insn (gen_rtx_SET (VOIDmode, dest, GEN_INT (val2)));
4dd737
+	      emit_insn (gen_insv_immdi (dest, GEN_INT (i),
4dd737
+					 GEN_INT ((val >> i) & 0xffff)));
4dd737
+	    }
4dd737
+	  return 2;
4dd737
+	}
4dd737
+    }
4dd737
+
4dd737
+  /* Generate 2-4 instructions, skipping 16 bits of all zeroes or ones which
4dd737
+     are emitted by the initial mov.  If one_match > zero_match, skip set bits,
4dd737
+     otherwise skip zero bits.  */
4dd737
+
4dd737
+  num_insns = 1;
4dd737
+  mask = 0xffff;
4dd737
+  val2 = one_match > zero_match ? ~val : val;
4dd737
+  i = (val2 & mask) != 0 ? 0 : (val2 & (mask << 16)) != 0 ? 16 : 32;
4dd737
+
4dd737
+  if (generate)
4dd737
+    emit_insn (gen_rtx_SET (VOIDmode, dest, GEN_INT (one_match > zero_match
4dd737
+					   ? (val | ~(mask << i))
4dd737
+					   : (val & (mask << i)))));
4dd737
+  for (i += 16; i < 64; i += 16)
4dd737
+    {
4dd737
+      if ((val2 & (mask << i)) == 0)
4dd737
+	continue;
4dd737
+      if (generate)
4dd737
+	emit_insn (gen_insv_immdi (dest, GEN_INT (i),
4dd737
+				   GEN_INT ((val >> i) & 0xffff)));
4dd737
+      num_insns ++;
4dd737
+    }
4dd737
+
4dd737
+  return num_insns;
4dd737
+}
4dd737
+
4dd737
+/* Add DELTA to REGNUM in mode MODE.  SCRATCHREG can be used to hold a
4dd737
+   temporary value if necessary.  FRAME_RELATED_P should be true if
4dd737
+   the RTX_FRAME_RELATED flag should be set and CFA adjustments added
4dd737
+   to the generated instructions.  If SCRATCHREG is known to hold
4dd737
+   abs (delta), EMIT_MOVE_IMM can be set to false to avoid emitting the
4dd737
+   immediate again.
4dd737
+
4dd737
+   Since this function may be used to adjust the stack pointer, we must
4dd737
+   ensure that it cannot cause transient stack deallocation (for example
4dd737
+   by first incrementing SP and then decrementing when adjusting by a
4dd737
+   large immediate).  */
4dd737
+
4dd737
+static void
4dd737
+aarch64_add_constant_internal (enum machine_mode mode, int regnum,
4dd737
+			       int scratchreg, HOST_WIDE_INT delta,
4dd737
+			       bool frame_related_p, bool emit_move_imm)
4dd737
+{
4dd737
+  HOST_WIDE_INT mdelta = abs_hwi (delta);
4dd737
+  rtx this_rtx = gen_rtx_REG (mode, regnum);
4dd737
+  rtx insn;
4dd737
+
4dd737
+  if (!mdelta)
4dd737
+    return;
4dd737
+
4dd737
+  /* Single instruction adjustment.  */
4dd737
+  if (aarch64_uimm12_shift (mdelta))
4dd737
+    {
4dd737
+      insn = emit_insn (gen_add2_insn (this_rtx, GEN_INT (delta)));
4dd737
+      RTX_FRAME_RELATED_P (insn) = frame_related_p;
4dd737
+      return;
4dd737
+    }
4dd737
+
4dd737
+  /* Emit 2 additions/subtractions if the adjustment is less than 24 bits.
4dd737
+     Only do this if mdelta is not a 16-bit move as adjusting using a move
4dd737
+     is better.  */
4dd737
+  if (mdelta < 0x1000000 && !aarch64_move_imm (mdelta, mode))
4dd737
+    {
4dd737
+      HOST_WIDE_INT low_off = mdelta & 0xfff;
4dd737
+
4dd737
+      low_off = delta < 0 ? -low_off : low_off;
4dd737
+      insn = emit_insn (gen_add2_insn (this_rtx, GEN_INT (low_off)));
4dd737
+      RTX_FRAME_RELATED_P (insn) = frame_related_p;
4dd737
+      insn = emit_insn (gen_add2_insn (this_rtx, GEN_INT (delta - low_off)));
4dd737
+      RTX_FRAME_RELATED_P (insn) = frame_related_p;
4dd737
+      return;
4dd737
+    }
4dd737
+
4dd737
+  /* Emit a move immediate if required and an addition/subtraction.  */
4dd737
+  rtx scratch_rtx = gen_rtx_REG (mode, scratchreg);
4dd737
+  if (emit_move_imm)
4dd737
+    aarch64_internal_mov_immediate (scratch_rtx, GEN_INT (mdelta), true, mode);
4dd737
+  insn = emit_insn (delta < 0 ? gen_sub2_insn (this_rtx, scratch_rtx)
4dd737
+			      : gen_add2_insn (this_rtx, scratch_rtx));
4dd737
+  if (frame_related_p)
4dd737
+    {
4dd737
+      RTX_FRAME_RELATED_P (insn) = frame_related_p;
4dd737
+      rtx adj = plus_constant (mode, this_rtx, delta);
4dd737
+      add_reg_note (insn , REG_CFA_ADJUST_CFA,
4dd737
+		    gen_rtx_SET (VOIDmode, this_rtx, adj));
4dd737
+    }
4dd737
+}
4dd737
+
4dd737
+static inline void
4dd737
+aarch64_sub_sp (int scratchreg, HOST_WIDE_INT delta, bool frame_related_p)
4dd737
+{
4dd737
+  aarch64_add_constant_internal (Pmode, SP_REGNUM, scratchreg, -delta,
4dd737
+				 frame_related_p, true);
4dd737
+}
4dd737
+
4dd737
 /* Implement TARGET_PASS_BY_REFERENCE.  */
4dd737
 
4dd737
 static bool
4dd737
@@ -1476,6 +1669,47 @@ aarch64_libgcc_cmp_return_mode (void)
4dd737
   return SImode;
4dd737
 }
4dd737
 
4dd737
+#define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP)
4dd737
+
4dd737
+/* We use the 12-bit shifted immediate arithmetic instructions so values
4dd737
+   must be multiple of (1 << 12), i.e. 4096.  */
4dd737
+#define ARITH_FACTOR 4096
4dd737
+
4dd737
+/* Probe a range of stack addresses from REG1 to REG2 inclusive.  These are
4dd737
+   absolute addresses.  */
4dd737
+
4dd737
+const char *
4dd737
+aarch64_output_probe_stack_range (rtx reg1, rtx reg2)
4dd737
+{
4dd737
+  static int labelno = 0;
4dd737
+  char loop_lab[32];
4dd737
+  rtx xops[2];
4dd737
+
4dd737
+  ASM_GENERATE_INTERNAL_LABEL (loop_lab, "LPSRL", labelno++);
4dd737
+
4dd737
+  /* Loop.  */
4dd737
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, loop_lab);
4dd737
+
4dd737
+  /* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL.  */
4dd737
+  xops[0] = reg1;
4dd737
+  xops[1] = GEN_INT (PROBE_INTERVAL);
4dd737
+  output_asm_insn ("sub\t%0, %0, %1", xops);
4dd737
+
4dd737
+  /* Probe at TEST_ADDR.  */
4dd737
+  output_asm_insn ("str\txzr, [%0]", xops);
4dd737
+
4dd737
+  /* Test if TEST_ADDR == LAST_ADDR.  */
4dd737
+  xops[1] = reg2;
4dd737
+  output_asm_insn ("cmp\t%0, %1", xops);
4dd737
+
4dd737
+  /* Branch.  */
4dd737
+  fputs ("\tb.ne\t", asm_out_file);
4dd737
+  assemble_name_raw (asm_out_file, loop_lab);
4dd737
+  fputc ('\n', asm_out_file);
4dd737
+
4dd737
+  return "";
4dd737
+}
4dd737
+
4dd737
 static bool
4dd737
 aarch64_frame_pointer_required (void)
4dd737
 {
4dd737
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
4dd737
index 91299901bbf..17082486ac8 100644
4dd737
--- a/gcc/config/aarch64/aarch64.md
4dd737
+++ b/gcc/config/aarch64/aarch64.md
4dd737
@@ -88,6 +88,7 @@
4dd737
     UNSPEC_ST4
4dd737
     UNSPEC_TLS
4dd737
     UNSPEC_TLSDESC
4dd737
+    UNSPECV_PROBE_STACK_RANGE   ; Represent stack range probing.
4dd737
     UNSPEC_VSTRUCTDUMMY
4dd737
 ])
4dd737
 
4dd737
@@ -3399,6 +3400,18 @@
4dd737
   [(set_attr "length" "0")]
4dd737
 )
4dd737
 
4dd737
+(define_insn "probe_stack_range"
4dd737
+  [(set (match_operand:DI 0 "register_operand" "=r")
4dd737
+	(unspec_volatile:DI [(match_operand:DI 1 "register_operand" "0")
4dd737
+			     (match_operand:DI 2 "register_operand" "r")]
4dd737
+			      UNSPECV_PROBE_STACK_RANGE))]
4dd737
+  ""
4dd737
+{
4dd737
+  return aarch64_output_probe_stack_range (operands[0], operands[2]);
4dd737
+}
4dd737
+  [(set_attr "length" "32")]
4dd737
+)
4dd737
+
4dd737
 ;; Named pattern for expanding thread pointer reference.
4dd737
 (define_expand "get_thread_pointerdi"
4dd737
   [(match_operand:DI 0 "register_operand" "=r")]