public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH v2 2/7] Generation support for CLOBBER_HIGH
  2018-07-26  9:14 [PATCH v2 0/7] Support partial clobbers around TLS calls on Aarch64 SVE Alan Hayward
  2018-07-26  9:14 ` [PATCH v2 4/7] lra support for clobber_high Alan Hayward
@ 2018-07-26  9:14 ` Alan Hayward
  2018-08-04  4:09   ` Jeff Law
  2018-07-26  9:14 ` [PATCH v2 6/7] Remaining support for clobber high Alan Hayward
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Alan Hayward @ 2018-07-26  9:14 UTC (permalink / raw)
  To: gcc-patches; +Cc: nd, Alan Hayward

Ensure clobber high is a register expression.
Info is passed through for the error case.

2018-07-25  Alan Hayward  <alan.hayward@arm.com>

	* emit-rtl.c (verify_rtx_sharing): Check for CLOBBER_HIGH.
	(copy_insn_1): Likewise.
	(gen_hard_reg_clobber_high): New gen function.
	* genconfig.c (walk_insn_part): Check for CLOBBER_HIGH.
	* genemit.c (gen_exp): Likewise.
	(gen_emit_seq): Pass through info.
	(gen_insn): Check for CLOBBER_HIGH.
	(gen_expand): Pass through info.
	(gen_split): Likewise.
	(output_add_clobbers): Likewise.
	* genrecog.c (validate_pattern): Check for CLOBBER_HIGH.
	(remove_clobbers): Likewise.
	* rtl.h (gen_hard_reg_clobber_high): New declaration.
---
 gcc/emit-rtl.c  | 16 ++++++++++++++++
 gcc/genconfig.c |  1 +
 gcc/genemit.c   | 51 +++++++++++++++++++++++++++++++--------------------
 gcc/genrecog.c  |  3 ++-
 gcc/rtl.h       |  1 +
 5 files changed, 51 insertions(+), 21 deletions(-)

diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index e4b070486e8..6a32bcbdaf6 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -2865,6 +2865,7 @@ verify_rtx_sharing (rtx orig, rtx insn)
       /* SCRATCH must be shared because they represent distinct values.  */
       return;
     case CLOBBER:
+    case CLOBBER_HIGH:
       /* Share clobbers of hard registers (like cc0), but do not share pseudo reg
          clobbers or clobbers of hard registers that originated as pseudos.
          This is needed to allow safe register renaming.  */
@@ -3118,6 +3119,7 @@ repeat:
       /* SCRATCH must be shared because they represent distinct values.  */
       return;
     case CLOBBER:
+    case CLOBBER_HIGH:
       /* Share clobbers of hard registers (like cc0), but do not share pseudo reg
          clobbers or clobbers of hard registers that originated as pseudos.
          This is needed to allow safe register renaming.  */
@@ -5690,6 +5692,7 @@ copy_insn_1 (rtx orig)
     case SIMPLE_RETURN:
       return orig;
     case CLOBBER:
+    case CLOBBER_HIGH:
       /* Share clobbers of hard registers (like cc0), but do not share pseudo reg
          clobbers or clobbers of hard registers that originated as pseudos.
          This is needed to allow safe register renaming.  */
@@ -6508,6 +6511,19 @@ gen_hard_reg_clobber (machine_mode mode, unsigned int regno)
 	    gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (mode, regno)));
 }
 
+static GTY((deletable)) rtx
+hard_reg_clobbers_high[NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER];
+
+rtx
+gen_hard_reg_clobber_high (machine_mode mode, unsigned int regno)
+{
+  if (hard_reg_clobbers_high[mode][regno])
+    return hard_reg_clobbers_high[mode][regno];
+  else
+    return (hard_reg_clobbers_high[mode][regno]
+	    = gen_rtx_CLOBBER_HIGH (VOIDmode, gen_rtx_REG (mode, regno)));
+}
+
 location_t prologue_location;
 location_t epilogue_location;
 
diff --git a/gcc/genconfig.c b/gcc/genconfig.c
index c1bfde8d54b..745d5374b39 100644
--- a/gcc/genconfig.c
+++ b/gcc/genconfig.c
@@ -72,6 +72,7 @@ walk_insn_part (rtx part, int recog_p, int non_pc_set_src)
   switch (code)
     {
     case CLOBBER:
+    case CLOBBER_HIGH:
       clobbers_seen_this_insn++;
       break;
 
diff --git a/gcc/genemit.c b/gcc/genemit.c
index f4179e2b631..86e792f7396 100644
--- a/gcc/genemit.c
+++ b/gcc/genemit.c
@@ -79,7 +79,7 @@ gen_rtx_scratch (rtx x, enum rtx_code subroutine_type)
    substituting any operand references appearing within.  */
 
 static void
-gen_exp (rtx x, enum rtx_code subroutine_type, char *used)
+gen_exp (rtx x, enum rtx_code subroutine_type, char *used, md_rtx_info *info)
 {
   RTX_CODE code;
   int i;
@@ -123,7 +123,7 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used)
       for (i = 0; i < XVECLEN (x, 1); i++)
 	{
 	  printf (",\n\t\t");
-	  gen_exp (XVECEXP (x, 1, i), subroutine_type, used);
+	  gen_exp (XVECEXP (x, 1, i), subroutine_type, used, info);
 	}
       printf (")");
       return;
@@ -137,7 +137,7 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used)
       for (i = 0; i < XVECLEN (x, 2); i++)
 	{
 	  printf (",\n\t\t");
-	  gen_exp (XVECEXP (x, 2, i), subroutine_type, used);
+	  gen_exp (XVECEXP (x, 2, i), subroutine_type, used, info);
 	}
       printf (")");
       return;
@@ -163,12 +163,21 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used)
     case CLOBBER:
       if (REG_P (XEXP (x, 0)))
 	{
-	  printf ("gen_hard_reg_clobber (%smode, %i)", GET_MODE_NAME (GET_MODE (XEXP (x, 0))),
-			  			     REGNO (XEXP (x, 0)));
+	  printf ("gen_hard_reg_clobber (%smode, %i)",
+		  GET_MODE_NAME (GET_MODE (XEXP (x, 0))),
+		  REGNO (XEXP (x, 0)));
 	  return;
 	}
       break;
-
+    case CLOBBER_HIGH:
+      if (!REG_P (XEXP (x, 0)))
+	error ("CLOBBER_HIGH argument is not a register expr, at %s:%d",
+	       info->loc.filename, info->loc.lineno);
+      printf ("gen_hard_reg_clobber_high (%smode, %i)",
+	      GET_MODE_NAME (GET_MODE (XEXP (x, 0))),
+	      REGNO (XEXP (x, 0)));
+      return;
+      break;
     case CC0:
       printf ("cc0_rtx");
       return;
@@ -224,7 +233,7 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used)
       switch (fmt[i])
 	{
 	case 'e': case 'u':
-	  gen_exp (XEXP (x, i), subroutine_type, used);
+	  gen_exp (XEXP (x, i), subroutine_type, used, info);
 	  break;
 
 	case 'i':
@@ -252,7 +261,7 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used)
 	    for (j = 0; j < XVECLEN (x, i); j++)
 	      {
 		printf (",\n\t\t");
-		gen_exp (XVECEXP (x, i, j), subroutine_type, used);
+		gen_exp (XVECEXP (x, i, j), subroutine_type, used, info);
 	      }
 	    printf (")");
 	    break;
@@ -270,7 +279,7 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used)
    becoming a separate instruction.  USED is as for gen_exp.  */
 
 static void
