Commit c5dc215d by Kyrylo Tkachov Committed by Kyrylo Tkachov

[AArch64] 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

	* 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.c (aarch64_expand_builtin): Use IGNORE
	argument.
	* config/aarch64/aarch64-protos.h (aarch64_general_expand_builtin):
	Add fourth argument in prototype.
	* config/aarch64/aarch64-builtins.c (enum aarch64_builtins):
	Add AARCH64_BUILTIN_RNG_RNDR, AARCH64_BUILTIN_RNG_RNDRRS.
	(aarch64_init_rng_builtins): Define.
	(aarch64_general_init_builtins): Call aarch64_init_rng_builtins.
	(aarch64_expand_rng_builtin): Define.
	(aarch64_general_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.target/aarch64/acle/rng_1.c: New test.

From-SVN: r277239
parent d2db7f79
2019-10-21 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
* 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.c (aarch64_expand_builtin): Use IGNORE
argument.
* config/aarch64/aarch64-protos.h (aarch64_general_expand_builtin):
Add fourth argument in prototype.
* config/aarch64/aarch64-builtins.c (enum aarch64_builtins):
Add AARCH64_BUILTIN_RNG_RNDR, AARCH64_BUILTIN_RNG_RNDRRS.
(aarch64_init_rng_builtins): Define.
(aarch64_general_init_builtins): Call aarch64_init_rng_builtins.
(aarch64_expand_rng_builtin): Define.
(aarch64_general_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.
2019-10-21 Andre Vieira <andre.simoesdiasvieira@arm.com> 2019-10-21 Andre Vieira <andre.simoesdiasvieira@arm.com>
* tree-vect-stmts (ensure_base_align): Only change alignment if new * tree-vect-stmts (ensure_base_align): Only change alignment if new
...@@ -445,6 +445,9 @@ enum aarch64_builtins ...@@ -445,6 +445,9 @@ enum aarch64_builtins
AARCH64_TME_BUILTIN_TCOMMIT, AARCH64_TME_BUILTIN_TCOMMIT,
AARCH64_TME_BUILTIN_TTEST, AARCH64_TME_BUILTIN_TTEST,
AARCH64_TME_BUILTIN_TCANCEL, AARCH64_TME_BUILTIN_TCANCEL,
/* Armv8.5-a RNG instruction builtins. */
AARCH64_BUILTIN_RNG_RNDR,
AARCH64_BUILTIN_RNG_RNDRRS,
AARCH64_BUILTIN_MAX AARCH64_BUILTIN_MAX
}; };
...@@ -1111,7 +1114,25 @@ aarch64_init_tme_builtins (void) ...@@ -1111,7 +1114,25 @@ aarch64_init_tme_builtins (void)
AARCH64_TME_BUILTIN_TCANCEL); AARCH64_TME_BUILTIN_TCANCEL);
} }
/* 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]
= aarch64_general_add_builtin ("__builtin_aarch64_rndr", ftype,
AARCH64_BUILTIN_RNG_RNDR);
aarch64_builtin_decls[AARCH64_BUILTIN_RNG_RNDRRS]
= aarch64_general_add_builtin ("__builtin_aarch64_rndrrs", ftype,
AARCH64_BUILTIN_RNG_RNDRRS);
}
/* Initialize all builtins in the AARCH64_BUILTIN_GENERAL group. */ /* Initialize all builtins in the AARCH64_BUILTIN_GENERAL group. */
void void
aarch64_general_init_builtins (void) aarch64_general_init_builtins (void)
{ {
...@@ -1144,6 +1165,7 @@ aarch64_general_init_builtins (void) ...@@ -1144,6 +1165,7 @@ aarch64_general_init_builtins (void)
aarch64_init_crc32_builtins (); aarch64_init_crc32_builtins ();
aarch64_init_builtin_rsqrt (); aarch64_init_builtin_rsqrt ();
aarch64_init_rng_builtins ();
tree ftype_jcvt tree ftype_jcvt
= build_function_type_list (intSI_type_node, double_type_node, NULL); = build_function_type_list (intSI_type_node, double_type_node, NULL);
...@@ -1607,10 +1629,48 @@ aarch64_expand_builtin_tme (int fcode, tree exp, rtx target) ...@@ -1607,10 +1629,48 @@ aarch64_expand_builtin_tme (int fcode, tree exp, rtx target)
return target; 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 built-in function FCODE, /* Expand an expression EXP that calls built-in function FCODE,
with result going to TARGET if that's convenient. */ with result going to TARGET if that's convenient. IGNORE is true
if the result of the builtin is ignored. */
rtx rtx
aarch64_general_expand_builtin (unsigned int fcode, tree exp, rtx target) aarch64_general_expand_builtin (unsigned int fcode, tree exp, rtx target,
int ignore)
{ {
int icode; int icode;
rtx pat, op0; rtx pat, op0;
...@@ -1717,6 +1777,9 @@ aarch64_general_expand_builtin (unsigned int fcode, tree exp, rtx target) ...@@ -1717,6 +1777,9 @@ aarch64_general_expand_builtin (unsigned int fcode, tree exp, rtx target)
case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ180_V4HF: case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ180_V4HF:
case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ270_V4HF: case AARCH64_SIMD_BUILTIN_FCMLA_LANEQ270_V4HF:
return aarch64_expand_fcmla_builtin (exp, target, fcode); 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) if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
......
...@@ -160,6 +160,7 @@ aarch64_update_cpp_builtins (cpp_reader *pfile) ...@@ -160,6 +160,7 @@ aarch64_update_cpp_builtins (cpp_reader *pfile)
aarch64_def_or_undef (TARGET_FRINT, "__ARM_FEATURE_FRINT", pfile); aarch64_def_or_undef (TARGET_FRINT, "__ARM_FEATURE_FRINT", pfile);
aarch64_def_or_undef (TARGET_TME, "__ARM_FEATURE_TME", pfile); aarch64_def_or_undef (TARGET_TME, "__ARM_FEATURE_TME", pfile);
aarch64_def_or_undef (TARGET_RNG, "__ARM_FEATURE_RNG", pfile);
/* Not for ACLE, but required to keep "float.h" correct if we switch /* 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 target between implementations that do or do not support ARMv8.2-A
......
...@@ -659,7 +659,7 @@ const char *aarch64_general_mangle_builtin_type (const_tree); ...@@ -659,7 +659,7 @@ const char *aarch64_general_mangle_builtin_type (const_tree);
void aarch64_general_init_builtins (void); void aarch64_general_init_builtins (void);
tree aarch64_general_fold_builtin (unsigned int, tree, unsigned int, tree *); tree aarch64_general_fold_builtin (unsigned int, tree, unsigned int, tree *);
gimple *aarch64_general_gimple_fold_builtin (unsigned int, gcall *); gimple *aarch64_general_gimple_fold_builtin (unsigned int, gcall *);
rtx aarch64_general_expand_builtin (unsigned int, tree, rtx); rtx aarch64_general_expand_builtin (unsigned int, tree, rtx, int);
tree aarch64_general_builtin_decl (unsigned, bool); tree aarch64_general_builtin_decl (unsigned, bool);
tree aarch64_general_builtin_rsqrt (unsigned int); tree aarch64_general_builtin_rsqrt (unsigned int);
tree aarch64_builtin_vectorized_function (unsigned int, tree, tree); tree aarch64_builtin_vectorized_function (unsigned int, tree, tree);
......
...@@ -11737,7 +11737,7 @@ aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi) ...@@ -11737,7 +11737,7 @@ aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi)
/* Implement TARGET_EXPAND_BUILTIN. */ /* Implement TARGET_EXPAND_BUILTIN. */
static rtx static rtx
aarch64_expand_builtin (tree exp, rtx target, rtx, machine_mode, int) aarch64_expand_builtin (tree exp, rtx target, rtx, machine_mode, int ignore)
{ {
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
unsigned int code = DECL_MD_FUNCTION_CODE (fndecl); unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
...@@ -11745,7 +11745,7 @@ aarch64_expand_builtin (tree exp, rtx target, rtx, machine_mode, int) ...@@ -11745,7 +11745,7 @@ aarch64_expand_builtin (tree exp, rtx target, rtx, machine_mode, int)
switch (code & AARCH64_BUILTIN_CLASS) switch (code & AARCH64_BUILTIN_CLASS)
{ {
case AARCH64_BUILTIN_GENERAL: case AARCH64_BUILTIN_GENERAL:
return aarch64_general_expand_builtin (subcode, exp, target); return aarch64_general_expand_builtin (subcode, exp, target, ignore);
} }
gcc_unreachable (); gcc_unreachable ();
} }
......
...@@ -245,6 +245,7 @@ extern unsigned aarch64_architecture_version; ...@@ -245,6 +245,7 @@ extern unsigned aarch64_architecture_version;
#define AARCH64_ISA_SHA3 (aarch64_isa_flags & AARCH64_FL_SHA3) #define AARCH64_ISA_SHA3 (aarch64_isa_flags & AARCH64_FL_SHA3)
#define AARCH64_ISA_F16FML (aarch64_isa_flags & AARCH64_FL_F16FML) #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_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_V8_5 (aarch64_isa_flags & AARCH64_FL_V8_5)
#define AARCH64_ISA_TME (aarch64_isa_flags & AARCH64_FL_TME) #define AARCH64_ISA_TME (aarch64_isa_flags & AARCH64_FL_TME)
...@@ -300,6 +301,9 @@ extern unsigned aarch64_architecture_version; ...@@ -300,6 +301,9 @@ extern unsigned aarch64_architecture_version;
/* TME instructions are enabled. */ /* TME instructions are enabled. */
#define TARGET_TME (AARCH64_ISA_TME) #define TARGET_TME (AARCH64_ISA_TME)
/* 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 /* Make sure this is always defined so we don't have to check for ifdefs
but rather use normal ifs. */ but rather use normal ifs. */
#ifndef TARGET_FIX_ERR_A53_835769_DEFAULT #ifndef TARGET_FIX_ERR_A53_835769_DEFAULT
......
...@@ -262,6 +262,8 @@ ...@@ -262,6 +262,8 @@
UNSPECV_TSTART ; Represent transaction start. UNSPECV_TSTART ; Represent transaction start.
UNSPECV_TCOMMIT ; Represent transaction commit. UNSPECV_TCOMMIT ; Represent transaction commit.
UNSPECV_TCANCEL ; Represent transaction cancel. UNSPECV_TCANCEL ; Represent transaction cancel.
UNSPEC_RNDR ; Represent RNDR
UNSPEC_RNDRRS ; Represent RNDRRS
] ]
) )
...@@ -7338,6 +7340,26 @@ ...@@ -7338,6 +7340,26 @@
[(set_attr "type" "tme")] [(set_attr "type" "tme")]
) )
(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 ;; AdvSIMD Stuff
(include "aarch64-simd.md") (include "aarch64-simd.md")
......
...@@ -193,6 +193,22 @@ __ttest (void) ...@@ -193,6 +193,22 @@ __ttest (void)
#pragma GCC pop_options #pragma GCC pop_options
#endif #endif
#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 #ifdef __cplusplus
} }
#endif #endif
......
2019-10-21 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
* gcc.target/aarch64/acle/rng_1.c: New test.
2019-10-21 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org> 2019-10-21 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
PR tree-optimization/91532 PR tree-optimization/91532
......
/* 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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment