[gcc r9-8939] Implement __rndr, __rndrrs intrinsics

Kyrylo Tkachov ktkachov@gcc.gnu.org
Fri Sep 25 10:25:35 GMT 2020


https://gcc.gnu.org/g:4fb606b503780b91ad79c203003dc41a32cfbab7

commit r9-8939-g4fb606b503780b91ad79c203003dc41a32cfbab7
Author: Kyrylo Tkachov <kyrylo.tkachov@arm.com>
Date:   Mon Oct 21 10:52:05 2019 +0000

    Implement __rndr, __rndrrs intrinsics
    
    This patch implements the recently published[1] __rndr and __rndrrs
    intrinsics used to access the RNG in Armv8.5-A.
    The __rndrrs intrinsics can be used to reseed the generator too.
    They are guarded by the __ARM_FEATURE_RNG feature macro.
    A quirk with these intrinsics is that they store the random number in
    their pointer argument and return a status
    code if the generation succeeded.
    
    The instructions themselves write the CC flags indicating the success of
    the operation that we can then read with a CSET.
    Therefore this implementation makes use of the IGNORE indicator to the
    builtin expand machinery to avoid generating
    the CSET if its result is unused (the CC reg clobbering effect is still
    reflected in the pattern).
    I've checked that using unspec_volatile prevents undesirable CSEing of
    the instructions.
    
    [1] https://developer.arm.com/docs/101028/latest/data-processing-intrinsics
    
    gcc/
            PR target/71233
            * config/aarch64/aarch64.md (UNSPEC_RNDR, UNSPEC_RNDRRS):
            Define.
            (aarch64_rndr): New define_insn.
            (aarch64_rndrrs): Likewise.
            * config/aarch64/aarch64.h (AARCH64_ISA_RNG): Define.
            (TARGET_RNG): Likewise.
            * config/aarch64/aarch64-builtins.c (enum aarch64_builtins):
            Add AARCH64_BUILTIN_RNG_RNDR, AARCH64_BUILTIN_RNG_RNDRRS.
            (aarch64_init_rng_builtins): Define.
            (aarch64_init_builtins): Call aarch64_init_rng_builtins.
            (aarch64_expand_rng_builtin): Define.
            (aarch64_expand_builtin): Use IGNORE argument, handle
            RNG builtins.
            * config/aarch64/aarch64-c.c (aarch64_update_cpp_builtins):
            Define __ARM_FEATURE_RNG when TARGET_RNG.
            * config/aarch64/arm_acle.h (__rndr, __rndrrs): Define.
    
    gcc/testsuite/
            PR target/71233
            * gcc.target/aarch64/acle/rng_1.c: New test.

Diff:
---
 gcc/config/aarch64/aarch64-builtins.c         | 62 +++++++++++++++++++++++++++
 gcc/config/aarch64/aarch64-c.c                |  2 +
 gcc/config/aarch64/aarch64.h                  |  4 ++
 gcc/config/aarch64/aarch64.md                 | 22 ++++++++++
 gcc/config/aarch64/arm_acle.h                 | 18 ++++++++
 gcc/testsuite/gcc.target/aarch64/acle/rng_1.c | 53 +++++++++++++++++++++++
 6 files changed, 161 insertions(+)

diff --git a/gcc/config/aarch64/aarch64-builtins.c b/gcc/config/aarch64/aarch64-builtins.c
index d44716c0506..f22f64797a2 100644
--- a/gcc/config/aarch64/aarch64-builtins.c
+++ b/gcc/config/aarch64/aarch64-builtins.c
@@ -438,6 +438,9 @@ enum aarch64_builtins
   AARCH64_SIMD_FCMLA_LANEQ_BUILTINS
   /* Builtin for Arm8.3-a Javascript conversion instruction.  */
   AARCH64_JSCVT,
+  /* Armv8.5-a RNG instruction builtins.  */
+  AARCH64_BUILTIN_RNG_RNDR,
+  AARCH64_BUILTIN_RNG_RNDRRS,
   AARCH64_BUILTIN_MAX
 };
 
@@ -1059,6 +1062,25 @@ aarch64_init_pauth_hint_builtins (void)
 			    NULL_TREE);
 }
 