-gen_emit_seq (rtvec vec, char *used)
+gen_emit_seq (rtvec vec, char *used, md_rtx_info *info)
 {
   for (int i = 0, len = GET_NUM_ELEM (vec); i < len; ++i)
     {
@@ -279,7 +288,7 @@ gen_emit_seq (rtvec vec, char *used)
       if (const char *name = get_emit_function (next))
 	{
 	  printf ("  %s (", name);
-	  gen_exp (next, DEFINE_EXPAND, used);
+	  gen_exp (next, DEFINE_EXPAND, used, info);
 	  printf (");\n");
 	  if (!last_p && needs_barrier_p (next))
 	    printf ("  emit_barrier ();");
@@ -287,7 +296,7 @@ gen_emit_seq (rtvec vec, char *used)
       else
 	{
 	  printf ("  emit (");
-	  gen_exp (next, DEFINE_EXPAND, used);
+	  gen_exp (next, DEFINE_EXPAND, used, info);
 	  printf (", %s);\n", last_p ? "false" : "true");
 	}
     }
@@ -334,7 +343,8 @@ gen_insn (md_rtx_info *info)
 
       for (i = XVECLEN (insn, 1) - 1; i > 0; i--)
 	{
-	  if (GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER)
+	  if (GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER
+	      && GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER_HIGH)
 	    break;
 
 	  if (REG_P (XEXP (XVECEXP (insn, 1, i), 0)))
@@ -368,7 +378,8 @@ gen_insn (md_rtx_info *info)
 		  /* OLD and NEW_INSN are the same if both are to be a SCRATCH
 		     of the same mode,
 		     or if both are registers of the same mode and number.  */
-		  if (! (GET_MODE (old_rtx) == GET_MODE (new_rtx)
+		  if (! (GET_CODE (old_rtx) == GET_CODE (new_rtx)
+			 && GET_MODE (old_rtx) == GET_MODE (new_rtx)
 			 && ((GET_CODE (old_rtx) == MATCH_SCRATCH
 			      && GET_CODE (new_rtx) == MATCH_SCRATCH)
 			     || (REG_P (old_rtx) && REG_P (new_rtx)
@@ -431,7 +442,7 @@ gen_insn (md_rtx_info *info)
 		? NULL
 		: XCNEWVEC (char, stats.num_generator_args));
   printf ("  return ");
-  gen_exp (pattern, DEFINE_INSN, used);
+  gen_exp (pattern, DEFINE_INSN, used, info);
   printf (";\n}\n\n");
   XDELETEVEC (used);
 }
@@ -480,7 +491,7 @@ gen_expand (md_rtx_info *info)
       && XVECLEN (expand, 1) == 1)
     {
       printf ("  return ");
-      gen_exp (XVECEXP (expand, 1, 0), DEFINE_EXPAND, NULL);
+      gen_exp (XVECEXP (expand, 1, 0), DEFINE_EXPAND, NULL, info);
       printf (";\n}\n\n");
       return;
     }
@@ -534,7 +545,7 @@ gen_expand (md_rtx_info *info)
     }
 
   used = XCNEWVEC (char, stats.num_operand_vars);
-  gen_emit_seq (XVEC (expand, 1), used);
+  gen_emit_seq (XVEC (expand, 1), used, info);
   XDELETEVEC (used);
 
   /* Call `get_insns' to extract the list of all the
@@ -617,7 +628,7 @@ gen_split (md_rtx_info *info)
       printf ("  (void) operand%d;\n", i);
     }
 
-  gen_emit_seq (XVEC (split, 2), used);
+  gen_emit_seq (XVEC (split, 2), used, info);
 
   /* Call `get_insns' to make a list of all the
      insns emitted within this gen_... function.  */
@@ -634,7 +645,7 @@ gen_split (md_rtx_info *info)
    the end of the vector.  */
 
 static void
-output_add_clobbers (void)
+output_add_clobbers (md_rtx_info *info)
 {
   struct clobber_pat *clobber;
   struct clobber_ent *ent;
@@ -654,7 +665,7 @@ output_add_clobbers (void)
 	{
 	  printf ("      XVECEXP (pattern, 0, %d) = ", i);
 	  gen_exp (XVECEXP (clobber->pattern, 1, i),
-		   GET_CODE (clobber->pattern), NULL);
+		   GET_CODE (clobber->pattern), NULL, info);
 	  printf (";\n");
 	}
 
@@ -837,7 +848,7 @@ from the machine description file `md'.  */\n\n");
 
   /* Write out the routines to add CLOBBERs to a pattern and say whether they
      clobber a hard reg.  */
-  output_add_clobbers ();
+  output_add_clobbers (&info);
   output_added_clobbers_hard_reg_p ();
 
   fflush (stdout);
diff --git a/gcc/genrecog.c b/gcc/genrecog.c
index 663df8c58af..629e2dc91f3 100644
--- a/gcc/genrecog.c
+++ b/gcc/genrecog.c
@@ -718,6 +718,7 @@ validate_pattern (rtx pattern, md_rtx_info *info, rtx set, int set_code)
       }
 
     case CLOBBER:
+    case CLOBBER_HIGH:
       validate_pattern (SET_DEST (pattern), info, pattern, '=');
       return;
 
@@ -5294,7 +5295,7 @@ remove_clobbers (acceptance_type *acceptance_ptr, rtx *pattern_ptr)
   for (i = XVECLEN (pattern, 0); i > 0; i--)
     {
       rtx x = XVECEXP (pattern, 0, i - 1);
-      if (GET_CODE (x) != CLOBBER
+      if ((GET_CODE (x) != CLOBBER && GET_CODE (x) != CLOBBER_HIGH)
 	  || (!REG_P (XEXP (x, 0))
 	      && GET_CODE (XEXP (x, 0)) != MATCH_SCRATCH))
 	break;
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 5e07e9bee80..f42d749511d 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -4242,6 +4242,7 @@ extern void vt_equate_reg_base_value (const_rtx, const_rtx);
 extern bool memory_modified_in_insn_p (const_rtx, const_rtx);
 extern bool may_be_sp_based_p (rtx);
 extern rtx gen_hard_reg_clobber (machine_mode, unsigned int);
+extern rtx gen_hard_reg_clobber_high (machine_mode, unsigned int);
 extern rtx get_reg_known_value (unsigned int);
 extern bool get_reg_known_equiv_p (unsigned int);
 extern rtx get_reg_base_value (unsigned int);
-- 
2.15.2 (Apple Git-101.1)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v2 7/7] Enable clobber high for tls descs on Aarch64
  2018-07-26  9:14 [PATCH v2 0/7] Support partial clobbers around TLS calls on Aarch64 SVE Alan Hayward
                   ` (5 preceding siblings ...)
  2018-07-26  9:14 ` [PATCH v2 3/7] Add func to check if register is clobbered by clobber_high Alan Hayward
@ 2018-07-26  9:14 ` Alan Hayward
  2018-08-04  4:27   ` Jeff Law
  2018-08-06 13:15   ` Richard Sandiford
  2018-08-02 13:01 ` PING [PATCH v2 0/7] Support partial clobbers around TLS calls on Aarch64 SVE Alan Hayward
  7 siblings, 2 replies; 18+ messages in thread
From: Alan Hayward @ 2018-07-26  9:14 UTC (permalink / raw)
  To: gcc-patches; +Cc: nd, Alan Hayward

Add the clobber high expressions to tls_desc for aarch64.
It also adds three tests.

In addition I also tested by taking the gcc torture test suite and making
all global variables __thread. Then emended the suite to compile with -fpic,
save the .s file and only for one given O level.
I ran this before and after the patch and compared the resulting .s files,
ensuring that there were no ASM changes.
I discarded the 10% of tests that failed to compile (due to the code in
the test now being invalid C).
I did this for O0,O2,O3 on both x86 and aarch64 and observed no difference
between ASM files before and after the patch.

Alan.

2018-07-25  Alan Hayward  <alan.hayward@arm.com>

gcc/
	* config/aarch64/aarch64.md: Add clobber highs to tls_desc.

gcc/testsuite/
	* gcc.target/aarch64/sve_tls_preserve_1.c: New test.
	* gcc.target/aarch64/sve_tls_preserve_2.c: New test.
	* gcc.target/aarch64/sve_tls_preserve_3.c: New test.
---
 gcc/config/aarch64/aarch64.md                      | 69 ++++++++++++++++++----
 .../gcc.target/aarch64/sve_tls_preserve_1.c        | 19 ++++++
 .../gcc.target/aarch64/sve_tls_preserve_2.c        | 24 ++++++++
 .../gcc.target/aarch64/sve_tls_preserve_3.c        | 24 ++++++++
 4 files changed, 124 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_2.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_3.c

diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index e9c16f9697b..a41d6e15bc8 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -57,14 +57,36 @@
     (LR_REGNUM		30)
     (SP_REGNUM		31)
     (V0_REGNUM		32)
+    (V1_REGNUM		33)
+    (V2_REGNUM		34)
+    (V3_REGNUM		35)
     (V4_REGNUM		36)
+    (V5_REGNUM		37)
+    (V6_REGNUM		38)
+    (V7_REGNUM		39)
     (V8_REGNUM		40)
+    (V9_REGNUM		41)
+    (V10_REGNUM		42)
+    (V11_REGNUM		43)
     (V12_REGNUM		44)
+    (V13_REGNUM		45)
+    (V14_REGNUM		46)
     (V15_REGNUM		47)
     (V16_REGNUM		48)
+    (V17_REGNUM		49)
+    (V18_REGNUM		50)
+    (V19_REGNUM		51)
     (V20_REGNUM		52)
+    (V21_REGNUM		53)
+    (V22_REGNUM		54)
+    (V23_REGNUM		55)
     (V24_REGNUM		56)
+    (V25_REGNUM		57)
+    (V26_REGNUM		58)
+    (V27_REGNUM		59)
     (V28_REGNUM		60)
+    (V29_REGNUM		61)
+    (V30_REGNUM		62)
     (V31_REGNUM		63)
     (LAST_SAVED_REGNUM	63)
     (SFP_REGNUM		64)
@@ -6302,24 +6324,47 @@
   [(set_attr "type" "call")
    (set_attr "length" "16")])
 
-;; For SVE, model tlsdesc calls as clobbering all vector and predicate
-;; registers, on top of the usual R0 and LR.  In reality the calls
-;; preserve the low 128 bits of the vector registers, but we don't
-;; yet have a way of representing that in the instruction pattern.
+;; For SVE, model tlsdesc calls as clobbering the lower 128 bits of
+;; all vector registers, and clobber all predicate registers, on
+;; top of the usual R0 and LR.
 (define_insn "tlsdesc_small_sve_<mode>"
   [(set (reg:PTR R0_REGNUM)
         (unspec:PTR [(match_operand 0 "aarch64_valid_symref" "S")]
 		    UNSPEC_TLSDESC))
    (clobber (reg:DI LR_REGNUM))
    (clobber (reg:CC CC_REGNUM))
-   (clobber (reg:XI V0_REGNUM))
-   (clobber (reg:XI V4_REGNUM))
-   (clobber (reg:XI V8_REGNUM))
-   (clobber (reg:XI V12_REGNUM))
-   (clobber (reg:XI V16_REGNUM))
-   (clobber (reg:XI V20_REGNUM))
-   (clobber (reg:XI V24_REGNUM))
-   (clobber (reg:XI V28_REGNUM))
+   (clobber_high (reg:TI V0_REGNUM))
+   (clobber_high (reg:TI V1_REGNUM))
+   (clobber_high (reg:TI V2_REGNUM))
+   (clobber_high (reg:TI V3_REGNUM))
+   (clobber_high (reg:TI V4_REGNUM))
+   (clobber_high (reg:TI V5_REGNUM))
+   (clobber_high (reg:TI V6_REGNUM))
+   (clobber_high (reg:TI V7_REGNUM))
+   (clobber_high (reg:TI V8_REGNUM))
+   (clobber_high (reg:TI V9_REGNUM))
+   (clobber_high (reg:TI V10_REGNUM))
+   (clobber_high (reg:TI V11_REGNUM))
+   (clobber_high (reg:TI V12_REGNUM))
+   (clobber_high (reg:TI V13_REGNUM))
+   (clobber_high (reg:TI V14_REGNUM))
+   (clobber_high (reg:TI V15_REGNUM))
+   (clobber_high (reg:TI V16_REGNUM))
+   (clobber_high (reg:TI V17_REGNUM))
+   (clobber_high (reg:TI V18_REGNUM))
+   (clobber_high (reg:TI V19_REGNUM))
+   (clobber_high (reg:TI V20_REGNUM))
+   (clobber_high (reg:TI V21_REGNUM))
+   (clobber_high (reg:TI V22_REGNUM))
+   (clobber_high (reg:TI V23_REGNUM))
+   (clobber_high (reg:TI V24_REGNUM))
+   (clobber_high (reg:TI V25_REGNUM))
+   (clobber_high (reg:TI V26_REGNUM))
+   (clobber_high (reg:TI V27_REGNUM))
+   (clobber_high (reg:TI V28_REGNUM))
+   (clobber_high (reg:TI V29_REGNUM))
+   (clobber_high (reg:TI V30_REGNUM))
+   (clobber_high (reg:TI V31_REGNUM))
    (clobber (reg:VNx2BI P0_REGNUM))
    (clobber (reg:VNx2BI P1_REGNUM))
    (clobber (reg:VNx2BI P2_REGNUM))
diff --git a/gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_1.c b/gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_1.c
new file mode 100644
index 00000000000..3bb1725e5e6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_1.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fpic -march=armv8-a+sve" } */
+
+/* Clobber highs do not need to be spilled around tls usage.  */
+
+typedef float v4si __attribute__ ((vector_size (16)));
+
+__thread v4si tx;
+
+v4si foo (v4si a, v4si b, v4si c)
+{
+  v4si y;
+
+  y = a + tx + b + c;
+
+  return y + 7;
+}
+
+/* { dg-final { scan-assembler-not {\tst[rp]\t[dqv]} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_2.c b/gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_2.c
new file mode 100644
index 00000000000..69e8829287b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fpic -march=armv8-a+sve -msve-vector-bits=256 -fno-schedule-insns" } */
+
+/* Clobber highs must be spilled around tls usage.  */
+
+typedef float v8si __attribute__ ((vector_size (32)));
+
+__thread v8si tx;
+
+v8si foo (v8si a, v8si b, v8si c)
+{
+  v8si y;
+
+  /* There is nothing stopping the compiler from making the tls call before
+     loading the input variables off the stack.  However, there appears to
+     be no way in C of enforcing this.  Thankfully the compiler doesn't
+     do this reordering.  */
+
+  y = a + tx + b + c;
+
+  return y + 7;
+}
+
+/* { dg-final { scan-assembler-times {\tstr\tz[0-9]+,} 3 } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_3.c b/gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_3.c
new file mode 100644
index 00000000000..b6aa59a3c73
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_3.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fpic -march=armv8-a+sve -msve-vector-bits=512 -fno-schedule-insns" } */
+
+/* Clobber highs must be spilled around tls usage.  */
+
+typedef float v16si __attribute__ ((vector_size (64)));
+
+__thread v16si tx;
+
+v16si foo (v16si a, v16si b, v16si c)
+{
+  v16si y;
+
+  /* There is nothing stopping the compiler from making the tls call before
+     loading the input variables off the stack.  However, there appears to
+     be no way in C of enforcing this.  Thankfully the compiler doesn't
+     do this reordering.  */
+
+  y = a + tx + b + c;
+
+  return y + 7;
+}
+
+/* { dg-final { scan-assembler-times {\tstr\tz[0-9]+,} 3 } } */
-- 
2.15.2 (Apple Git-101.1)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v2 0/7] Support partial clobbers around TLS calls on Aarch64 SVE
@ 2018-07-26  9:14 Alan Hayward
  2018-07-26  9:14 ` [PATCH v2 4/7] lra support for clobber_high Alan Hayward
                   ` (7 more replies)
  0 siblings, 8 replies; 18+ messages in thread
From: Alan Hayward @ 2018-07-26  9:14 UTC (permalink / raw)
  To: gcc-patches; +Cc: nd, Alan Hayward

This is rebasing of the patch posted in November.
It's aim is to support aarch64 SVE register preservation around TLS calls
by adding a CLOBBER_HIGH expression.

Across a TLS call, Aarch64 SVE does not explicitly preserve the
SVE vector registers. However, the Neon vector registers are preserved.
Due to overlapping of registers, this means the lower 128bits of all
SVE vector registers will be preserved.

The existing GCC code assume all Neon and SVE registers are clobbered
across TLS calls.

This patch introduces a CLOBBER_HIGH expression. This behaves a bit like
a CLOBBER expression. CLOBBER_HIGH can only refer to a single register.
The mode of the expression indicates the size of the lower bits which
will be preserved. If the register contains a value bigger than this
mode then the code will treat the register as clobbered, otherwise the
register remains untouched.

The means in order to evaluate if a clobber high is relevant, we need to
ensure the mode of the existing value in a register is tracked.

The first two patches introduce CLOBBER_HIGH and generation support.
The next patch adds a helper function for easily determining if a register
gets clobbered by a CLOBBER_HIGH.
The next three patches add clobber high checks to all of the passes. I
couldn't think of a better way of splitting this up (maybe needs dividing
into smaller patches?).
Finally the last patch adds the CLOBBER_HIGHS around a TLS call for
aarch64 SVE and some test cases.

Alan Hayward (7):
  Add CLOBBER_HIGH expression
  Generation support for CLOBBER_HIGH
  Add func to check if register is clobbered by clobber_high
  lra support for clobber_high
  cse support for clobber_high
  Remaining support for clobber high
  Enable clobber high for tls descs on Aarch64

 gcc/alias.c                                        |  11 ++
 gcc/cfgexpand.c                                    |   1 +
 gcc/combine-stack-adj.c                            |   1 +
 gcc/combine.c                                      |  38 ++++-
 gcc/config/aarch64/aarch64.md                      |  69 ++++++--
 gcc/cse.c                                          | 187 ++++++++++++++-------
 gcc/cselib.c                                       |  42 +++--
 gcc/cselib.h                                       |   2 +-
 gcc/dce.c                                          |  11 +-
 gcc/df-scan.c                                      |   6 +
 gcc/doc/rtl.texi                                   |  15 +-
 gcc/dwarf2out.c                                    |   1 +
 gcc/emit-rtl.c                                     |  16 ++
 gcc/genconfig.c                                    |   1 +
 gcc/genemit.c                                      |  51 +++---
 gcc/genrecog.c                                     |   3 +-
 gcc/haifa-sched.c                                  |   3 +
 gcc/ira-build.c                                    |   5 +
 gcc/ira-costs.c                                    |   7 +
 gcc/ira.c                                          |   6 +-
 gcc/jump.c                                         |   1 +
 gcc/lra-eliminations.c                             |  11 ++
 gcc/lra-int.h                                      |   2 +
 gcc/lra-lives.c                                    |  31 ++--
 gcc/lra.c                                          |  66 +++++---
 gcc/postreload-gcse.c                              |  21 ++-
 gcc/postreload.c                                   |  25 ++-
 gcc/print-rtl.c                                    |   1 +
 gcc/recog.c                                        |   9 +-
 gcc/regcprop.c                                     |  10 +-
 gcc/reginfo.c                                      |   4 +
 gcc/reload1.c                                      |  16 +-
 gcc/reorg.c                                        |  27 ++-
 gcc/resource.c                                     |  24 ++-
 gcc/rtl.c                                          |  15 ++
 gcc/rtl.def                                        |  10 ++
 gcc/rtl.h                                          |  27 ++-
 gcc/rtlanal.c                                      |  47 +++++-
 gcc/sched-deps.c                                   |  15 +-
 .../gcc.target/aarch64/sve_tls_preserve_1.c        |  19 +++
 .../gcc.target/aarch64/sve_tls_preserve_2.c        |  24 +++
 .../gcc.target/aarch64/sve_tls_preserve_3.c        |  24 +++
 42 files changed, 725 insertions(+), 180 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_2.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_3.c

-- 
2.15.2 (Apple Git-101.1)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v2 6/7] Remaining support for clobber high
  2018-07-26  9:14 [PATCH v2 0/7] Support partial clobbers around TLS calls on Aarch64 SVE Alan Hayward
  2018-07-26  9:14 ` [PATCH v2 4/7] lra support for clobber_high Alan Hayward
  2018-07-26  9:14 ` [PATCH v2 2/7] Generation support for CLOBBER_HIGH Alan Hayward
@ 2018-07-26  9:14 ` Alan Hayward
  2018-08-04  4:30   ` Jeff Law
  2018-12-13 10:11   ` Jakub Jelinek
  2018-07-26  9:14 ` [PATCH v2 1/7] Add CLOBBER_HIGH expression Alan Hayward
                   ` (4 subsequent siblings)
  7 siblings, 2 replies; 18+ messages in thread
From: Alan Hayward @ 2018-07-26  9:14 UTC (permalink / raw)
  To: gcc-patches; +Cc: nd, Alan Hayward

Add the remainder of clobber high checks.
Happy to split this into smaller patches if required (there didn't
seem anything obvious to split into).

2018-07-25  Alan Hayward  <alan.hayward@arm.com>

	* alias.c (record_set): Check for clobber high.
	* cfgexpand.c (expand_gimple_stmt): Likewise.
	* combine-stack-adj.c (single_set_for_csa): Likewise.
	* combine.c (find_single_use_1): Likewise.
	(set_nonzero_bits_and_sign_copies): Likewise.
	(get_combine_src_dest): Likewise.
	(is_parallel_of_n_reg_sets): Likewise.
	(try_combine): Likewise.
	(record_dead_and_set_regs_1): Likewise.
	(reg_dead_at_p_1): Likewise.
	(reg_dead_at_p): Likewise.
	* dce.c (deletable_insn_p): Likewise.
	(mark_nonreg_stores_1): Likewise.
	(mark_nonreg_stores_2): Likewise.
	* df-scan.c (df_find_hard_reg_defs): Likewise.
	(df_uses_record): Likewise.
	(df_get_call_refs): Likewise.
	* dwarf2out.c (mem_loc_descriptor): Likewise.
	* haifa-sched.c (haifa_classify_rtx): Likewise.
	* ira-build.c (create_insn_allocnos): Likewise.
	* ira-costs.c (scan_one_insn): Likewise.
	* ira.c (equiv_init_movable_p): Likewise.
	(rtx_moveable_p): Likewise.
	(interesting_dest_for_shprep): Likewise.
	* jump.c (mark_jump_label_1): Likewise.
	* postreload-gcse.c (record_opr_changes): Likewise.
	* postreload.c (reload_cse_simplify): Likewise.
	(struct reg_use): Add source expr.
	(reload_combine): Check for clobber high.
	(reload_combine_note_use): Likewise.
	(reload_cse_move2add): Likewise.
	(move2add_note_store): Likewise.
	* print-rtl.c (print_pattern): Likewise.
	* recog.c (decode_asm_operands): Likewise.
	(store_data_bypass_p): Likewise.
	(if_test_bypass_p): Likewise.
	* regcprop.c (kill_clobbered_value): Likewise.
	(kill_set_value): Likewise.
	* reginfo.c (reg_scan_mark_refs): Likewise.
	* reload1.c (maybe_fix_stack_asms): Likewise.
	(eliminate_regs_1): Likewise.
	(elimination_effects): Likewise.
	(mark_not_eliminable): Likewise.
	(scan_paradoxical_subregs): Likewise.
	(forget_old_reloads_1): Likewise.
	* reorg.c (find_end_label): Likewise.
	(try_merge_delay_insns): Likewise.
	(redundant_insn): Likewise.
	(own_thread_p): Likewise.
	(fill_simple_delay_slots): Likewise.
	(fill_slots_from_thread): Likewise.
	(dbr_schedule): Likewise.
	* resource.c (update_live_status): Likewise.
	(mark_referenced_resources): Likewise.
	(mark_set_resources): Likewise.
	* rtl.c (copy_rtx): Likewise.
	* rtlanal.c (reg_referenced_p): Likewise.
	(single_set_2): Likewise.
	(noop_move_p): Likewise.
	(note_stores): Likewise.
	* sched-deps.c (sched_analyze_reg): Likewise.
	(sched_analyze_insn): Likewise.
---
 gcc/alias.c             | 11 +++++++++++
 gcc/cfgexpand.c         |  1 +
 gcc/combine-stack-adj.c |  1 +
 gcc/combine.c           | 38 +++++++++++++++++++++++++++++++++-----
 gcc/dce.c               | 11 +++++++++--
 gcc/df-scan.c           |  6 ++++++
 gcc/dwarf2out.c         |  1 +
 gcc/haifa-sched.c       |  3 +++
 gcc/ira-build.c         |  5 +++++
 gcc/ira-costs.c         |  7 +++++++
 gcc/ira.c               |  6 +++++-
 gcc/jump.c              |  1 +
 gcc/postreload-gcse.c   | 21 ++++++++++++---------
 gcc/postreload.c        | 25 ++++++++++++++++++++++++-
 gcc/print-rtl.c         |  1 +
 gcc/recog.c             |  9 ++++++---
 gcc/regcprop.c          | 10 ++++++++--
 gcc/reginfo.c           |  4 ++++
 gcc/reload1.c           | 16 +++++++++++++++-
 gcc/reorg.c             | 27 ++++++++++++++++++---------
 gcc/resource.c          | 24 +++++++++++++++++++++---
 gcc/rtl.c               |  4 ++++
 gcc/rtlanal.c           | 18 +++++++++++++++---
 gcc/sched-deps.c        | 15 ++++++++++++++-
 24 files changed, 225 insertions(+), 40 deletions(-)

diff --git a/gcc/alias.c b/gcc/alias.c
index 2091dfbf3d7..748da2b6951 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -1554,6 +1554,17 @@ record_set (rtx dest, const_rtx set, void *data ATTRIBUTE_UNUSED)
 	  new_reg_base_value[regno] = 0;
 	  return;
 	}
+      /* A CLOBBER_HIGH only wipes out the old value if the mode of the old
+	 value is greater than that of the clobber.  */
+      else if (GET_CODE (set) == CLOBBER_HIGH)
+	{
+	  if (new_reg_base_value[regno] != 0
+	      && reg_is_clobbered_by_clobber_high (
+		   regno, GET_MODE (new_reg_base_value[regno]), XEXP (set, 0)))
+	    new_reg_base_value[regno] = 0;
+	  return;
+	}
+
       src = SET_SRC (set);
     }
   else
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index d6e3c382085..39db6ed435f 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -3750,6 +3750,7 @@ expand_gimple_stmt (gimple *stmt)
 	      /* If we want exceptions for non-call insns, any
 		 may_trap_p instruction may throw.  */
 	      && GET_CODE (PATTERN (insn)) != CLOBBER
+	      && GET_CODE (PATTERN (insn)) != CLOBBER_HIGH
 	      && GET_CODE (PATTERN (insn)) != USE
 	      && insn_could_throw_p (insn))
 	    make_reg_eh_region_note (insn, 0, lp_nr);
diff --git a/gcc/combine-stack-adj.c b/gcc/combine-stack-adj.c
index 4573dc2a87d..bd7f5d0d2ec 100644
--- a/gcc/combine-stack-adj.c
+++ b/gcc/combine-stack-adj.c
@@ -133,6 +133,7 @@ single_set_for_csa (rtx_insn *insn)
 	  && SET_SRC (this_rtx) == SET_DEST (this_rtx))
 	;
       else if (GET_CODE (this_rtx) != CLOBBER
+	       && GET_CODE (this_rtx) != CLOBBER_HIGH
 	       && GET_CODE (this_rtx) != USE)
 	return NULL_RTX;
     }
diff --git a/gcc/combine.c b/gcc/combine.c
index cfe0f190ece..be8397b5763 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -570,6 +570,7 @@ find_single_use_1 (rtx dest, rtx *loc)
     case SYMBOL_REF:
     CASE_CONST_ANY:
     case CLOBBER:
+    case CLOBBER_HIGH:
       return 0;
 
     case SET:
@@ -1752,6 +1753,9 @@ set_nonzero_bits_and_sign_copies (rtx x, const_rtx set, void *data)
 	  return;
 	}
 
+      /* Should not happen as we only using pseduo registers.  */
+      gcc_assert (GET_CODE (set) != CLOBBER_HIGH);
+
       /* If this register is being initialized using itself, and the
 	 register is uninitialized in this basic block, and there are
 	 no LOG_LINKS which set the register, then part of the
@@ -1910,6 +1914,7 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED,
 
 	      /* We can ignore CLOBBERs.  */
 	    case CLOBBER:
+	    case CLOBBER_HIGH:
 	      break;
 
 	    case SET:
@@ -2570,10 +2575,17 @@ is_parallel_of_n_reg_sets (rtx pat, int n)
 	|| !REG_P (SET_DEST (XVECEXP (pat, 0, i))))
       return false;
   for ( ; i < len; i++)
-    if (GET_CODE (XVECEXP (pat, 0, i)) != CLOBBER
-	|| XEXP (XVECEXP (pat, 0, i), 0) == const0_rtx)
-      return false;
-
+    switch (GET_CODE (XVECEXP (pat, 0, i)))
+      {
+      case CLOBBER:
+	if (XEXP (XVECEXP (pat, 0, i), 0) == const0_rtx)
+	  return false;
+	break;
+      case CLOBBER_HIGH:
+	break;
+      default:
+	return false;
+      }
   return true;
 }
 
@@ -2848,7 +2860,8 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       for (i = 0; ok && i < XVECLEN (p2, 0); i++)
 	{
 	  if ((GET_CODE (XVECEXP (p2, 0, i)) == SET
-	       || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER)
+	       || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER
+	       || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER_HIGH)
 	      && reg_overlap_mentioned_p (SET_DEST (PATTERN (i3)),
 					  SET_DEST (XVECEXP (p2, 0, i))))
 	    ok = false;
@@ -13296,6 +13309,15 @@ record_dead_and_set_regs_1 (rtx dest, const_rtx setter, void *data)
 			      ? SET_SRC (setter)
 			      : gen_lowpart (GET_MODE (dest),
 					     SET_SRC (setter)));
+      else if (GET_CODE (setter) == CLOBBER_HIGH)
+	{
+	  reg_stat_type *rsp = &reg_stat[REGNO (dest)];
+	  if (rsp->last_set_value
+	      && reg_is_clobbered_by_clobber_high
+		   (REGNO (dest), GET_MODE (rsp->last_set_value),
+		    XEXP (setter, 0)))
+	    record_value_for_reg (dest, NULL, NULL_RTX);
+	}
       else
 	record_value_for_reg (dest, record_dead_insn, NULL_RTX);
     }
@@ -13716,6 +13738,7 @@ get_last_value (const_rtx x)
 
 static unsigned int reg_dead_regno, reg_dead_endregno;
 static int reg_dead_flag;
+rtx reg_dead_reg;
 
 /* Function called via note_stores from reg_dead_at_p.
 
@@ -13730,6 +13753,10 @@ reg_dead_at_p_1 (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED)
   if (!REG_P (dest))
     return;
 
+  if (GET_CODE (x) == CLOBBER_HIGH
+      && !reg_is_clobbered_by_clobber_high (reg_dead_reg, XEXP (x, 0)))
+    return;
+
   regno = REGNO (dest);
   endregno = END_REGNO (dest);
   if (reg_dead_endregno > regno && reg_dead_regno < endregno)
@@ -13753,6 +13780,7 @@ reg_dead_at_p (rtx reg, rtx_insn *insn)
   /* Set variables for reg_dead_at_p_1.  */
   reg_dead_regno = REGNO (reg);
   reg_dead_endregno = END_REGNO (reg);
+  reg_dead_reg = reg;
 
   reg_dead_flag = 0;
 
diff --git a/gcc/dce.c b/gcc/dce.c
index e4d442c62b5..7fc3fd209b5 100644
--- a/gcc/dce.c
+++ b/gcc/dce.c
@@ -145,6 +145,7 @@ deletable_insn_p (rtx_insn *insn, bool fast, bitmap arg_stores)
       return false;
 
     case CLOBBER:
+    case CLOBBER_HIGH:
       if (fast)
 	{
 	  /* A CLOBBER of a dead pseudo register serves no purpose.
@@ -213,7 +214,10 @@ static void
 mark_nonreg_stores_1 (rtx dest, const_rtx pattern, void *data)
 {
   if (GET_CODE (pattern) != CLOBBER && !REG_P (dest))
-    mark_insn ((rtx_insn *) data, true);
+    {
+      gcc_checking_assert (GET_CODE (pattern) != CLOBBER_HIGH);
+      mark_insn ((rtx_insn *) data, true);
+    }
 }
 
 
@@ -224,7 +228,10 @@ static void
 mark_nonreg_stores_2 (rtx dest, const_rtx pattern, void *data)
 {
   if (GET_CODE (pattern) != CLOBBER && !REG_P (dest))
-    mark_insn ((rtx_insn *) data, false);
+    {
+      gcc_checking_assert (GET_CODE (pattern) != CLOBBER_HIGH);
+      mark_insn ((rtx_insn *) data, false);
+    }
 }
 
 
diff --git a/gcc/df-scan.c b/gcc/df-scan.c
index cbb08fc36ae..0b119f211ea 100644
--- a/gcc/df-scan.c
+++ b/gcc/df-scan.c
@@ -2778,6 +2778,7 @@ df_find_hard_reg_defs (rtx x, HARD_REG_SET *defs)
       break;
 
     case CLOBBER:
+    case CLOBBER_HIGH:
       df_find_hard_reg_defs_1 (XEXP (x, 0), defs);
       break;
 
@@ -2837,6 +2838,10 @@ df_uses_record (struct df_collection_rec *collection_rec,
       /* If we're clobbering a REG then we have a def so ignore.  */
       return;
 
+    case CLOBBER_HIGH:
+      gcc_assert (REG_P (XEXP (x, 0)));
+      return;
+
     case MEM:
       df_uses_record (collection_rec,
 		      &XEXP (x, 0), DF_REF_REG_MEM_LOAD,
@@ -3133,6 +3138,7 @@ df_get_call_refs (struct df_collection_rec *collection_rec,
   for (note = CALL_INSN_FUNCTION_USAGE (insn_info->insn); note;
        note = XEXP (note, 1))
     {
+      gcc_assert (GET_CODE (XEXP (note, 0)) != CLOBBER_HIGH);
       if (GET_CODE (XEXP (note, 0)) == USE)
         df_uses_record (collection_rec, &XEXP (XEXP (note, 0), 0),
 			DF_REF_REG_USE, bb, insn_info, flags);
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 8377cbc5dd1..33d6d3ea3a2 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -16321,6 +16321,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
     case CONST_FIXED:
     case CLRSB:
     case CLOBBER:
+    case CLOBBER_HIGH:
       /* If delegitimize_address couldn't do anything with the UNSPEC, we
 	 can't express it in the debug info.  This can happen e.g. with some
 	 TLS UNSPECs.  */
diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
index 4a899b56173..4f0221f6f43 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -529,6 +529,9 @@ haifa_classify_rtx (const_rtx x)
 	  /* Test if it is a 'store'.  */
 	  tmp_class = may_trap_exp (XEXP (x, 0), 1);
 	  break;
+	case CLOBBER_HIGH:
+	  gcc_assert (REG_P (XEXP (x, 0)));
+	  break;
 	case SET:
 	  /* Test if it is a store.  */
 	  tmp_class = may_trap_exp (SET_DEST (x), 1);
diff --git a/gcc/ira-build.c b/gcc/ira-build.c
index c0fd9384f8b..da017be5b3d 100644
--- a/gcc/ira-build.c
+++ b/gcc/ira-build.c
@@ -1876,6 +1876,11 @@ create_insn_allocnos (rtx x, rtx outer, bool output_p)
       create_insn_allocnos (XEXP (x, 0), NULL, true);
       return;
     }
+  else if (code == CLOBBER_HIGH)
+    {
+      gcc_assert (REG_P (XEXP (x, 0)) && HARD_REGISTER_P (XEXP (x, 0)));
+      return;
+    }
   else if (code == MEM)
     {
       create_insn_allocnos (XEXP (x, 0), NULL, false);
diff --git a/gcc/ira-costs.c b/gcc/ira-costs.c
index 2b4ae38f410..6fa917ab1a1 100644
--- a/gcc/ira-costs.c
+++ b/gcc/ira-costs.c
@@ -1444,6 +1444,13 @@ scan_one_insn (rtx_insn *insn)
       return insn;
     }
 
+  if (pat_code == CLOBBER_HIGH)
+    {
+      gcc_assert (REG_P (XEXP (PATTERN (insn), 0))
+		  && HARD_REGISTER_P (XEXP (PATTERN (insn), 0)));
+      return insn;
+    }
+
   counted_mem = false;
   set = single_set (insn);
   extract_insn (insn);
diff --git a/gcc/ira.c b/gcc/ira.c
index b7bcc15a15d..def194a0782 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -3086,6 +3086,7 @@ equiv_init_movable_p (rtx x, int regno)
 
     case CC0:
     case CLOBBER:
+    case CLOBBER_HIGH:
       return 0;
 
     case PRE_INC:
@@ -4411,6 +4412,7 @@ rtx_moveable_p (rtx *loc, enum op_type type)
 	      && rtx_moveable_p (&XEXP (x, 2), OP_IN));
 
     case CLOBBER:
+    case CLOBBER_HIGH:
       return rtx_moveable_p (&SET_DEST (x), OP_OUT);
 
     case UNSPEC_VOLATILE:
@@ -4863,7 +4865,9 @@ interesting_dest_for_shprep (rtx_insn *insn, basic_block call_dom)
   for (int i = 0; i < XVECLEN (pat, 0); i++)
     {
       rtx sub = XVECEXP (pat, 0, i);
-      if (GET_CODE (sub) == USE || GET_CODE (sub) == CLOBBER)
+      if (GET_CODE (sub) == USE
+	  || GET_CODE (sub) == CLOBBER
+	  || GET_CODE (sub) == CLOBBER_HIGH)
 	continue;
       if (GET_CODE (sub) != SET
 	  || side_effects_p (sub))
diff --git a/gcc/jump.c b/gcc/jump.c
index f379048f636..06f7255d24d 100644
--- a/gcc/jump.c
+++ b/gcc/jump.c
@@ -1094,6 +1094,7 @@ mark_jump_label_1 (rtx x, rtx_insn *insn, bool in_mem, bool is_target)
     case CC0:
     case REG:
     case CLOBBER:
+    case CLOBBER_HIGH:
     case CALL:
       return;
 
diff --git a/gcc/postreload-gcse.c b/gcc/postreload-gcse.c
index 152dd6ae452..afa61dcede6 100644
--- a/gcc/postreload-gcse.c
+++ b/gcc/postreload-gcse.c
@@ -791,15 +791,18 @@ record_opr_changes (rtx_insn *insn)
 	record_last_reg_set_info_regno (insn, regno);
 
       for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
-	if (GET_CODE (XEXP (link, 0)) == CLOBBER)
-	  {
-	    x = XEXP (XEXP (link, 0), 0);
-	    if (REG_P (x))
-	      {
-		gcc_assert (HARD_REGISTER_P (x));
-		record_last_reg_set_info (insn, x);
-	      }
-	  }
+	{
+	  gcc_assert (GET_CODE (XEXP (link, 0)) != CLOBBER_HIGH);
+	  if (GET_CODE (XEXP (link, 0)) == CLOBBER)
+	    {
+	      x = XEXP (XEXP (link, 0), 0);
+	      if (REG_P (x))
+		{
+		  gcc_assert (HARD_REGISTER_P (x));
+		  record_last_reg_set_info (insn, x);
+		}
+	    }
+	}
 
       if (! RTL_CONST_OR_PURE_CALL_P (insn))
 	record_last_mem_set_info (insn);
diff --git a/gcc/postreload.c b/gcc/postreload.c
index 0638709639b..56cb14dc676 100644
--- a/gcc/postreload.c
+++ b/gcc/postreload.c
@@ -133,6 +133,8 @@ reload_cse_simplify (rtx_insn *insn, rtx testreg)
 	  for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
 	    {
 	      rtx part = XVECEXP (body, 0, i);
+	      /* asms can only have full clobbers, not clobber_highs.  */
+	      gcc_assert (GET_CODE (part) != CLOBBER_HIGH);
 	      if (GET_CODE (part) == CLOBBER && REG_P (XEXP (part, 0)))
 		cselib_invalidate_rtx (XEXP (part, 0));
 	    }
@@ -156,6 +158,7 @@ reload_cse_simplify (rtx_insn *insn, rtx testreg)
 		}
 	    }
 	  else if (GET_CODE (part) != CLOBBER
+		   && GET_CODE (part) != CLOBBER_HIGH
 		   && GET_CODE (part) != USE)
 	    break;
 	}
@@ -667,7 +670,8 @@ struct reg_use
    STORE_RUID is always meaningful if we only want to use a value in a
    register in a different place: it denotes the next insn in the insn
    stream (i.e. the last encountered) that sets or clobbers the register.
-   REAL_STORE_RUID is similar, but clobbers are ignored when updating it.  */
+   REAL_STORE_RUID is similar, but clobbers are ignored when updating it.
+   EXPR is the expression used when storing the register.  */
 static struct
   {
     struct reg_use reg_use[RELOAD_COMBINE_MAX_USES];
@@ -677,6 +681,7 @@ static struct
     int real_store_ruid;
     int use_ruid;
     bool all_offsets_match;
+    rtx expr;
   } reg_state[FIRST_PSEUDO_REGISTER];
 
 /* Reverse linear uid.  This is increased in reload_combine while scanning
@@ -1341,6 +1346,10 @@ reload_combine (void)
 	    {
 	      rtx setuse = XEXP (link, 0);
 	      rtx usage_rtx = XEXP (setuse, 0);
+	      /* We could support CLOBBER_HIGH and treat it in the same way as
+		 HARD_REGNO_CALL_PART_CLOBBERED, but no port needs that yet.  */
+	      gcc_assert (GET_CODE (setuse) != CLOBBER_HIGH);
+
 	      if ((GET_CODE (setuse) == USE || GET_CODE (setuse) == CLOBBER)
 		  && REG_P (usage_rtx))
 	        {
@@ -1516,6 +1525,10 @@ reload_combine_note_use (rtx *xp, rtx_insn *insn, int ruid, rtx containing_mem)
 	}
       break;
 
+    case CLOBBER_HIGH:
+      gcc_assert (REG_P (SET_DEST (x)));
+      return;
+
     case PLUS:
       /* We are interested in (plus (reg) (const_int)) .  */
       if (!REG_P (XEXP (x, 0))
@@ -2135,6 +2148,9 @@ reload_cse_move2add (rtx_insn *first)
 	    {
 	      rtx setuse = XEXP (link, 0);
 	      rtx usage_rtx = XEXP (setuse, 0);
+	      /* CALL_INSN_FUNCTION_USAGEs can only have full clobbers, not
+		 clobber_highs.  */
+	      gcc_assert (GET_CODE (setuse) != CLOBBER_HIGH);
 	      if (GET_CODE (setuse) == CLOBBER
 		  && REG_P (usage_rtx))
 	        {
@@ -2297,6 +2313,13 @@ move2add_note_store (rtx dst, const_rtx set, void *data)
 
       move2add_record_mode (dst);
     }
+  else if (GET_CODE (set) == CLOBBER_HIGH)
+    {
+      /* Only invalidate if actually clobbered.  */
+      if (reg_mode[regno] == BLKmode
+	  || reg_is_clobbered_by_clobber_high (regno, reg_mode[regno], dst))
+	 goto invalidate;
+    }
   else
     {
     invalidate:
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 37c0d53fae2..ba9ac02fce7 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -1742,6 +1742,7 @@ print_pattern (pretty_printer *pp, const_rtx x, int verbose)
       print_exp (pp, x, verbose);
       break;
     case CLOBBER:
+    case CLOBBER_HIGH:
     case USE:
       pp_printf (pp, "%s ", GET_RTX_NAME (GET_CODE (x)));
       print_value (pp, XEXP (x, 0), verbose);
diff --git a/gcc/recog.c b/gcc/recog.c
index 0a8fa2ce46c..d7c69439683 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -1600,6 +1600,7 @@ decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs,
 	      {
 		if (GET_CODE (XVECEXP (body, 0, i)) == CLOBBER)
 		  break;		/* Past last SET */
+		gcc_assert (GET_CODE (XVECEXP (body, 0, i)) == SET);
 		if (operands)
 		  operands[i] = SET_DEST (XVECEXP (body, 0, i));
 		if (operand_locs)
@@ -3715,7 +3716,8 @@ store_data_bypass_p_1 (rtx_insn *out_insn, rtx in_set)
     {
       rtx out_exp = XVECEXP (out_pat, 0, i);
 
-      if (GET_CODE (out_exp) == CLOBBER || GET_CODE (out_exp) == USE)
+      if (GET_CODE (out_exp) == CLOBBER || GET_CODE (out_exp) == USE
+	  || GET_CODE (out_exp) == CLOBBER_HIGH)
 	continue;
 
       gcc_assert (GET_CODE (out_exp) == SET);
@@ -3746,7 +3748,8 @@ store_data_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn)
     {
       rtx in_exp = XVECEXP (in_pat, 0, i);
 
-      if (GET_CODE (in_exp) == CLOBBER || GET_CODE (in_exp) == USE)
+      if (GET_CODE (in_exp) == CLOBBER || GET_CODE (in_exp) == USE
+	  || GET_CODE (in_exp) == CLOBBER_HIGH)
 	continue;
 
       gcc_assert (GET_CODE (in_exp) == SET);
@@ -3798,7 +3801,7 @@ if_test_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn)
 	{
 	  rtx exp = XVECEXP (out_pat, 0, i);
 
-	  if (GET_CODE (exp) == CLOBBER)
+	  if (GET_CODE (exp) == CLOBBER  || GET_CODE (exp) == CLOBBER_HIGH)
 	    continue;
 
 	  gcc_assert (GET_CODE (exp) == SET);
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index 18132425ab2..1f805765b93 100644
--- a/gcc/regcprop.c
+++ b/gcc/regcprop.c
@@ -237,7 +237,11 @@ static void
 kill_clobbered_value (rtx x, const_rtx set, void *data)
 {
   struct value_data *const vd = (struct value_data *) data;
-  if (GET_CODE (set) == CLOBBER)
+  gcc_assert (GET_CODE (set) != CLOBBER_HIGH || REG_P (x));
+
+  if (GET_CODE (set) == CLOBBER
+      || (GET_CODE (set) == CLOBBER_HIGH
+	  && reg_is_clobbered_by_clobber_high (x, XEXP (set, 0))))
     kill_value (x, vd);
 }
 
@@ -257,7 +261,9 @@ kill_set_value (rtx x, const_rtx set, void *data)
   struct kill_set_value_data *ksvd = (struct kill_set_value_data *) data;
   if (rtx_equal_p (x, ksvd->ignore_set_reg))
     return;
-  if (GET_CODE (set) != CLOBBER)
+
+  gcc_assert (GET_CODE (set) != CLOBBER_HIGH || REG_P (x));
+  if (GET_CODE (set) != CLOBBER && GET_CODE (set) != CLOBBER_HIGH)
     {
       kill_value (x, ksvd->vd);
       if (REG_P (x))
diff --git a/gcc/reginfo.c b/gcc/reginfo.c
index f4071dac8b4..1f36d141c73 100644
--- a/gcc/reginfo.c
+++ b/gcc/reginfo.c
@@ -1100,6 +1100,10 @@ reg_scan_mark_refs (rtx x, rtx_insn *insn)
 	reg_scan_mark_refs (XEXP (XEXP (x, 0), 0), insn);
       break;
 
+    case CLOBBER_HIGH:
+      gcc_assert (!(MEM_P (XEXP (x, 0))));
+      break;
+
     case SET:
       /* Count a set of the destination if it is a register.  */
       for (dest = SET_DEST (x);
diff --git a/gcc/reload1.c b/gcc/reload1.c
index a4cc3ee02ea..8e15160c6ad 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -1339,6 +1339,8 @@ maybe_fix_stack_asms (void)
 	  rtx t = XVECEXP (pat, 0, i);
 	  if (GET_CODE (t) == CLOBBER && STACK_REG_P (XEXP (t, 0)))
 	    SET_HARD_REG_BIT (clobbered, REGNO (XEXP (t, 0)));
+	  /* CLOBBER_HIGH is only supported for LRA.  */
+	  gcc_assert (GET_CODE (t) != CLOBBER_HIGH);
 	}
 
       /* Get the operand values and constraints out of the insn.  */
@@ -2879,6 +2881,7 @@ eliminate_regs_1 (rtx x, machine_mode mem_mode, rtx insn,
       return x;
 
     case CLOBBER:
+    case CLOBBER_HIGH:
     case ASM_OPERANDS:
       gcc_assert (insn && DEBUG_INSN_P (insn));
       break;
@@ -3089,6 +3092,10 @@ elimination_effects (rtx x, machine_mode mem_mode)
       elimination_effects (XEXP (x, 0), mem_mode);
       return;
 
+    case CLOBBER_HIGH:
+      /* CLOBBER_HIGH is only supported for LRA.  */
+      return;
+
     case SET:
       /* Check for setting a register that we know about.  */
       if (REG_P (SET_DEST (x)))
@@ -3810,6 +3817,9 @@ mark_not_eliminable (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED)
   if (dest == hard_frame_pointer_rtx)
     return;
 
+  /* CLOBBER_HIGH is only supported for LRA.  */
+  gcc_assert (GET_CODE (x) != CLOBBER_HIGH);
+
   for (i = 0; i < NUM_ELIMINABLE_REGS; i++)
     if (reg_eliminate[i].can_eliminate && dest == reg_eliminate[i].to_rtx
 	&& (GET_CODE (x) != SET
@@ -4445,6 +4455,7 @@ scan_paradoxical_subregs (rtx x)
     case PC:
     case USE:
     case CLOBBER:
+    case CLOBBER_HIGH:
       return;
 
     case SUBREG:
@@ -4899,7 +4910,7 @@ reload_as_needed (int live_known)
    to be forgotten later.  */
 
 static void
-forget_old_reloads_1 (rtx x, const_rtx ignored ATTRIBUTE_UNUSED,
+forget_old_reloads_1 (rtx x, const_rtx setter,
 		      void *data)
 {
   unsigned int regno;
@@ -4919,6 +4930,9 @@ forget_old_reloads_1 (rtx x, const_rtx ignored ATTRIBUTE_UNUSED,
   if (!REG_P (x))
     return;
 
+  /* CLOBBER_HIGH is only supported for LRA.  */
+  gcc_assert (GET_CODE (setter) != CLOBBER_HIGH);
+
   regno = REGNO (x);
 
   if (regno >= FIRST_PSEUDO_REGISTER)
diff --git a/gcc/reorg.c b/gcc/reorg.c
index 904d91ec9e8..f8a986cea1d 100644
--- a/gcc/reorg.c
+++ b/gcc/reorg.c
@@ -397,7 +397,8 @@ find_end_label (rtx kind)
   while (NOTE_P (insn)
 	 || (NONJUMP_INSN_P (insn)
 	     && (GET_CODE (PATTERN (insn)) == USE
-		 || GET_CODE (PATTERN (insn)) == CLOBBER)))
+		 || GET_CODE (PATTERN (insn)) == CLOBBER
+		 || GET_CODE (PATTERN (insn)) == CLOBBER_HIGH)))
     insn = PREV_INSN (insn);
 
   /* When a target threads its epilogue we might already have a
@@ -1297,7 +1298,8 @@ try_merge_delay_insns (rtx_insn *insn, rtx_insn *thread)
 
       /* TRIAL must be a CALL_INSN or INSN.  Skip USE and CLOBBER.  */
       if (NONJUMP_INSN_P (trial)
-	  && (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER))
+	  && (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
+	      || GET_CODE (pat) == CLOBBER_HIGH))
 	continue;
 
       if (GET_CODE (next_to_match) == GET_CODE (trial)
@@ -1491,7 +1493,8 @@ redundant_insn (rtx insn, rtx_insn *target, const vec<rtx_insn *> &delay_list)
       --insns_to_search;
 
       pat = PATTERN (trial);
-      if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)
+      if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
+	  || GET_CODE (pat) == CLOBBER_HIGH)
 	continue;
 
       if (GET_CODE (trial) == DEBUG_INSN)
@@ -1589,7 +1592,8 @@ redundant_insn (rtx insn, rtx_insn *target, const vec<rtx_insn *> &delay_list)
       --insns_to_search;
 
       pat = PATTERN (trial);
-      if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)
+      if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
+	  || GET_CODE (pat) == CLOBBER_HIGH)
 	continue;
 
       if (GET_CODE (trial) == DEBUG_INSN)
@@ -1701,7 +1705,8 @@ own_thread_p (rtx thread, rtx label, int allow_fallthrough)
 	|| LABEL_P (insn)
 	|| (NONJUMP_INSN_P (insn)
 	    && GET_CODE (PATTERN (insn)) != USE
-	    && GET_CODE (PATTERN (insn)) != CLOBBER))
+	    && GET_CODE (PATTERN (insn)) != CLOBBER
+	    && GET_CODE (PATTERN (insn)) != CLOBBER_HIGH))
       return 0;
 
   return 1;
@@ -2024,7 +2029,8 @@ fill_simple_delay_slots (int non_jumps_p)
 	      pat = PATTERN (trial);
 
 	      /* Stand-alone USE and CLOBBER are just for flow.  */
-	      if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)
+	      if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
+		  || GET_CODE (pat) == CLOBBER_HIGH)
 		continue;
 
 	      /* And DEBUG_INSNs never go into delay slots.  */
@@ -2150,7 +2156,8 @@ fill_simple_delay_slots (int non_jumps_p)
 	      pat = PATTERN (trial);
 
 	      /* Stand-alone USE and CLOBBER are just for flow.  */
-	      if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)
+	      if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
+		  || GET_CODE (pat) == CLOBBER_HIGH)
 		continue;
 
 	      /* And DEBUG_INSNs do not go in delay slots.  */
@@ -2418,7 +2425,8 @@ fill_slots_from_thread (rtx_jump_insn *insn, rtx condition,
 	}
 
       pat = PATTERN (trial);
-      if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)
+      if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
+	  || GET_CODE (pat) == CLOBBER_HIGH)
 	continue;
 
       if (GET_CODE (trial) == DEBUG_INSN)
