[gcc(refs/vendors/ARM/heads/morello)] morello: Add immediate form of clrperm

Alex Coplan acoplan@gcc.gnu.org
Tue Nov 1 11:01:30 GMT 2022


https://gcc.gnu.org/g:70cb98d7a702272cae4174f21046ab785226d74c

commit 70cb98d7a702272cae4174f21046ab785226d74c
Author: Alex Coplan <alex.coplan@arm.com>
Date:   Fri Oct 14 19:17:30 2022 +0100

    morello: Add immediate form of clrperm
    
    This extends the pattern for clrperm in the AArch64 backend to generate
    the immediate variant where possible. We adjust the expander for
    __builtin_cheri_perms_and to use the immediate variant of the
    instruction where possible.

Diff:
---
 gcc/config/aarch64/aarch64-morello.md              |  26 +++--
 gcc/config/aarch64/aarch64-protos.h                |   1 +
 gcc/config/aarch64/aarch64.c                       |  33 ++++++
 gcc/config/aarch64/constraints.md                  |   3 +
 gcc/config/aarch64/predicates.md                   |  12 ++
 .../morello/builtin_cheri_perms_and_immed.c        | 127 +++++++++++++++++++++
 6 files changed, 195 insertions(+), 7 deletions(-)

diff --git a/gcc/config/aarch64/aarch64-morello.md b/gcc/config/aarch64/aarch64-morello.md
index 50de65fedc5..cb57197e751 100644
--- a/gcc/config/aarch64/aarch64-morello.md
+++ b/gcc/config/aarch64/aarch64-morello.md
@@ -260,13 +260,15 @@
 )
 
 (define_insn "aarch64_cap_clear_perm"
-  [(set (match_operand:CADI 0 "register_operand" "=rk")
-        (unspec:CADI [(match_operand:CADI 1 "register_operand" "rk")
-          (match_operand:DI 2 "register_operand" "r")]
-            UNSPEC_CHERI_CLEAR_PERM))
+  [(set (match_operand:CADI 0 "register_operand" "=rk,rk")
+	(unspec:CADI [(match_operand:CADI 1 "register_operand" "rk,rk")
+	  (match_operand:DI 2 "aarch64_clrperm_operand" "r,Ucp")]
+	    UNSPEC_CHERI_CLEAR_PERM))
   ]
   "TARGET_MORELLO"
-  "clrperm\\t%0, %1, %2"
+  "@
+  clrperm\\t%0, %1, %2
+  * return aarch64_output_clrperm_immed (operands);"
 )
 
 (define_insn "cap_global_data_get"
@@ -280,10 +282,20 @@
 (define_expand "cap_perms_and_cadi"
   [(match_operand:CADI 0 "register_operand")
    (match_operand:CADI 1 "register_operand")
-   (match_operand:DI 2 "register_operand")]
+   (match_operand:DI 2 "aarch64_reg_or_imm")]
   "TARGET_MORELLO"
   {
-    emit_insn (gen_one_cmpldi2 (operands[2], operands[2]));
+    if (CONST_INT_P (operands[2]))
+      {
+	rtx cand = gen_int_mode (~UINTVAL (operands[2]), DImode);
+	if (aarch64_clrperm_immediate (cand, DImode))
+	  operands[2] = cand;
+	else
+	  operands[2] = force_reg (DImode, cand);
+      }
+    else
+      emit_insn (gen_one_cmpldi2 (operands[2], operands[2]));
+
     emit_insn (gen_aarch64_cap_clear_perm (operands[0], operands[1], operands[2]));
     DONE;
   }
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 142ba4dfb7a..b365bf92421 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -564,6 +564,7 @@ bool aarch64_uimm12_shift (HOST_WIDE_INT);
 int aarch64_movk_shift (const wide_int_ref &, const wide_int_ref &);
 bool aarch64_use_return_insn_p (void);
 const char *aarch64_output_casesi (rtx *);
+const char *aarch64_output_clrperm_immed (rtx *);
 bool aarch64_scbnds_immediate (unsigned HOST_WIDE_INT);
 
 unsigned int aarch64_tlsdesc_abi_id ();
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 456a2b10710..5179f310552 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -12114,6 +12114,39 @@ aarch64_output_casesi (rtx *operands)
   return "";
 }
 
+const char *
+aarch64_output_clrperm_immed (rtx *operands)
+{
+  gcc_assert (REG_P (operands[0]) && GET_MODE (operands[0]) == CADImode);
+  gcc_assert (REG_P (operands[1]) && GET_MODE (operands[1]) == CADImode);
+  gcc_assert (CONST_INT_P (operands[2]));
+
+  char immed[4];
+  const unsigned rwx_bits = (UINTVAL (operands[2]) >> 15) & 7;
+  if (rwx_bits == 0)
+    snprintf (immed, sizeof (immed), "#0");
+  else
+    {
+      char *p = immed;
+      enum {
+	X = (1 << 0),
+	W = (1 << 1),
+	R = (1 << 2)
+      };
+      if (rwx_bits & R)
+	*p++ = 'r';
+      if (rwx_bits & W)
+	*p++ = 'w';
+      if (rwx_bits & X)
+	*p++ = 'x';
+      *p = '\0';
+    }
+
+  asm_fprintf (asm_out_file, "\tclrperm\tc%u, c%u, %s\n",
+	       REGNO (operands[0]), REGNO (operands[1]), immed);
+  return "";
+}
+
 
 /* Return size in bits of an arithmetic operand which is shifted/scaled and
    masked such that it is suitable for a UXTB, UXTH, or UXTW extend
diff --git a/gcc/config/aarch64/constraints.md b/gcc/config/aarch64/constraints.md
index 386ce5b64d6..568f91e0f67 100644
--- a/gcc/config/aarch64/constraints.md
+++ b/gcc/config/aarch64/constraints.md
@@ -90,6 +90,9 @@
   (and (match_code "const_int")
        (match_test "aarch64_scbnds_immediate (ival)")))
 
+(define_constraint "Ucp"
+  "A constraint matching an immediate suitable for clrperm."
+  (match_operand 0 "aarch64_clrperm_immediate"))
 
 (define_constraint "J"
  "A constant that can be used with a SUB operation (once negated)."
diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index 03bcc73ce9e..b4b0349843d 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -64,6 +64,18 @@
   (ior (match_operand 0 "register_operand")
        (match_code "const_int")))
 
+; We can use the immediate form of clrperm if we're only clearing rwx
+; bits (bits 16 through 18 inclusive), i.e. if all the low bits below
+; these are cleared in the mask.
+(define_predicate "aarch64_clrperm_immediate"
+  (and
+    (match_code "const_int")
+    (match_test "(UINTVAL (op) & 0x7fff) == 0")))
+
+(define_predicate "aarch64_clrperm_operand"
+  (ior (match_operand 0 "register_operand")
+       (match_operand 0 "aarch64_clrperm_immediate")))
+
 (define_predicate "aarch64_simd_register"
   (and (match_code "reg")
        (match_test "FP_REGNUM_P (REGNO (op))")))
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtin_cheri_perms_and_immed.c b/gcc/testsuite/gcc.target/aarch64/morello/builtin_cheri_perms_and_immed.c
new file mode 100644
index 00000000000..90abaafedf0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtin_cheri_perms_and_immed.c
@@ -0,0 +1,127 @@
+/* { dg-do assemble } */
+/* { dg-additional-options "-save-temps" } */
+/* { dg-final { check-function-bodies "**" ""  { {-O[123s]} } } } */
+/* { dg-require-effective-target cheri_capability_pure } */
+
+enum {
+  R = __CHERI_CAP_PERMISSION_PERMIT_LOAD__,
+  W = __CHERI_CAP_PERMISSION_PERMIT_STORE__,
+  X = __CHERI_CAP_PERMISSION_PERMIT_EXECUTE__,
+
+  /* Here we make assumptions about the encoding of permisisons on
+     Morello in order to test the codegen.  */
+  EXTRA_HIGH_BIT = (R << 1),
+  LOWER_BIT = __CHERI_CAP_PERMISSION_PERMIT_LOAD_CAPABILITY__,
+};
+
+/*
+** clear_x:
+** 	clrperm	c0, c0, x
+** 	ret
+*/
+void *clear_x(void *x)
+{
+  return __builtin_cheri_perms_and (x, ~X);
+}
+
+/*
+** clear_w:
+** 	clrperm	c0, c0, w
+** 	ret
+*/
+void *clear_w(void *x)
+{
+  return __builtin_cheri_perms_and (x, ~W);
+}
+
+/*
+** clear_r:
+** 	clrperm	c0, c0, r
+** 	ret
+*/
+void *clear_r(void *x)
+{
+  return __builtin_cheri_perms_and (x, ~R);
+}
+
+/*
+** clear_wx:
+** 	clrperm	c0, c0, wx
+** 	ret
+*/
+void *clear_wx(void *x)
+{
+  return __builtin_cheri_perms_and (x, ~(W | X));
+}
+
+/*
+** clear_rx:
+** 	clrperm	c0, c0, rx
+** 	ret
+*/
+void *clear_rx(void *x)
+{
+  return __builtin_cheri_perms_and (x, ~(R | X));
+}
+
+/*
+** clear_rw:
+** 	clrperm	c0, c0, rw
+** 	ret
+*/
+void *clear_rw(void *x)
+{
+  return __builtin_cheri_perms_and (x, ~(R | W));
+}
+
+/*
+** all_three:
+** 	clrperm	c0, c0, rwx
+** 	ret
+*/
+void *all_three(void *x)
+{
+  return __builtin_cheri_perms_and (x, ~(R | W | X));
+}
+
+/*
+** clear_none:
+** 	clrperm	c0, c0, #0
+** 	ret
+*/
+void *clear_none(void *x)
+{
+  return __builtin_cheri_perms_and(x, ~0UL);
+}
+
+/*
+** extra_high_bits_dont_matter:
+** 	clrperm	c0, c0, rwx
+** 	ret
+*/
+void *extra_high_bits_dont_matter(void *x)
+{
+  return __builtin_cheri_perms_and (x, ~(R | W | X | EXTRA_HIGH_BIT));
+}
+
+/*
+** scuppered:
+** 	mov	x1, 49152
+** 	clrperm	c0, c0, x1
+** 	ret
+*/
+void *scuppered(void *x)
+{
+  return __builtin_cheri_perms_and (x, ~(X | LOWER_BIT));
+}
+
+/*
+** clear_just_low_bits:
+** 	mov	x1, 7
+** 	clrperm	c0, c0, x1
+** 	ret
+*/
+void *clear_just_low_bits (void *x)
+{
+  return __builtin_cheri_perms_and (x, ~7UL);
+}


More information about the Gcc-cvs mailing list