+/* Add builtins for Random Number instructions.  */
+
+static void
+aarch64_init_rng_builtins (void)
+{
+  tree unsigned_ptr_type = build_pointer_type (unsigned_intDI_type_node);
+  tree ftype
+    = build_function_type_list (integer_type_node, unsigned_ptr_type, NULL);
+  aarch64_builtin_decls[AARCH64_BUILTIN_RNG_RNDR]
+    = add_builtin_function ("__builtin_aarch64_rndr", ftype,
+			    AARCH64_BUILTIN_RNG_RNDR, BUILT_IN_MD, NULL,
+			    NULL_TREE);
+  aarch64_builtin_decls[AARCH64_BUILTIN_RNG_RNDRRS]
+    = add_builtin_function ("__builtin_aarch64_rndrrs", ftype,
+			    AARCH64_BUILTIN_RNG_RNDRRS, BUILT_IN_MD, NULL,
+			    NULL_TREE);
+}
+
+
 void
 aarch64_init_builtins (void)
 {
@@ -1087,6 +1109,7 @@ aarch64_init_builtins (void)
 
   aarch64_init_crc32_builtins ();
   aarch64_init_builtin_rsqrt ();
+  aarch64_init_rng_builtins ();
 
   tree ftype_jcvt
     = build_function_type_list (intSI_type_node, double_type_node, NULL);
@@ -1505,6 +1528,42 @@ aarch64_expand_fcmla_builtin (tree exp, rtx target, int fcode)
   return target;
 }
 
+/* Expand a random number builtin EXP with code FCODE, putting the result
+   int TARGET.  If IGNORE is true the return value is ignored.  */
+
+rtx
+aarch64_expand_rng_builtin (tree exp, rtx target, int fcode, int ignore)
+{
+  rtx pat;
+  enum insn_code icode;
+  if (fcode == AARCH64_BUILTIN_RNG_RNDR)
+    icode = CODE_FOR_aarch64_rndr;
+  else if (fcode == AARCH64_BUILTIN_RNG_RNDRRS)
+    icode = CODE_FOR_aarch64_rndrrs;
+  else
+    gcc_unreachable ();
+
+  rtx rand = gen_reg_rtx (DImode);
+  pat = GEN_FCN (icode) (rand);
+  if (!pat)
+    return NULL_RTX;
+
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  rtx res_addr = expand_normal (arg0);
+  res_addr = convert_memory_address (Pmode, res_addr);
+  rtx res_mem = gen_rtx_MEM (DImode, res_addr);
+  emit_insn (pat);
+  emit_move_insn (res_mem, rand);
+  /* If the status result is unused don't generate the CSET code.  */
+  if (ignore)
+    return target;
+
+  rtx cc_reg = gen_rtx_REG (CC_Zmode, CC_REGNUM);
+  rtx cmp_rtx = gen_rtx_fmt_ee (NE, SImode, cc_reg, const0_rtx);
+  emit_insn (gen_aarch64_cstoresi (target, cmp_rtx, cc_reg));
+  return target;
+}
+
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient.  */
 rtx
@@ -1603,6 +1662,9 @@ aarch64_expand_builtin (tree exp,
     case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ180_V4HF:
     case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ270_V4HF:
       return aarch64_expand_fcmla_builtin (exp, target, fcode);
+    case AARCH64_BUILTIN_RNG_RNDR:
+    case AARCH64_BUILTIN_RNG_RNDRRS:
+      return aarch64_expand_rng_builtin (exp, target, fcode, ignore);
     }
 
   if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
diff --git a/gcc/config/aarch64/aarch64-c.c b/gcc/config/aarch64/aarch64-c.c
index ce2d0aefde1..1812387dee6 100644
--- a/gcc/config/aarch64/aarch64-c.c
+++ b/gcc/config/aarch64/aarch64-c.c
@@ -169,6 +169,8 @@ aarch64_update_cpp_builtins (cpp_reader *pfile)
       builtin_define_with_int_value ("__ARM_FEATURE_PAC_DEFAULT", v);
     }
 
+  aarch64_def_or_undef (TARGET_RNG, "__ARM_FEATURE_RNG", pfile);
+
   /* Not for ACLE, but required to keep "float.h" correct if we switch
      target between implementations that do or do not support ARMv8.2-A
      16-bit floating-point extensions.  */
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index feda7a1385e..ace80ac4cef 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -234,6 +234,7 @@ extern unsigned aarch64_architecture_version;
 #define AARCH64_ISA_SHA3	   (aarch64_isa_flags & AARCH64_FL_SHA3)
 #define AARCH64_ISA_F16FML	   (aarch64_isa_flags & AARCH64_FL_F16FML)
 #define AARCH64_ISA_RCPC8_4	   (aarch64_isa_flags & AARCH64_FL_RCPC8_4)
+#define AARCH64_ISA_RNG		   (aarch64_isa_flags & AARCH64_FL_RNG)
 #define AARCH64_ISA_V8_5	   (aarch64_isa_flags & AARCH64_FL_V8_5)
 #define AARCH64_ISA_SB		   (aarch64_isa_flags & AARCH64_FL_SB)
 