@@ -3818,7 +3826,8 @@ dbr_schedule (rtx_insn *first)
 	  if (! insn->deleted ()
 	      && NONJUMP_INSN_P (insn)
 	      && GET_CODE (PATTERN (insn)) != USE
-	      && GET_CODE (PATTERN (insn)) != CLOBBER)
+	      && GET_CODE (PATTERN (insn)) != CLOBBER
+	      && GET_CODE (PATTERN (insn)) != CLOBBER_HIGH)
 	    {
 	      if (GET_CODE (PATTERN (insn)) == SEQUENCE)
 		{
diff --git a/gcc/resource.c b/gcc/resource.c
index 0822daebde7..fdfab6916d4 100644
--- a/gcc/resource.c
+++ b/gcc/resource.c
@@ -108,6 +108,11 @@ update_live_status (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED)
   if (GET_CODE (x) == CLOBBER)
     for (i = first_regno; i < last_regno; i++)
       CLEAR_HARD_REG_BIT (current_live_regs, i);
+  else if (GET_CODE (x) == CLOBBER_HIGH)
+    /* No current target supports both branch delay slots and CLOBBER_HIGH.
+       We'd need more elaborate liveness tracking to handle that
+       combination.  */
+    gcc_unreachable ();
   else
     for (i = first_regno; i < last_regno; i++)
       {
@@ -293,6 +298,7 @@ mark_referenced_resources (rtx x, struct resources *res,
       return;
 
     case CLOBBER:
+    case CLOBBER_HIGH:
       return;
 
     case CALL_INSN:
@@ -668,9 +674,15 @@ mark_set_resources (rtx x, struct resources *res, int in_dest,
 
 	  for (link = CALL_INSN_FUNCTION_USAGE (call_insn);
 	       link; link = XEXP (link, 1))
-	    if (GET_CODE (XEXP (link, 0)) == CLOBBER)
-	      mark_set_resources (SET_DEST (XEXP (link, 0)), res, 1,
-				  MARK_SRC_DEST);
+	    {
+	      /* We could support CLOBBER_HIGH and treat it in the same way as
+		 HARD_REGNO_CALL_PART_CLOBBERED, but no port needs that
+		 yet.  */
+	      gcc_assert (GET_CODE (XEXP (link, 0)) != CLOBBER_HIGH);
+	      if (GET_CODE (XEXP (link, 0)) == CLOBBER)
+		mark_set_resources (SET_DEST (XEXP (link, 0)), res, 1,
+				    MARK_SRC_DEST);
+	    }
 
 	  /* Check for a REG_SETJMP.  If it exists, then we must
 	     assume that this call can clobber any register.  */
@@ -713,6 +725,12 @@ mark_set_resources (rtx x, struct resources *res, int in_dest,
       mark_set_resources (XEXP (x, 0), res, 1, MARK_SRC_DEST);
       return;
 
+    case CLOBBER_HIGH:
+      /* No current target supports both branch delay slots and CLOBBER_HIGH.
+	 We'd need more elaborate liveness tracking to handle that
+	 combination.  */
+      gcc_unreachable ();
+
     case SEQUENCE:
       {
         rtx_sequence *seq = as_a <rtx_sequence *> (x);
diff --git a/gcc/rtl.c b/gcc/rtl.c
index 985db1c14f0..f9146afcf2c 100644
--- a/gcc/rtl.c
+++ b/gcc/rtl.c
@@ -304,6 +304,10 @@ copy_rtx (rtx orig)
 	return orig;
       break;
 
+    case CLOBBER_HIGH:
+	gcc_assert (REG_P (XEXP (orig, 0)));
+	return orig;
+
     case CONST:
       if (shared_const_p (orig))
 	return orig;
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 1cab1545744..6c620a4a3e5 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -1198,6 +1198,10 @@ reg_referenced_p (const_rtx x, const_rtx body)
 	  return 1;
       return 0;
 
+    case CLOBBER_HIGH:
+      gcc_assert (REG_P (XEXP (body, 0)));
+      return 0;
+
     case COND_EXEC:
       if (reg_overlap_mentioned_p (x, COND_EXEC_TEST (body)))
 	return 1;
@@ -1420,7 +1424,11 @@ set_of_1 (rtx x, const_rtx pat, void *data1)
 {
   struct set_of_data *const data = (struct set_of_data *) (data1);
   if (rtx_equal_p (x, data->pat)
-      || (!MEM_P (x) && reg_overlap_mentioned_p (data->pat, x)))
+      || (GET_CODE (pat) == CLOBBER_HIGH
+	  && REGNO(data->pat) == REGNO(XEXP (pat, 0))
+	  && reg_is_clobbered_by_clobber_high (data->pat, XEXP (pat, 0)))
+      || (GET_CODE (pat) != CLOBBER_HIGH && !MEM_P (x)
+	  && reg_overlap_mentioned_p (data->pat, x)))
     data->found = pat;
 }
 
@@ -1509,6 +1517,7 @@ single_set_2 (const rtx_insn *insn, const_rtx pat)
 	    {
 	    case USE:
 	    case CLOBBER:
+	    case CLOBBER_HIGH:
 	      break;
 
 	    case SET:
@@ -1663,7 +1672,8 @@ noop_move_p (const rtx_insn *insn)
 	  rtx tem = XVECEXP (pat, 0, i);
 
 	  if (GET_CODE (tem) == USE
-	      || GET_CODE (tem) == CLOBBER)
+	      || GET_CODE (tem) == CLOBBER
+	      || GET_CODE (tem) == CLOBBER_HIGH)
 	    continue;
 
 	  if (GET_CODE (tem) != SET || ! set_noop_p (tem))
@@ -1895,7 +1905,9 @@ note_stores (const_rtx x, void (*fun) (rtx, const_rtx, void *), void *data)
   if (GET_CODE (x) == COND_EXEC)
     x = COND_EXEC_CODE (x);
 
-  if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
+  if (GET_CODE (x) == SET
+      || GET_CODE (x) == CLOBBER
+      || GET_CODE (x) == CLOBBER_HIGH)
     {
       rtx dest = SET_DEST (x);
 
diff --git a/gcc/sched-deps.c b/gcc/sched-deps.c
index 120b5f0ddc1..f89f28269fd 100644
--- a/gcc/sched-deps.c
+++ b/gcc/sched-deps.c
@@ -2319,6 +2319,13 @@ sched_analyze_reg (struct deps_desc *deps, int regno, machine_mode mode,
 	  while (--i >= 0)
 	    note_reg_use (regno + i);
 	}
+      else if (ref == CLOBBER_HIGH)
+	{
+	  gcc_assert (i == 1);
+	  /* We don't know the current state of the register, so have to treat
+	     the clobber high as a full clobber.  */
+	  note_reg_clobber (regno);
+	}
       else
 	{
 	  while (--i >= 0)
@@ -2342,6 +2349,8 @@ sched_analyze_reg (struct deps_desc *deps, int regno, machine_mode mode,
       else if (ref == USE)
 	note_reg_use (regno);
       else
+	/* For CLOBBER_HIGH, we don't know the current state of the register,
+	   so have to treat it as a full clobber.  */
 	note_reg_clobber (regno);
 
       /* Pseudos that are REG_EQUIV to something may be replaced
@@ -2962,7 +2971,7 @@ sched_analyze_insn (struct deps_desc *deps, rtx x, rtx_insn *insn)
 	      sub = COND_EXEC_CODE (sub);
 	      code = GET_CODE (sub);
 	    }
-	  if (code == SET || code == CLOBBER)
+	  else if (code == SET || code == CLOBBER || code == CLOBBER_HIGH)
 	    sched_analyze_1 (deps, sub, insn);
 	  else
 	    sched_analyze_2 (deps, sub, insn);
@@ -2978,6 +2987,10 @@ sched_analyze_insn (struct deps_desc *deps, rtx x, rtx_insn *insn)
 	{
 	  if (GET_CODE (XEXP (link, 0)) == CLOBBER)
 	    sched_analyze_1 (deps, XEXP (link, 0), insn);
+	  else if (GET_CODE (XEXP (link, 0)) == CLOBBER_HIGH)
+	    /* We could support CLOBBER_HIGH and treat it in the same way as
+	      HARD_REGNO_CALL_PART_CLOBBERED, but no port needs that yet.  */
+	    gcc_unreachable ();
 	  else if (GET_CODE (XEXP (link, 0)) != SET)
 	    sched_analyze_2 (deps, XEXP (link, 0), insn);
 	}
-- 
2.15.2 (Apple Git-101.1)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v2 4/7] lra support for clobber_high
  2018-07-26  9:14 [PATCH v2 0/7] Support partial clobbers around TLS calls on Aarch64 SVE Alan Hayward
@ 2018-07-26  9:14 ` Alan Hayward
  2018-08-04  4:21   ` Jeff Law
  2018-07-26  9:14 ` [PATCH v2 2/7] Generation support for CLOBBER_HIGH Alan Hayward
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Alan Hayward @ 2018-07-26  9:14 UTC (permalink / raw)
  To: gcc-patches; +Cc: nd, Alan Hayward

The lra specific changes for clobber_high.

2018-07-25  Alan Hayward  <alan.hayward@arm.com>

	* lra-eliminations.c (lra_eliminate_regs_1): Check for clobber high.
	(mark_not_eliminable): Likewise.
	* lra-int.h (struct lra_insn_reg): Add clobber high marker.
	* lra-lives.c (process_bb_lives): Check for clobber high.
	* lra.c (new_insn_reg): Remember clobber highs.
	(collect_non_operand_hard_regs): Check for clobber high.
	(lra_set_insn_recog_data): Likewise.
	(add_regs_to_insn_regno_info): Likewise.
	(lra_update_insn_regno_info): Likewise.
---
 gcc/lra-eliminations.c | 11 +++++++++
 gcc/lra-int.h          |  2 ++
 gcc/lra-lives.c        | 31 ++++++++++++++++--------
 gcc/lra.c              | 66 +++++++++++++++++++++++++++++++++++---------------
 4 files changed, 80 insertions(+), 30 deletions(-)

diff --git a/gcc/lra-eliminations.c b/gcc/lra-eliminations.c
index f5f104020b3..d0cfaa8714a 100644
--- a/gcc/lra-eliminations.c
+++ b/gcc/lra-eliminations.c
@@ -654,6 +654,7 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
       return x;
 
     case CLOBBER:
+    case CLOBBER_HIGH:
     case SET:
       gcc_unreachable ();
 
@@ -806,6 +807,16 @@ mark_not_eliminable (rtx x, machine_mode mem_mode)
 	    setup_can_eliminate (ep, false);
       return;
 
+    case CLOBBER_HIGH:
+      gcc_assert (REG_P (XEXP (x, 0)));
+      gcc_assert (REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER);
+      for (ep = reg_eliminate;
+	   ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
+	   ep++)
+	if (reg_is_clobbered_by_clobber_high (ep->to_rtx, XEXP (x, 0)))
+	  setup_can_eliminate (ep, false);
+      return;
+
     case SET:
       if (SET_DEST (x) == stack_pointer_rtx
 	  && GET_CODE (SET_SRC (x)) == PLUS
diff --git a/gcc/lra-int.h b/gcc/lra-int.h
index 86e103b7480..5267b53c5e3 100644
--- a/gcc/lra-int.h
+++ b/gcc/lra-int.h
@@ -168,6 +168,8 @@ struct lra_insn_reg
   /* True if there is an early clobber alternative for this
      operand.  */
   unsigned int early_clobber : 1;
+  /* True if the reg is clobber highed by the operand.  */
+  unsigned int clobber_high : 1;
   /* The corresponding regno of the register.  */
   int regno;
   /* Next reg info of the same insn.  */
diff --git a/gcc/lra-lives.c b/gcc/lra-lives.c
index 920fd02b997..433c819d9e3 100644
--- a/gcc/lra-lives.c
+++ b/gcc/lra-lives.c
@@ -658,7 +658,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
       bool call_p;
       int n_alt, dst_regno, src_regno;
       rtx set;
-      struct lra_insn_reg *reg;
+      struct lra_insn_reg *reg, *hr;
 
       if (!NONDEBUG_INSN_P (curr_insn))
 	continue;
@@ -690,11 +690,12 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
 		break;
 	      }
 	  for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
-	    if (reg->type != OP_IN)
+	    if (reg->type != OP_IN && !reg->clobber_high)
 	      {
 		remove_p = false;
 		break;
 	      }
+
 	  if (remove_p && ! volatile_refs_p (PATTERN (curr_insn)))
 	    {
 	      dst_regno = REGNO (SET_DEST (set));
@@ -812,14 +813,24 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
 	 unused values because they still conflict with quantities
 	 that are live at the time of the definition.  */
       for (reg = curr_id->regs; reg != NULL; reg = reg->next)
-	if (reg->type != OP_IN)
-	  {
-	    need_curr_point_incr
-	      |= mark_regno_live (reg->regno, reg->biggest_mode,
-				  curr_point);
-	    check_pseudos_live_through_calls (reg->regno,
-					      last_call_used_reg_set);
-	  }
+	{
+	  if (reg->type != OP_IN)
+	    {
+	      need_curr_point_incr
+		|= mark_regno_live (reg->regno, reg->biggest_mode,
+				    curr_point);
+	      check_pseudos_live_through_calls (reg->regno,
+						last_call_used_reg_set);
+	    }
+
+	  if (reg->regno >= FIRST_PSEUDO_REGISTER)
+	    for (hr = curr_static_id->hard_regs; hr != NULL; hr = hr->next)
+	      if (hr->clobber_high
+		  && maybe_gt (GET_MODE_SIZE (PSEUDO_REGNO_MODE (reg->regno)),
+			       GET_MODE_SIZE (hr->biggest_mode)))
+		SET_HARD_REG_BIT (lra_reg_info[reg->regno].conflict_hard_regs,
+				  hr->regno);
+	}
 
       for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
 	if (reg->type != OP_IN)
diff --git a/gcc/lra.c b/gcc/lra.c
index b410b90f126..aa768fb2a23 100644
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -535,13 +535,14 @@ object_allocator<lra_insn_reg> lra_insn_reg_pool ("insn regs");
    clobbered in the insn (EARLY_CLOBBER), and reference to the next
    insn reg info (NEXT).  If REGNO can be early clobbered,
    alternatives in which it can be early clobbered are given by
-   EARLY_CLOBBER_ALTS.  */
+   EARLY_CLOBBER_ALTS.  CLOBBER_HIGH marks if reference is a clobber
+   high.  */
 static struct lra_insn_reg *
 new_insn_reg (rtx_insn *insn, int regno, enum op_type type,
 	      machine_mode mode,
 	      bool subreg_p, bool early_clobber,
 	      alternative_mask early_clobber_alts,
-	      struct lra_insn_reg *next)
+	      struct lra_insn_reg *next, bool clobber_high)
 {
   lra_insn_reg *ir = lra_insn_reg_pool.allocate ();
   ir->type = type;
@@ -552,6 +553,7 @@ new_insn_reg (rtx_insn *insn, int regno, enum op_type type,
   ir->subreg_p = subreg_p;
   ir->early_clobber = early_clobber;
   ir->early_clobber_alts = early_clobber_alts;
+  ir->clobber_high = clobber_high;
   ir->regno = regno;
   ir->next = next;
   return ir;
@@ -821,12 +823,13 @@ setup_operand_alternative (lra_insn_recog_data_t data,
    not the insn operands, in X with TYPE (in/out/inout) and flag that
    it is early clobbered in the insn (EARLY_CLOBBER) and add the info
    to LIST.  X is a part of insn given by DATA.	 Return the result
-   list.  */
+   list.  CLOBBER_HIGH marks if X is a clobber high.  */
 static struct lra_insn_reg *
 collect_non_operand_hard_regs (rtx_insn *insn, rtx *x,
 			       lra_insn_recog_data_t data,
 			       struct lra_insn_reg *list,
-			       enum op_type type, bool early_clobber)
+			       enum op_type type, bool early_clobber,
+			       bool clobber_high)
 {
   int i, j, regno, last;
   bool subreg_p;
@@ -890,7 +893,8 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x,
 #endif
 	      list = new_insn_reg (data->insn, regno, type, mode, subreg_p,
 				   early_clobber,
-				   early_clobber ? ALL_ALTERNATIVES : 0, list);
+				   early_clobber ? ALL_ALTERNATIVES : 0, list,
+				   clobber_high);
 	    }
 	}
       return list;
@@ -899,24 +903,31 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x,
     {
     case SET:
       list = collect_non_operand_hard_regs (insn, &SET_DEST (op), data,
-					    list, OP_OUT, false);
+					    list, OP_OUT, false, false);
       list = collect_non_operand_hard_regs (insn, &SET_SRC (op), data,
-					    list, OP_IN, false);
+					    list, OP_IN, false, false);
       break;
     case CLOBBER:
       /* We treat clobber of non-operand hard registers as early clobber.  */
       list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data,
-					    list, OP_OUT, true);
+					    list, OP_OUT, true, false);
+      break;
+    case CLOBBER_HIGH:
+      /* Clobber high should always span exactly one register.  */
+      gcc_assert (REG_NREGS (XEXP (op, 0)) == 1);
+      /* We treat clobber of non-operand hard registers as early clobber.  */
+      list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data,
+					    list, OP_OUT, true, true);
       break;
     case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC:
       list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data,
-					    list, OP_INOUT, false);
+					    list, OP_INOUT, false, false);
       break;
     case PRE_MODIFY: case POST_MODIFY:
       list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data,
-					    list, OP_INOUT, false);
+					    list, OP_INOUT, false, false);
       list = collect_non_operand_hard_regs (insn, &XEXP (op, 1), data,
-					    list, OP_IN, false);
+					    list, OP_IN, false, false);
       break;
     default:
       fmt = GET_RTX_FORMAT (code);
@@ -924,11 +935,12 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x,
 	{
 	  if (fmt[i] == 'e')
 	    list = collect_non_operand_hard_regs (insn, &XEXP (op, i), data,
-						  list, OP_IN, false);
+						  list, OP_IN, false, false);
 	  else if (fmt[i] == 'E')
 	    for (j = XVECLEN (op, i) - 1; j >= 0; j--)
 	      list = collect_non_operand_hard_regs (insn, &XVECEXP (op, i, j),
-						    data, list, OP_IN, false);
+						    data, list, OP_IN, false,
+						    false);
 	}
     }
   return list;
@@ -1081,7 +1093,7 @@ lra_set_insn_recog_data (rtx_insn *insn)
   else
     insn_static_data->hard_regs
       = collect_non_operand_hard_regs (insn, &PATTERN (insn), data,
-				       NULL, OP_IN, false);
+				       NULL, OP_IN, false, false);
   data->arg_hard_regs = NULL;
   if (CALL_P (insn))
     {
@@ -1107,6 +1119,11 @@ lra_set_insn_recog_data (rtx_insn *insn)
 	      arg_hard_regs[n_hard_regs++]
 		= regno + i + (use_p ? 0 : FIRST_PSEUDO_REGISTER);
 	  }
+	else if (GET_CODE (XEXP (link, 0)) == CLOBBER_HIGH)
+	  /* We could support CLOBBER_HIGH and treat it in the same way as
+	     HARD_REGNO_CALL_PART_CLOBBERED, but no port needs that yet.  */
+	  gcc_unreachable ();
+
       if (n_hard_regs != 0)
 	{
 	  arg_hard_regs[n_hard_regs++] = -1;
@@ -1469,7 +1486,7 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x,
 	{
 	  data->regs = new_insn_reg (data->insn, regno, type, mode, subreg_p,
 				     early_clobber, early_clobber_alts,
-				     data->regs);
+				     data->regs, false);
 	  return;
 	}
       else
@@ -1482,7 +1499,8 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x,
 		     structure.  */
 		  data->regs = new_insn_reg (data->insn, regno, type, mode,
 					     subreg_p, early_clobber,
-					     early_clobber_alts, data->regs);
+					     early_clobber_alts, data->regs,
+					     false);
 		else
 		  {
 		    if (curr->type != type)
@@ -1509,6 +1527,8 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x,
       add_regs_to_insn_regno_info (data, XEXP (x, 0), insn, OP_OUT,
 				   true, ALL_ALTERNATIVES);
       break;
+    case CLOBBER_HIGH:
+      gcc_unreachable ();
     case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC:
       add_regs_to_insn_regno_info (data, XEXP (x, 0), insn, OP_INOUT, false, 0);
       break;
@@ -1643,10 +1663,16 @@ lra_update_insn_regno_info (rtx_insn *insn)
     for (link = CALL_INSN_FUNCTION_USAGE (insn);
 	 link != NULL_RTX;
 	 link = XEXP (link, 1))
-      if (((code = GET_CODE (XEXP (link, 0))) == USE || code == CLOBBER)
-	  && MEM_P (XEXP (XEXP (link, 0), 0)))
-	add_regs_to_insn_regno_info (data, XEXP (XEXP (link, 0), 0), insn,
-				     code == USE ? OP_IN : OP_OUT, false, 0);
+      {
+	code = GET_CODE (XEXP (link, 0));
+	/* We could support CLOBBER_HIGH and treat it in the same way as
+	   HARD_REGNO_CALL_PART_CLOBBERED, but no port needs that yet.  */
+	gcc_assert (code != CLOBBER_HIGH);
+	if ((code == USE || code == CLOBBER)
+	    && MEM_P (XEXP (XEXP (link, 0), 0)))
+	  add_regs_to_insn_regno_info (data, XEXP (XEXP (link, 0), 0), insn,
+				       code == USE ? OP_IN : OP_OUT, false, 0);
+      }
   if (NONDEBUG_INSN_P (insn))
     setup_insn_reg_info (data, freq);
 }
-- 
2.15.2 (Apple Git-101.1)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v2 1/7] Add CLOBBER_HIGH expression
  2018-07-26  9:14 [PATCH v2 0/7] Support partial clobbers around TLS calls on Aarch64 SVE Alan Hayward
                   ` (2 preceding siblings ...)
  2018-07-26  9:14 ` [PATCH v2 6/7] Remaining support for clobber high Alan Hayward
@ 2018-07-26  9:14 ` Alan Hayward
  2018-08-04  4:04   ` Jeff Law
  2018-07-26  9:14 ` [PATCH v2 5/7] cse support for clobber_high Alan Hayward
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Alan Hayward @ 2018-07-26  9:14 UTC (permalink / raw)
  To: gcc-patches; +Cc: nd, Alan Hayward

Includes documentation.

2018-07-25  Alan Hayward  <alan.hayward@arm.com>

	* doc/rtl.texi (clobber_high): Add.
	(parallel): Add in clobber high
	* rtl.c (rtl_check_failed_code3): Add function.
	* rtl.def (CLOBBER_HIGH): Add expression.
	* rtl.h (RTL_CHECKC3): Add macro.
	(rtl_check_failed_code3): Add declaration.
	(XC3EXP): Add macro.
---
 gcc/doc/rtl.texi | 15 ++++++++++++++-
 gcc/rtl.c        | 11 +++++++++++
 gcc/rtl.def      | 10 ++++++++++
 gcc/rtl.h        | 16 +++++++++++++++-
 4 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index a37d9ac5389..20c57732679 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -3296,6 +3296,18 @@ There is one other known use for clobbering a pseudo register in a
 clobbered by the insn.  In this case, using the same pseudo register in
 the clobber and elsewhere in the insn produces the expected results.
 
+@findex clobber_high
+@item (clobber_high @var{x})
+Represents the storing or possible storing of an unpredictable,
+undescribed value into the upper parts of @var{x}. The mode of the expression
+represents the lower parts of the register which will not be overwritten.
+@code{reg} must be a reg expression.
+
+One place this is used is when calling into functions where the registers are
+preserved, but only up to a given number of bits.  For example when using
+Aarch64 SVE, calling a TLS descriptor will cause only the lower 128 bits of
+each of the vector registers to be preserved.
+
 @findex use
 @item (use @var{x})
 Represents the use of the value of @var{x}.  It indicates that the
@@ -3349,7 +3361,8 @@ Represents several side effects performed in parallel.  The square
 brackets stand for a vector; the operand of @code{parallel} is a
 vector of expressions.  @var{x0}, @var{x1} and so on are individual
 side effect expressions---expressions of code @code{set}, @code{call},
-@code{return}, @code{simple_return}, @code{clobber} or @code{use}.
+@code{return}, @code{simple_return}, @code{clobber} @code{use} or
+@code{clobber_high}.
 
 ``In parallel'' means that first all the values used in the individual
 side-effects are computed, and second all the actual side-effects are
diff --git a/gcc/rtl.c b/gcc/rtl.c
index 90bbc7c6861..985db1c14f0 100644
--- a/gcc/rtl.c
+++ b/gcc/rtl.c
@@ -856,6 +856,17 @@ rtl_check_failed_code2 (const_rtx r, enum rtx_code code1, enum rtx_code code2,
      func, trim_filename (file), line);
 }
 
+void
+rtl_check_failed_code3 (const_rtx r, enum rtx_code code1, enum rtx_code code2,
+			enum rtx_code code3, const char *file, int line,
+			const char *func)
+{
+  internal_error
+    ("RTL check: expected code '%s', '%s' or '%s', have '%s' in %s, at %s:%d",
+     GET_RTX_NAME (code1), GET_RTX_NAME (code2), GET_RTX_NAME (code3),
+     GET_RTX_NAME (GET_CODE (r)), func, trim_filename (file), line);
+}
+
 void
 rtl_check_failed_code_mode (const_rtx r, enum rtx_code code, machine_mode mode,
 			    bool not_mode, const char *file, int line,
diff --git a/gcc/rtl.def b/gcc/rtl.def
index 2578a0ccb9e..0ed27505545 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -312,6 +312,16 @@ DEF_RTL_EXPR(USE, "use", "e", RTX_EXTRA)
    is considered undeletable before reload.  */
 DEF_RTL_EXPR(CLOBBER, "clobber", "e", RTX_EXTRA)
 
+/* Indicate that the upper parts of something are clobbered in a way that we
+   don't want to explain.  The MODE references the lower bits that will be
+   preserved.  Anything above that size will be clobbered.
+
+   CLOBBER_HIGH only occurs as the operand of a PARALLEL rtx.  It cannot appear
+   in other contexts, and unlike CLOBBER, it cannot appear on its own.
+   CLOBBER_HIGH can only be used with fixed register rtxes.  */
+
+DEF_RTL_EXPR(CLOBBER_HIGH, "clobber_high", "e", RTX_EXTRA)
+
 /* Call a subroutine.
    Operand 1 is the address to call.
    Operand 2 is the number of arguments.  */
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 565ce3abbe4..5e07e9bee80 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1100,6 +1100,14 @@ is_a_helper <rtx_note *>::test (rtx_insn *insn)
 			       __FUNCTION__); \
      &_rtx->u.fld[_n]; }))
 
+#define RTL_CHECKC3(RTX, N, C1, C2, C3) __extension__			\
+(*({ __typeof (RTX) const _rtx = (RTX); const int _n = (N);		\
+     const enum rtx_code _code = GET_CODE (_rtx);			\
+     if (_code != (C1) && _code != (C2) && _code != (C3))		\
+       rtl_check_failed_code3 (_rtx, (C1), (C2), (C3), __FILE__,	\
+			       __LINE__, __FUNCTION__);			\
+     &_rtx->u.fld[_n]; }))
+
 #define RTVEC_ELT(RTVEC, I) __extension__				\
 (*({ __typeof (RTVEC) const _rtvec = (RTVEC); const int _i = (I);	\
      if (_i < 0 || _i >= GET_NUM_ELEM (_rtvec))				\
@@ -1190,6 +1198,10 @@ extern void rtl_check_failed_code1 (const_rtx, enum rtx_code, const char *,
 extern void rtl_check_failed_code2 (const_rtx, enum rtx_code, enum rtx_code,
 				    const char *, int, const char *)
     ATTRIBUTE_NORETURN ATTRIBUTE_COLD;
+extern void rtl_check_failed_code3 (const_rtx, enum rtx_code, enum rtx_code,
+				    enum rtx_code, const char *, int,
+				    const char *)
+    ATTRIBUTE_NORETURN ATTRIBUTE_COLD;
 extern void rtl_check_failed_code_mode (const_rtx, enum rtx_code, machine_mode,
 					bool, const char *, int, const char *)
     ATTRIBUTE_NORETURN ATTRIBUTE_COLD;
@@ -1208,6 +1220,7 @@ extern void rtvec_check_failed_bounds (const_rtvec, int, const char *, int,
 #define RTL_CHECK2(RTX, N, C1, C2)  ((RTX)->u.fld[N])
 #define RTL_CHECKC1(RTX, N, C)	    ((RTX)->u.fld[N])
 #define RTL_CHECKC2(RTX, N, C1, C2) ((RTX)->u.fld[N])
+#define RTL_CHECKC3(RTX, N, C1, C2, C3) ((RTX)->u.fld[N])
 #define RTVEC_ELT(RTVEC, I)	    ((RTVEC)->elem[I])
 #define XWINT(RTX, N)		    ((RTX)->u.hwint[N])
 #define CWI_ELT(RTX, I)		    ((RTX)->u.hwiv.elem[I])
@@ -1362,6 +1375,7 @@ extern void rtl_check_failed_flag (const char *, const_rtx, const char *,
 #define XCVECLEN(RTX, N, C)	GET_NUM_ELEM (XCVEC (RTX, N, C))
 
 #define XC2EXP(RTX, N, C1, C2)      (RTL_CHECKC2 (RTX, N, C1, C2).rt_rtx)
+#define XC3EXP(RTX, N, C1, C2, C3)  (RTL_CHECKC3 (RTX, N, C1, C2, C3).rt_rtx)
 \f
 
 /* Methods of rtx_expr_list.  */
@@ -2632,7 +2646,7 @@ do {								        \
 
 /* For a SET rtx, SET_DEST is the place that is set
    and SET_SRC is the value it is set to.  */
-#define SET_DEST(RTX) XC2EXP (RTX, 0, SET, CLOBBER)
+#define SET_DEST(RTX) XC3EXP (RTX, 0, SET, CLOBBER, CLOBBER_HIGH)
 #define SET_SRC(RTX) XCEXP (RTX, 1, SET)
 #define SET_IS_RETURN_P(RTX)						\
   (RTL_FLAG_CHECK1 ("SET_IS_RETURN_P", (RTX), SET)->jump)
-- 
2.15.2 (Apple Git-101.1)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v2 5/7] cse support for clobber_high
  2018-07-26  9:14 [PATCH v2 0/7] Support partial clobbers around TLS calls on Aarch64 SVE Alan Hayward
                   ` (3 preceding siblings ...)
  2018-07-26  9:14 ` [PATCH v2 1/7] Add CLOBBER_HIGH expression Alan Hayward
@ 2018-07-26  9:14 ` Alan Hayward
  2018-08-04  4:26   ` Jeff Law
  2018-07-26  9:14 ` [PATCH v2 3/7] Add func to check if register is clobbered by clobber_high Alan Hayward
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Alan Hayward @ 2018-07-26  9:14 UTC (permalink / raw)
  To: gcc-patches; +Cc: nd, Alan Hayward

The cse specific changes for clobber_high.

2018-07-25  Alan Hayward  <alan.hayward@arm.com>

	* cse.c (invalidate_reg): New function extracted from...
	(invalidate): ...here.
	(canonicalize_insn): Check for clobber high.
	(invalidate_from_clobbers): invalidate clobber highs.
	(invalidate_from_sets_and_clobbers): Likewise.
	(count_reg_usage): Check for clobber high.
	(insn_live_p): Likewise.
	* cselib.c (cselib_expand_value_rtx_1):Likewise.
	(cselib_invalidate_regno): Check for clobber in setter.
	(cselib_invalidate_rtx): Pass through setter.
	(cselib_invalidate_rtx_note_stores):
	(cselib_process_insn): Check for clobber high.
	* cselib.h (cselib_invalidate_rtx): Add operand.
---
 gcc/cse.c    | 187 +++++++++++++++++++++++++++++++++++++++--------------------
 gcc/cselib.c |  42 ++++++++++----
 gcc/cselib.h |   2 +-
 3 files changed, 156 insertions(+), 75 deletions(-)

diff --git a/gcc/cse.c b/gcc/cse.c
index 4e94152b380..3d7888b7093 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -559,6 +559,7 @@ static struct table_elt *insert_with_costs (rtx, struct table_elt *, unsigned,
 static struct table_elt *insert (rtx, struct table_elt *, unsigned,
 				 machine_mode);
 static void merge_equiv_classes (struct table_elt *, struct table_elt *);
+static void invalidate_reg (rtx, bool);
 static void invalidate (rtx, machine_mode);
 static void remove_invalid_refs (unsigned int);
 static void remove_invalid_subreg_refs (unsigned int, poly_uint64,
@@ -1818,7 +1819,85 @@ check_dependence (const_rtx x, rtx exp, machine_mode mode, rtx addr)
     }
   return false;
 }
-\f
+
+/* Remove from the hash table, or mark as invalid, all expressions whose
+   values could be altered by storing in register X.
+
+   CLOBBER_HIGH is set if X was part of a CLOBBER_HIGH expression.  */
+
+static void
+invalidate_reg (rtx x, bool clobber_high)
+{
+  gcc_assert (GET_CODE (x) == REG);
+
+  /* If X is a register, dependencies on its contents are recorded
+     through the qty number mechanism.  Just change the qty number of
+     the register, mark it as invalid for expressions that refer to it,
+     and remove it itself.  */
+  unsigned int regno = REGNO (x);
+  unsigned int hash = HASH (x, GET_MODE (x));
+
+  /* Remove REGNO from any quantity list it might be on and indicate
+     that its value might have changed.  If it is a pseudo, remove its
+     entry from the hash table.
+
+     For a hard register, we do the first two actions above for any
+     additional hard registers corresponding to X.  Then, if any of these
+     registers are in the table, we must remove any REG entries that
+     overlap these registers.  */
+
+  delete_reg_equiv (regno);
+  REG_TICK (regno)++;
+  SUBREG_TICKED (regno) = -1;
+
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    {
+      gcc_assert (!clobber_high);
+      remove_pseudo_from_table (x, hash);
+    }
+  else
+    {
+      HOST_WIDE_INT in_table = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
+      unsigned int endregno = END_REGNO (x);
+      unsigned int rn;
+      struct table_elt *p, *next;
+
+      CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
+
+      for (rn = regno + 1; rn < endregno; rn++)
+	{
+	  in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, rn);
+	  CLEAR_HARD_REG_BIT (hard_regs_in_table, rn);
+	  delete_reg_equiv (rn);
+	  REG_TICK (rn)++;
+	  SUBREG_TICKED (rn) = -1;
+	}
+
+      if (in_table)
+	for (hash = 0; hash < HASH_SIZE; hash++)
+	  for (p = table[hash]; p; p = next)
+	    {
+	      next = p->next_same_hash;
+
+	      if (!REG_P (p->exp) || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
+		continue;
+
+	      if (clobber_high)
+		{
+		  if (reg_is_clobbered_by_clobber_high (p->exp, x))
+		    remove_from_table (p, hash);
+		}
+	      else
+		{
+		  unsigned int tregno = REGNO (p->exp);
+		  unsigned int tendregno = END_REGNO (p->exp);
+		  if (tendregno > regno && tregno < endregno)
+		    remove_from_table (p, hash);
+		}
+	    }
+    }
+}
+
 /* Remove from the hash table, or mark as invalid, all expressions whose
    values could be altered by storing in X.  X is a register, a subreg, or
    a memory reference with nonvarying address (because, when a memory
@@ -1841,65 +1920,7 @@ invalidate (rtx x, machine_mode full_mode)
   switch (GET_CODE (x))
     {
     case REG:
-      {
-	/* If X is a register, dependencies on its contents are recorded
-	   through the qty number mechanism.  Just change the qty number of
-	   the register, mark it as invalid for expressions that refer to it,
-	   and remove it itself.  */
-	unsigned int regno = REGNO (x);
-	unsigned int hash = HASH (x, GET_MODE (x));
-
-	/* Remove REGNO from any quantity list it might be on and indicate
-	   that its value might have changed.  If it is a pseudo, remove its
-	   entry from the hash table.
-
-	   For a hard register, we do the first two actions above for any
-	   additional hard registers corresponding to X.  Then, if any of these
-	   registers are in the table, we must remove any REG entries that
-	   overlap these registers.  */
-
-	delete_reg_equiv (regno);
-	REG_TICK (regno)++;
-	SUBREG_TICKED (regno) = -1;
-
-	if (regno >= FIRST_PSEUDO_REGISTER)
-	  remove_pseudo_from_table (x, hash);
-	else
-	  {
-	    HOST_WIDE_INT in_table
-	      = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
-	    unsigned int endregno = END_REGNO (x);
-	    unsigned int tregno, tendregno, rn;
-	    struct table_elt *p, *next;
-
-	    CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
-
-	    for (rn = regno + 1; rn < endregno; rn++)
-	      {
-		in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, rn);
-		CLEAR_HARD_REG_BIT (hard_regs_in_table, rn);
-		delete_reg_equiv (rn);
-		REG_TICK (rn)++;
-		SUBREG_TICKED (rn) = -1;
-	      }
-
-	    if (in_table)
-	      for (hash = 0; hash < HASH_SIZE; hash++)
-		for (p = table[hash]; p; p = next)
-		  {
-		    next = p->next_same_hash;
-
-		    if (!REG_P (p->exp)
-			|| REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
-		      continue;
-
-		    tregno = REGNO (p->exp);
-		    tendregno = END_REGNO (p->exp);
-		    if (tendregno > regno && tregno < endregno)
-		      remove_from_table (p, hash);
-		  }
-	  }
-      }
+      invalidate_reg (x, false);
       return;
 
     case SUBREG:
@@ -4399,6 +4420,8 @@ canonicalize_insn (rtx_insn *insn, struct set **psets, int n_sets)
       if (MEM_P (XEXP (x, 0)))
 	canon_reg (XEXP (x, 0), insn);
     }
+  else if (GET_CODE (x) == CLOBBER_HIGH)
+    gcc_assert (REG_P (XEXP (x, 0)));
   else if (GET_CODE (x) == USE
 	   && ! (REG_P (XEXP (x, 0))
 		 && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER))
@@ -4430,6 +4453,8 @@ canonicalize_insn (rtx_insn *insn, struct set **psets, int n_sets)
 	      if (MEM_P (XEXP (y, 0)))
 		canon_reg (XEXP (y, 0), insn);
 	    }
+	  else if (GET_CODE (y) == CLOBBER_HIGH)
+	    gcc_assert (REG_P (XEXP (y, 0)));
 	  else if (GET_CODE (y) == USE
 		   && ! (REG_P (XEXP (y, 0))
 			 && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER))
@@ -6130,6 +6155,12 @@ invalidate_from_clobbers (rtx_insn *insn)
 	    invalidate (XEXP (ref, 0), GET_MODE (ref));
 	}
     }
+  if (GET_CODE (x) == CLOBBER_HIGH)
+    {
+      rtx ref = XEXP (x, 0);
+      gcc_assert (REG_P (ref));
+      invalidate_reg (ref, true);
+    }
   else if (GET_CODE (x) == PARALLEL)
     {
       int i;
@@ -6146,6 +6177,12 @@ invalidate_from_clobbers (rtx_insn *insn)
 		       || GET_CODE (ref) == ZERO_EXTRACT)
 		invalidate (XEXP (ref, 0), GET_MODE (ref));
 	    }
+	  else if (GET_CODE (y) == CLOBBER_HIGH)
+	    {
+	      rtx ref = XEXP (y, 0);
+	      gcc_assert (REG_P (ref));
+	      invalidate_reg (ref, true);
+	    }
 	}
     }
 }
@@ -6163,8 +6200,17 @@ invalidate_from_sets_and_clobbers (rtx_insn *insn)
   if (CALL_P (insn))
     {
       for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
-	if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
-	  invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
+	{
+	  rtx temx = XEXP (tem, 0);
+	  if (GET_CODE (temx) == CLOBBER)
+	    invalidate (SET_DEST (temx), VOIDmode);
+	  else if (GET_CODE (temx) == CLOBBER_HIGH)
+	    {
+	      rtx temref = XEXP (temx, 0);
+	      gcc_assert (REG_P (temref));
+	      invalidate_reg (temref, true);
+	    }
+	}
     }
 
   /* Ensure we invalidate the destination register of a CALL insn.
@@ -6191,6 +6237,12 @@ invalidate_from_sets_and_clobbers (rtx_insn *insn)
 		       || GET_CODE (clobbered) == ZERO_EXTRACT)
 		invalidate (XEXP (clobbered, 0), GET_MODE (clobbered));
 	    }
+	  else if (GET_CODE (y) == CLOBBER_HIGH)
+	    {
+	      rtx ref = XEXP (y, 0);
+	      gcc_assert (REG_P (ref));
+	      invalidate_reg (ref, true);
+	    }
 	  else if (GET_CODE (y) == SET && GET_CODE (SET_SRC (y)) == CALL)
 	    invalidate (SET_DEST (y), VOIDmode);
 	}
@@ -6850,6 +6902,10 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
 	count_reg_usage (XEXP (XEXP (x, 0), 0), counts, NULL_RTX, incr);
       return;
 
+    case CLOBBER_HIGH:
+      gcc_assert (REG_P ((XEXP (x, 0))));
+      return;
+
     case SET:
       /* Unless we are setting a REG, count everything in SET_DEST.  */
       if (!REG_P (SET_DEST (x)))
@@ -6902,7 +6958,8 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
 	  || (REG_NOTE_KIND (x) != REG_NONNEG && GET_CODE (XEXP (x,0)) == USE)
 	  /* FUNCTION_USAGE expression lists may include (CLOBBER (mem /u)),
 	     involving registers in the address.  */
-	  || GET_CODE (XEXP (x, 0)) == CLOBBER)
+	  || GET_CODE (XEXP (x, 0)) == CLOBBER
+	  || GET_CODE (XEXP (x, 0)) == CLOBBER_HIGH)
 	count_reg_usage (XEXP (x, 0), counts, NULL_RTX, incr);
 
       count_reg_usage (XEXP (x, 1), counts, NULL_RTX, incr);
@@ -6986,7 +7043,9 @@ insn_live_p (rtx_insn *insn, int *counts)
 	      if (set_live_p (elt, insn, counts))
 		return true;
 	    }
-	  else if (GET_CODE (elt) != CLOBBER && GET_CODE (elt) != USE)
+	  else if (GET_CODE (elt) != CLOBBER
+		   && GET_CODE (elt) != CLOBBER_HIGH
+		   && GET_CODE (elt) != USE)
 	    return true;
 	}
       return false;
diff --git a/gcc/cselib.c b/gcc/cselib.c
index 5a978c1f4b8..6d3a4078c68 100644
--- a/gcc/cselib.c
+++ b/gcc/cselib.c
@@ -54,7 +54,8 @@ static unsigned int cselib_hash_rtx (rtx, int, machine_mode);
 static cselib_val *new_cselib_val (unsigned int, machine_mode, rtx);
 static void add_mem_for_addr (cselib_val *, cselib_val *, rtx);
 static cselib_val *cselib_lookup_mem (rtx, int);
-static void cselib_invalidate_regno (unsigned int, machine_mode);
+static void cselib_invalidate_regno (unsigned int, machine_mode,
+				     const_rtx = NULL);
 static void cselib_invalidate_mem (rtx);
 static void cselib_record_set (rtx, cselib_val *, cselib_val *);
 static void cselib_record_sets (rtx_insn *);
@@ -1661,6 +1662,7 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd,
       /* SCRATCH must be shared because they represent distinct values.  */
       return orig;
     case CLOBBER:
+    case CLOBBER_HIGH:
       if (REG_P (XEXP (orig, 0)) && HARD_REGISTER_NUM_P (REGNO (XEXP (orig, 0))))
 	return orig;
       break;
@@ -2163,7 +2165,8 @@ cselib_lookup (rtx x, machine_mode mode,
    invalidating call clobbered registers across a call.  */
 
 static void
-cselib_invalidate_regno (unsigned int regno, machine_mode mode)
+cselib_invalidate_regno (unsigned int regno, machine_mode mode,
+			 const_rtx setter)
 {
   unsigned int endregno;
   unsigned int i;
@@ -2186,6 +2189,9 @@ cselib_invalidate_regno (unsigned int regno, machine_mode mode)
 	i = regno - max_value_regs;
 
       endregno = end_hard_regno (mode, regno);
+
+      if (setter && GET_CODE (setter) == CLOBBER_HIGH)
+	gcc_assert (endregno == regno + 1);
     }
   else
     {
@@ -2218,6 +2224,19 @@ cselib_invalidate_regno (unsigned int regno, machine_mode mode)
 	      continue;
 	    }
 
+	  /* Ignore if clobber high and the register isn't clobbered.  */
+	  if (setter && GET_CODE (setter) == CLOBBER_HIGH)
+	    {
+	      gcc_assert (endregno == regno + 1);
+	      const_rtx x = XEXP (setter, 0);
+	      if (!reg_is_clobbered_by_clobber_high (i, GET_MODE (v->val_rtx),
+						     x))
+		{
+		  l = &(*l)->next;
+		  continue;
+		}
+	    }
+
 	  /* We have an overlap.  */
 	  if (*l == REG_VALUES (i))
 	    {
@@ -2352,10 +2371,10 @@ cselib_invalidate_mem (rtx mem_rtx)
   *vp = &dummy_val;
 }
 
-/* Invalidate DEST, which is being assigned to or clobbered.  */
+/* Invalidate DEST, which is being assigned to or clobbered by SETTER.  */
 
 void
-cselib_invalidate_rtx (rtx dest)
+cselib_invalidate_rtx (rtx dest, const_rtx setter)
 {
   while (GET_CODE (dest) == SUBREG
 	 || GET_CODE (dest) == ZERO_EXTRACT
@@ -2363,7 +2382,7 @@ cselib_invalidate_rtx (rtx dest)
     dest = XEXP (dest, 0);
 
   if (REG_P (dest))
-    cselib_invalidate_regno (REGNO (dest), GET_MODE (dest));
+    cselib_invalidate_regno (REGNO (dest), GET_MODE (dest), setter);
   else if (MEM_P (dest))
     cselib_invalidate_mem (dest);
 }
@@ -2371,10 +2390,10 @@ cselib_invalidate_rtx (rtx dest)
 /* A wrapper for cselib_invalidate_rtx to be called via note_stores.  */
 
 static void
-cselib_invalidate_rtx_note_stores (rtx dest, const_rtx ignore ATTRIBUTE_UNUSED,
+cselib_invalidate_rtx_note_stores (rtx dest, const_rtx setter,
 				   void *data ATTRIBUTE_UNUSED)
 {
-  cselib_invalidate_rtx (dest);
+  cselib_invalidate_rtx (dest, setter);
 }
 
 /* Record the result of a SET instruction.  DEST is being set; the source
@@ -2775,9 +2794,12 @@ cselib_process_insn (rtx_insn *insn)
   if (CALL_P (insn))
     {
       for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1))
-	if (GET_CODE (XEXP (x, 0)) == CLOBBER)
-	  cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0));
-      /* Flush evertything on setjmp.  */
+	{
+	  gcc_assert (GET_CODE (XEXP (x, 0)) != CLOBBER_HIGH);
+	  if (GET_CODE (XEXP (x, 0)) == CLOBBER)
+	    cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0));
+	}
+      /* Flush everything on setjmp.  */
       if (cselib_preserve_constants
 	  && find_reg_note (insn, REG_SETJMP, NULL))
 	{
diff --git a/gcc/cselib.h b/gcc/cselib.h
index be6feaf84de..0005ad3113c 100644
--- a/gcc/cselib.h
+++ b/gcc/cselib.h
@@ -92,7 +92,7 @@ extern bool cselib_dummy_expand_value_rtx_cb (rtx, bitmap, int,
 					      cselib_expand_callback, void *);
 extern rtx cselib_subst_to_values (rtx, machine_mode);
 extern rtx cselib_subst_to_values_from_insn (rtx, machine_mode, rtx_insn *);
-extern void cselib_invalidate_rtx (rtx);
+extern void cselib_invalidate_rtx (rtx, const_rtx = NULL);
 
 extern void cselib_reset_table (unsigned int);
 extern unsigned int cselib_get_next_uid (void);
-- 
2.15.2 (Apple Git-101.1)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v2 3/7] Add func to check if register is clobbered by clobber_high
  2018-07-26  9:14 [PATCH v2 0/7] Support partial clobbers around TLS calls on Aarch64 SVE Alan Hayward
                   ` (4 preceding siblings ...)
  2018-07-26  9:14 ` [PATCH v2 5/7] cse support for clobber_high Alan Hayward
@ 2018-07-26  9:14 ` Alan Hayward
  2018-08-04  4:12   ` Jeff Law
  2018-07-26  9:14 ` [PATCH v2 7/7] Enable clobber high for tls descs on Aarch64 Alan Hayward
  2018-08-02 13:01 ` PING [PATCH v2 0/7] Support partial clobbers around TLS calls on Aarch64 SVE Alan Hayward
  7 siblings, 1 reply; 18+ messages in thread
From: Alan Hayward @ 2018-07-26  9:14 UTC (permalink / raw)
  To: gcc-patches; +Cc: nd, Alan Hayward

Given a CLOBBER_HIGH expression and a register, it checks if
the register will be clobbered.

A second version exists for the cases where the expressions are
not available.

The function will be used throughout the following patches.

2018-07-25  Alan Hayward  <alan.hayward@arm.com>

	* rtl.h (reg_is_clobbered_by_clobber_high): Add declarations.
	* rtlanal.c (reg_is_clobbered_by_clobber_high): Add function.
---
 gcc/rtl.h     | 10 ++++++++++
 gcc/rtlanal.c | 29 +++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/gcc/rtl.h b/gcc/rtl.h
index f42d749511d..d549b0aad0b 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3467,6 +3467,16 @@ extern bool tablejump_p (const rtx_insn *, rtx_insn **, rtx_jump_table_data **);
 extern int computed_jump_p (const rtx_insn *);
 extern bool tls_referenced_p (const_rtx);
 extern bool contains_mem_rtx_p (rtx x);
+extern bool reg_is_clobbered_by_clobber_high (unsigned int, machine_mode,
+					      const_rtx);
+
+/* Convenient wrapper for reg_is_clobbered_by_clobber_high.  */
+inline bool
+reg_is_clobbered_by_clobber_high (const_rtx x, const_rtx clobber_high_op)
+{
+  return reg_is_clobbered_by_clobber_high (REGNO (x), GET_MODE (x),
+					   clobber_high_op);
+}
 
 /* Overload for refers_to_regno_p for checking a single register.  */
 inline bool
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 9f84d7f2a8c..1cab1545744 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -6551,3 +6551,32 @@ tls_referenced_p (const_rtx x)
       return true;
   return false;
 }
+
+/* Return true if reg REGNO with mode REG_MODE would be clobbered by the
+   clobber_high operand in CLOBBER_HIGH_OP.  */
+
+bool
+reg_is_clobbered_by_clobber_high (unsigned int regno, machine_mode reg_mode,
+				  const_rtx clobber_high_op)
+{
+  unsigned int clobber_regno = REGNO (clobber_high_op);
+  machine_mode clobber_mode = GET_MODE (clobber_high_op);
+  unsigned char regno_nregs = hard_regno_nregs (regno, reg_mode);
+
+  /* Clobber high should always span exactly one register.  */
+  gcc_assert (REG_NREGS (clobber_high_op) == 1);
+
+  /* Clobber high needs to match with one of the registers in X.  */
+  if (clobber_regno < regno || clobber_regno >= regno + regno_nregs)
+    return false;
+
+  gcc_assert (reg_mode != BLKmode && clobber_mode != BLKmode);
+
+  if (reg_mode == VOIDmode)
+    return clobber_mode != VOIDmode;
+
+  /* Clobber high will clobber if its size might be greater than the size of
+     register regno.  */
+  return maybe_gt (exact_div (GET_MODE_SIZE (reg_mode), regno_nregs),
+		 GET_MODE_SIZE (clobber_mode));
+}
-- 
2.15.2 (Apple Git-101.1)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* PING [PATCH v2 0/7] Support partial clobbers around TLS calls on Aarch64 SVE
  2018-07-26  9:14 [PATCH v2 0/7] Support partial clobbers around TLS calls on Aarch64 SVE Alan Hayward
                   ` (6 preceding siblings ...)
  2018-07-26  9:14 ` [PATCH v2 7/7] Enable clobber high for tls descs on Aarch64 Alan Hayward
@ 2018-08-02 13:01 ` Alan Hayward
  7 siblings, 0 replies; 18+ messages in thread
From: Alan Hayward @ 2018-08-02 13:01 UTC (permalink / raw)
  To: GCC Patches; +Cc: nd



> On 26 Jul 2018, at 10:13, Alan Hayward <Alan.Hayward@arm.com> wrote:
> 
> This is rebasing of the patch posted in November.
> It's aim is to support aarch64 SVE register preservation around TLS calls
> by adding a CLOBBER_HIGH expression.
> 
> Across a TLS call, Aarch64 SVE does not explicitly preserve the
> SVE vector registers. However, the Neon vector registers are preserved.
> Due to overlapping of registers, this means the lower 128bits of all
> SVE vector registers will be preserved.
> 
> The existing GCC code assume all Neon and SVE registers are clobbered
> across TLS calls.
> 
> This patch introduces a CLOBBER_HIGH expression. This behaves a bit like
> a CLOBBER expression. CLOBBER_HIGH can only refer to a single register.
> The mode of the expression indicates the size of the lower bits which
> will be preserved. If the register contains a value bigger than this
> mode then the code will treat the register as clobbered, otherwise the
> register remains untouched.
> 
> The means in order to evaluate if a clobber high is relevant, we need to
> ensure the mode of the existing value in a register is tracked.
> 
> The first two patches introduce CLOBBER_HIGH and generation support.
> The next patch adds a helper function for easily determining if a register
> gets clobbered by a CLOBBER_HIGH.
> The next three patches add clobber high checks to all of the passes. I
> couldn't think of a better way of splitting this up (maybe needs dividing
> into smaller patches?).
> Finally the last patch adds the CLOBBER_HIGHS around a TLS call for
> aarch64 SVE and some test cases.
> 
> Alan Hayward (7):
>  Add CLOBBER_HIGH expression
>  Generation support for CLOBBER_HIGH
>  Add func to check if register is clobbered by clobber_high
>  lra support for clobber_high
>  cse support for clobber_high
>  Remaining support for clobber high
>  Enable clobber high for tls descs on Aarch64
> 
> gcc/alias.c                                        |  11 ++
> gcc/cfgexpand.c                                    |   1 +
> gcc/combine-stack-adj.c                            |   1 +
> gcc/combine.c                                      |  38 ++++-
> gcc/config/aarch64/aarch64.md                      |  69 ++++++--
> gcc/cse.c                                          | 187 ++++++++++++++-------
> gcc/cselib.c                                       |  42 +++--
> gcc/cselib.h                                       |   2 +-
> gcc/dce.c                                          |  11 +-
> gcc/df-scan.c                                      |   6 +
> gcc/doc/rtl.texi                                   |  15 +-
> gcc/dwarf2out.c                                    |   1 +
> gcc/emit-rtl.c                                     |  16 ++
> gcc/genconfig.c                                    |   1 +
> gcc/genemit.c                                      |  51 +++---
> gcc/genrecog.c                                     |   3 +-
> gcc/haifa-sched.c                                  |   3 +
> gcc/ira-build.c                                    |   5 +
> gcc/ira-costs.c                                    |   7 +
> gcc/ira.c                                          |   6 +-
> gcc/jump.c                                         |   1 +
> gcc/lra-eliminations.c                             |  11 ++
> gcc/lra-int.h                                      |   2 +
> gcc/lra-lives.c                                    |  31 ++--
> gcc/lra.c                                          |  66 +++++---
> gcc/postreload-gcse.c                              |  21 ++-
> gcc/postreload.c                                   |  25 ++-
> gcc/print-rtl.c                                    |   1 +
> gcc/recog.c                                        |   9 +-
> gcc/regcprop.c                                     |  10 +-
> gcc/reginfo.c                                      |   4 +
> gcc/reload1.c                                      |  16 +-
> gcc/reorg.c                                        |  27 ++-
> gcc/resource.c                                     |  24 ++-
> gcc/rtl.c                                          |  15 ++
> gcc/rtl.def                                        |  10 ++
> gcc/rtl.h                                          |  27 ++-
> gcc/rtlanal.c                                      |  47 +++++-
> gcc/sched-deps.c                                   |  15 +-
> .../gcc.target/aarch64/sve_tls_preserve_1.c        |  19 +++
> .../gcc.target/aarch64/sve_tls_preserve_2.c        |  24 +++
> .../gcc.target/aarch64/sve_tls_preserve_3.c        |  24 +++
> 42 files changed, 725 insertions(+), 180 deletions(-)
> create mode 100644 gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_1.c
> create mode 100644 gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_2.c
> create mode 100644 gcc/testsuite/gcc.target/aarch64/sve_tls_preserve_3.c
> 
> -- 
> 2.15.2 (Apple Git-101.1)
> 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 1/7] Add CLOBBER_HIGH expression
  2018-07-26  9:14 ` [PATCH v2 1/7] Add CLOBBER_HIGH expression Alan Hayward
@ 2018-08-04  4:04   ` Jeff Law
  0 siblings, 0 replies; 18+ messages in thread
From: Jeff Law @ 2018-08-04  4:04 UTC (permalink / raw)
  To: Alan Hayward, gcc-patches; +Cc: nd

On 07/26/2018 03:13 AM, Alan Hayward wrote:
> Includes documentation.
> 
> 2018-07-25  Alan Hayward  <alan.hayward@arm.com>
> 
> 	* doc/rtl.texi (clobber_high): Add.
> 	(parallel): Add in clobber high
> 	* rtl.c (rtl_check_failed_code3): Add function.
> 	* rtl.def (CLOBBER_HIGH): Add expression.
> 	* rtl.h (RTL_CHECKC3): Add macro.
> 	(rtl_check_failed_code3): Add declaration.
> 	(XC3EXP): Add macro.
OK.
jeff

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 2/7] Generation support for CLOBBER_HIGH
  2018-07-26  9:14 ` [PATCH v2 2/7] Generation support for CLOBBER_HIGH Alan Hayward
@ 2018-08-04  4:09   ` Jeff Law
  0 siblings, 0 replies; 18+ messages in thread
From: Jeff Law @ 2018-08-04  4:09 UTC (permalink / raw)
  To: Alan Hayward, gcc-patches; +Cc: nd

On 07/26/2018 03:13 AM, Alan Hayward wrote:
> Ensure clobber high is a register expression.
> Info is passed through for the error case.
> 
> 2018-07-25  Alan Hayward  <alan.hayward@arm.com>
> 
> 	* emit-rtl.c (verify_rtx_sharing): Check for CLOBBER_HIGH.
> 	(copy_insn_1): Likewise.
> 	(gen_hard_reg_clobber_high): New gen function.
> 	* genconfig.c (walk_insn_part): Check for CLOBBER_HIGH.
> 	* genemit.c (gen_exp): Likewise.
> 	(gen_emit_seq): Pass through info.
> 	(gen_insn): Check for CLOBBER_HIGH.
> 	(gen_expand): Pass through info.
> 	(gen_split): Likewise.
> 	(output_add_clobbers): Likewise.
> 	* genrecog.c (validate_pattern): Check for CLOBBER_HIGH.
> 	(remove_clobbers): Likewise.
> 	* rtl.h (gen_hard_reg_clobber_high): New declaration.
> ---
>  gcc/emit-rtl.c  | 16 ++++++++++++++++
>  gcc/genconfig.c |  1 +
>  gcc/genemit.c   | 51 +++++++++++++++++++++++++++++++--------------------
>  gcc/genrecog.c  |  3 ++-
>  gcc/rtl.h       |  1 +
>  5 files changed, 51 insertions(+), 21 deletions(-)
> 
> diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
> index e4b070486e8..6a32bcbdaf6 100644
> --- a/gcc/emit-rtl.c
> +++ b/gcc/emit-rtl.c
> @@ -6508,6 +6511,19 @@ gen_hard_reg_clobber (machine_mode mode, unsigned int regno)
>  	    gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (mode, regno)));
>  }
>  
> +static GTY((deletable)) rtx
> +hard_reg_clobbers_high[NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER];
> +
> +rtx
> +gen_hard_reg_clobber_high (machine_mode mode, unsigned int regno)
> +{
> +  if (hard_reg_clobbers_high[mode][regno])
> +    return hard_reg_clobbers_high[mode][regno];
> +  else
> +    return (hard_reg_clobbers_high[mode][regno]
> +	    = gen_rtx_CLOBBER_HIGH (VOIDmode, gen_rtx_REG (mode, regno)));
> +}
You need a function comment on gen_hard_reg_clobber_high.

OK with that change.

jeff

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 3/7] Add func to check if register is clobbered by clobber_high
  2018-07-26  9:14 ` [PATCH v2 3/7] Add func to check if register is clobbered by clobber_high Alan Hayward
@ 2018-08-04  4:12   ` Jeff Law
  0 siblings, 0 replies; 18+ messages in thread
From: Jeff Law @ 2018-08-04  4:12 UTC (permalink / raw)
  To: Alan Hayward, gcc-patches; +Cc: nd

On 07/26/2018 03:13 AM, Alan Hayward wrote:
> Given a CLOBBER_HIGH expression and a register, it checks if
> the register will be clobbered.
> 
> A second version exists for the cases where the expressions are
> not available.
> 
> The function will be used throughout the following patches.
> 
> 2018-07-25  Alan Hayward  <alan.hayward@arm.com>
> 
> 	* rtl.h (reg_is_clobbered_by_clobber_high): Add declarations.
> 	* rtlanal.c (reg_is_clobbered_by_clobber_high): Add function.
OK
jeff

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 4/7] lra support for clobber_high
  2018-07-26  9:14 ` [PATCH v2 4/7] lra support for clobber_high Alan Hayward
@ 2018-08-04  4:21   ` Jeff Law
  0 siblings, 0 replies; 18+ messages in thread
From: Jeff Law @ 2018-08-04  4:21 UTC (permalink / raw)
  To: Alan Hayward, gcc-patches; +Cc: nd

On 07/26/2018 03:13 AM, Alan Hayward wrote:
> The lra specific changes for clobber_high.
> 
> 2018-07-25  Alan Hayward  <alan.hayward@arm.com>
> 
> 	* lra-eliminations.c (lra_eliminate_regs_1): Check for clobber high.
> 	(mark_not_eliminable): Likewise.
> 	* lra-int.h (struct lra_insn_reg): Add clobber high marker.
> 	* lra-lives.c (process_bb_lives): Check for clobber high.
> 	* lra.c (new_insn_reg): Remember clobber highs.
> 	(collect_non_operand_hard_regs): Check for clobber high.
> 	(lra_set_insn_recog_data): Likewise.
> 	(add_regs_to_insn_regno_info): Likewise.
> 	(lra_update_insn_regno_info): Likewise.
OK.
jeff

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 5/7] cse support for clobber_high
  2018-07-26  9:14 ` [PATCH v2 5/7] cse support for clobber_high Alan Hayward
@ 2018-08-04  4:26   ` Jeff Law
  0 siblings, 0 replies; 18+ messages in thread
