[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