@@ -280,6 +281,9 @@ extern unsigned aarch64_architecture_version;
 /* Armv8.3-a Complex number extension to AdvSIMD extensions.  */
 #define TARGET_COMPLEX (TARGET_SIMD && TARGET_ARMV8_3)
 
+/* Random number instructions from Armv8.5-a.  */
+#define TARGET_RNG (AARCH64_ISA_RNG)
+
 /* Make sure this is always defined so we don't have to check for ifdefs
    but rather use normal ifs.  */
 #ifndef TARGET_FIX_ERR_A53_835769_DEFAULT
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index b99c3402652..8d71994611d 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -247,6 +247,8 @@
     UNSPECV_BTI_C		; Represent BTI c.
     UNSPECV_BTI_J		; Represent BTI j.
     UNSPECV_BTI_JC		; Represent BTI jc.
+    UNSPEC_RNDR			; Represent RNDR
+    UNSPEC_RNDRRS		; Represent RNDRRS
   ]
 )
 
@@ -7270,6 +7272,26 @@
    (set_attr "speculation_barrier" "true")]
 )
 
+(define_insn "aarch64_rndr"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(unspec_volatile:DI [(const_int 0)] UNSPEC_RNDR))
+   (set (reg:CC_Z CC_REGNUM)
+	(unspec_volatile:CC_Z [(const_int 0)] UNSPEC_RNDR))]
+  "TARGET_RNG"
+  "mrs\t%0, RNDR"
+  [(set_attr "type" "mrs")]
+)
+
+(define_insn "aarch64_rndrrs"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(unspec_volatile:DI [(const_int 0)] UNSPEC_RNDRRS))
+   (set (reg:CC_Z CC_REGNUM)
+	(unspec_volatile:CC_Z [(const_int 0)] UNSPEC_RNDRRS))]
+  "TARGET_RNG"
+  "mrs\t%0, RNDRRS"
+  [(set_attr "type" "mrs")]
+)
+
 ;; AdvSIMD Stuff
 (include "aarch64-simd.md")
 
diff --git a/gcc/config/aarch64/arm_acle.h b/gcc/config/aarch64/arm_acle.h
index 29880793bdc..423136ecefd 100644
--- a/gcc/config/aarch64/arm_acle.h
+++ b/gcc/config/aarch64/arm_acle.h
@@ -99,6 +99,24 @@ __crc32d (uint32_t __a, uint64_t __b)
   return __builtin_aarch64_crc32x (__a, __b);
 }
 
+#pragma GCC pop_options
+
+#pragma GCC push_options
+#pragma GCC target ("+nothing+rng")
+__extension__ static __inline int __attribute__ ((__always_inline__))
+__rndr (uint64_t *__res)
+{
+  return __builtin_aarch64_rndr (__res);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+__rndrrs (uint64_t *__res)
+{
+  return __builtin_aarch64_rndrrs (__res);
+}
+
+#pragma GCC pop_options
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/gcc/testsuite/gcc.target/aarch64/acle/rng_1.c b/gcc/testsuite/gcc.target/aarch64/acle/rng_1.c
new file mode 100644
index 00000000000..1fbdb627663
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/acle/rng_1.c
@@ -0,0 +1,53 @@
+/* Test the __rndr ACLE intrinsic.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv8.5-a+rng" } */
+
+#include <arm_acle.h>
+
+#ifdef __ARM_FEATURE_RNG
+/* Check that instruction is generated when status result is unused.  */
+uint64_t
+test_rndr_no_stat (void)
+{
+  uint64_t res;
+  __rndr (&res);
+  return res;
+}
+
+/* Check that instruction is generated when random number result
+   is unused.  */
+int
+test_rndr_error_check (void)
+{
+  uint64_t res;
+  int fail = __rndr (&res);
+  if (fail)
+    return 0;
+  return -1;
+}
+
+/* { dg-final { scan-assembler-times "mrs\tx..?, RNDR\n" 2 } } */
+
+/* Check that instruction is generated when status result is unused.  */
+uint64_t
+test_rndrrs_no_stat (void)
+{
+  uint64_t res;
+  __rndrrs (&res);
+  return res;
+}
+
+/* Check that instruction is generated when random number result
+   is unused.  */
+int
+test_rndrrs_error_check (void)
+{
+  uint64_t res;
+  int fail = __rndrrs (&res);
+  if (fail)
+    return 0;
+  return -1;
+}
+
+/* { dg-final { scan-assembler-times "mrs\tx..?, RNDRRS\n" 2 } } */
+#endif


More information about the Gcc-cvs mailing list