From: Jeff Law @ 2018-08-04  4:26 UTC (permalink / raw)
  To: Alan Hayward, gcc-patches; +Cc: nd

On 07/26/2018 03:13 AM, Alan Hayward wrote:
> The cse specific changes for clobber_high.
> 
> 2018-07-25  Alan Hayward  <alan.hayward@arm.com>
> 
> 	* cse.c (invalidate_reg): New function extracted from...
> 	(invalidate): ...here.
> 	(canonicalize_insn): Check for clobber high.
> 	(invalidate_from_clobbers): invalidate clobber highs.
> 	(invalidate_from_sets_and_clobbers): Likewise.
> 	(count_reg_usage): Check for clobber high.
> 	(insn_live_p): Likewise.
> 	* cselib.c (cselib_expand_value_rtx_1):Likewise.
> 	(cselib_invalidate_regno): Check for clobber in setter.
> 	(cselib_invalidate_rtx): Pass through setter.
> 	(cselib_invalidate_rtx_note_stores):
> 	(cselib_process_insn): Check for clobber high.
> 	* cselib.h (cselib_invalidate_rtx): Add operand.
OK.
jeff

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 7/7] Enable clobber high for tls descs on Aarch64
  2018-07-26  9:14 ` [PATCH v2 7/7] Enable clobber high for tls descs on Aarch64 Alan Hayward
@ 2018-08-04  4:27   ` Jeff Law
  2018-08-06 13:15   ` Richard Sandiford
  1 sibling, 0 replies; 18+ messages in thread
From: Jeff Law @ 2018-08-04  4:27 UTC (permalink / raw)
  To: Alan Hayward, gcc-patches; +Cc: nd

On 07/26/2018 03:13 AM, Alan Hayward wrote:
> Add the clobber high expressions to tls_desc for aarch64.
> It also adds three tests.
> 
> In addition I also tested by taking the gcc torture test suite and making
> all global variables __thread. Then emended the suite to compile with -fpic,
> save the .s file and only for one given O level.
> I ran this before and after the patch and compared the resulting .s files,
> ensuring that there were no ASM changes.
> I discarded the 10% of tests that failed to compile (due to the code in
> the test now being invalid C).
> I did this for O0,O2,O3 on both x86 and aarch64 and observed no difference
> between ASM files before and after the patch.
> 
> Alan.
> 
> 2018-07-25  Alan Hayward  <alan.hayward@arm.com>
> 
> gcc/
> 	* config/aarch64/aarch64.md: Add clobber highs to tls_desc.
> 
> gcc/testsuite/
> 	* gcc.target/aarch64/sve_tls_preserve_1.c: New test.
> 	* gcc.target/aarch64/sve_tls_preserve_2.c: New test.
> 	* gcc.target/aarch64/sve_tls_preserve_3.c: New test.
AArch64 specific, so leaving it to the AArch64 maintainers to handle review.

jeff

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 6/7] Remaining support for clobber high
  2018-07-26  9:14 ` [PATCH v2 6/7] Remaining support for clobber high Alan Hayward
@ 2018-08-04  4:30   ` Jeff Law
  2018-12-13 10:11   ` Jakub Jelinek
  1 sibling, 0 replies; 18+ messages in thread
From: Jeff Law @ 2018-08-04  4:30 UTC (permalink / raw)
  To: Alan Hayward, gcc-patches; +Cc: nd

On 07/26/2018 03:13 AM, Alan Hayward wrote:
> Add the remainder of clobber high checks.
> Happy to split this into smaller patches if required (there didn't
> seem anything obvious to split into).
> 
> 2018-07-25  Alan Hayward  <alan.hayward@arm.com>
> 
> 	* alias.c (record_set): Check for clobber high.
> 	* cfgexpand.c (expand_gimple_stmt): Likewise.
> 	* combine-stack-adj.c (single_set_for_csa): Likewise.
> 	* combine.c (find_single_use_1): Likewise.
> 	(set_nonzero_bits_and_sign_copies): Likewise.
> 	(get_combine_src_dest): Likewise.
> 	(is_parallel_of_n_reg_sets): Likewise.
> 	(try_combine): Likewise.
> 	(record_dead_and_set_regs_1): Likewise.
> 	(reg_dead_at_p_1): Likewise.
> 	(reg_dead_at_p): Likewise.
> 	* dce.c (deletable_insn_p): Likewise.
> 	(mark_nonreg_stores_1): Likewise.
> 	(mark_nonreg_stores_2): Likewise.
> 	* df-scan.c (df_find_hard_reg_defs): Likewise.
> 	(df_uses_record): Likewise.
> 	(df_get_call_refs): Likewise.
> 	* dwarf2out.c (mem_loc_descriptor): Likewise.
> 	* haifa-sched.c (haifa_classify_rtx): Likewise.
> 	* ira-build.c (create_insn_allocnos): Likewise.
> 	* ira-costs.c (scan_one_insn): Likewise.
> 	* ira.c (equiv_init_movable_p): Likewise.
> 	(rtx_moveable_p): Likewise.
> 	(interesting_dest_for_shprep): Likewise.
> 	* jump.c (mark_jump_label_1): Likewise.
> 	* postreload-gcse.c (record_opr_changes): Likewise.
> 	* postreload.c (reload_cse_simplify): Likewise.
> 	(struct reg_use): Add source expr.
> 	(reload_combine): Check for clobber high.
> 	(reload_combine_note_use): Likewise.
> 	(reload_cse_move2add): Likewise.
> 	(move2add_note_store): Likewise.
> 	* print-rtl.c (print_pattern): Likewise.
> 	* recog.c (decode_asm_operands): Likewise.
> 	(store_data_bypass_p): Likewise.
> 	(if_test_bypass_p): Likewise.
> 	* regcprop.c (kill_clobbered_value): Likewise.
> 	(kill_set_value): Likewise.
> 	* reginfo.c (reg_scan_mark_refs): Likewise.
> 	* reload1.c (maybe_fix_stack_asms): Likewise.
> 	(eliminate_regs_1): Likewise.
> 	(elimination_effects): Likewise.
> 	(mark_not_eliminable): Likewise.
> 	(scan_paradoxical_subregs): Likewise.
> 	(forget_old_reloads_1): Likewise.
> 	* reorg.c (find_end_label): Likewise.
> 	(try_merge_delay_insns): Likewise.
> 	(redundant_insn): Likewise.
> 	(own_thread_p): Likewise.
> 	(fill_simple_delay_slots): Likewise.
> 	(fill_slots_from_thread): Likewise.
> 	(dbr_schedule): Likewise.
> 	* resource.c (update_live_status): Likewise.
> 	(mark_referenced_resources): Likewise.
> 	(mark_set_resources): Likewise.
> 	* rtl.c (copy_rtx): Likewise.
> 	* rtlanal.c (reg_referenced_p): Likewise.
> 	(single_set_2): Likewise.
> 	(noop_move_p): Likewise.
> 	(note_stores): Likewise.
> 	* sched-deps.c (sched_analyze_reg): Likewise.
> 	(sched_analyze_insn): Likewise.
I only spot-checked on this.  It's looks like it's relatively
mechanical.  I'm going to assume you fixed all the places that needed
fixing.


OK


Jeff

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 7/7] Enable clobber high for tls descs on Aarch64
  2018-07-26  9:14 ` [PATCH v2 7/7] Enable clobber high for tls descs on Aarch64 Alan Hayward
  2018-08-04  4:27   ` Jeff Law
@ 2018-08-06 13:15   ` Richard Sandiford
  1 sibling, 0 replies; 18+ messages in thread
From: Richard Sandiford @ 2018-08-06 13:15 UTC (permalink / raw)
  To: Alan Hayward; +Cc: gcc-patches, nd

Alan Hayward <alan.hayward@arm.com> writes:
> Add the clobber high expressions to tls_desc for aarch64.
> It also adds three tests.
>
> In addition I also tested by taking the gcc torture test suite and making
> all global variables __thread. Then emended the suite to compile with -fpic,
> save the .s file and only for one given O level.
> I ran this before and after the patch and compared the resulting .s files,
> ensuring that there were no ASM changes.
> I discarded the 10% of tests that failed to compile (due to the code in
> the test now being invalid C).
> I did this for O0,O2,O3 on both x86 and aarch64 and observed no difference
> between ASM files before and after the patch.
>
> Alan.
>
> 2018-07-25  Alan Hayward  <alan.hayward@arm.com>
>
> gcc/
> 	* config/aarch64/aarch64.md: Add clobber highs to tls_desc.
>
> gcc/testsuite/
> 	* gcc.target/aarch64/sve_tls_preserve_1.c: New test.
> 	* gcc.target/aarch64/sve_tls_preserve_2.c: New test.
> 	* gcc.target/aarch64/sve_tls_preserve_3.c: New test.

Like you were saying off-line, these should be in the aarch64/sve/
directory.  Files there don't specify an -march* option, since the
harness adds one if necessary.

OK with that change, thanks.

Richard

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 6/7] Remaining support for clobber high
  2018-07-26  9:14 ` [PATCH v2 6/7] Remaining support for clobber high Alan Hayward
  2018-08-04  4:30   ` Jeff Law
@ 2018-12-13 10:11   ` Jakub Jelinek
  1 sibling, 0 replies; 18+ messages in thread
From: Jakub Jelinek @ 2018-12-13 10:11 UTC (permalink / raw)
  To: Alan Hayward; +Cc: gcc-patches, nd

On Thu, Jul 26, 2018 at 10:13:28AM +0100, Alan Hayward wrote:
> --- a/gcc/rtl.c
> +++ b/gcc/rtl.c
> @@ -304,6 +304,10 @@ copy_rtx (rtx orig)
>  	return orig;
>        break;
>  
> +    case CLOBBER_HIGH:
> +	gcc_assert (REG_P (XEXP (orig, 0)));
> +	return orig;

Wrong formatting (indented too much).

More importantly, do you want it to be shareable always (e.g. CLOBBER
is sharedable only if
      if (REG_P (XEXP (orig, 0)) && REGNO (XEXP (orig, 0)) < FIRST_PSEUDO_REGISTER
          && ORIGINAL_REGNO (XEXP (orig, 0)) == REGNO (XEXP (orig, 0)))
You require CLOBBER_HIGH argument to be REG_P, so that parts goes away,
but what about the rest?

And, any reason something similar has not been added to cleanup_auto_inc_dec?
Have you grepped for all other case CLOBBER: spots?

	Jakub

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2018-12-13 10:11 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-26  9:14 [PATCH v2 0/7] Support partial clobbers around TLS calls on Aarch64 SVE Alan Hayward
2018-07-26  9:14 ` [PATCH v2 4/7] lra support for clobber_high Alan Hayward
2018-08-04  4:21   ` Jeff Law
2018-07-26  9:14 ` [PATCH v2 2/7] Generation support for CLOBBER_HIGH Alan Hayward
2018-08-04  4:09   ` Jeff Law
2018-07-26  9:14 ` [PATCH v2 6/7] Remaining support for clobber high Alan Hayward
2018-08-04  4:30   ` Jeff Law
2018-12-13 10:11   ` Jakub Jelinek
2018-07-26  9:14 ` [PATCH v2 1/7] Add CLOBBER_HIGH expression Alan Hayward
2018-08-04  4:04   ` Jeff Law
2018-07-26  9:14 ` [PATCH v2 5/7] cse support for clobber_high Alan Hayward
2018-08-04  4:26   ` Jeff Law
2018-07-26  9:14 ` [PATCH v2 3/7] Add func to check if register is clobbered by clobber_high Alan Hayward
2018-08-04  4:12   ` Jeff Law
2018-07-26  9:14 ` [PATCH v2 7/7] Enable clobber high for tls descs on Aarch64 Alan Hayward
2018-08-04  4:27   ` Jeff Law
2018-08-06 13:15   ` Richard Sandiford
2018-08-02 13:01 ` PING [PATCH v2 0/7] Support partial clobbers around TLS calls on Aarch64 SVE Alan Hayward

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).