Hi all,This patch implements the CRC32 intrinsics that map down to the optional CRC32 instructions in ARMv8-A as defined by ACLE. They are exposed by a new header file: arm_acle.h which can be included in user programs similarly to the existing arm_neon.h header.
To enable the use of these intrinsics (and instructions) we define a new -march=armv8-a+crc option. We will pass the "crc" option as a .arch_extension directive in the generated assembly to gas.
Documentation and testsuite changes are included (a new effective target check and option-adding procedure in testsuite/lib). A new directory: gcc.target/arm/acle/ is added that contains the new tests and can be used to contain tests for other non-NEON ACLE intrinsics that might be implemented in the future.
Regtested arm-none-eabi on a model and bootstrapped arm-none-linux-gnueabihf on a Chromebook.
Ok for trunk? Thanks, Kyrill gcc/ 2013-11-19 Kyrylo Tkachov <kyrylo.tkac...@arm.com> * Makefile.in (TEXI_GCC_FILES): Add arm-acle-intrinsics.texi. * config.gcc (extra_headers): Add arm_acle.h. * config/arm/arm.c (FL_CRC32): Define. (arm_have_crc): Likewise. (arm_option_override): Set arm_have_crc. (arm_builtins): Add CRC32 builtins. (bdesc_2arg): Likewise. (arm_init_crc32_builtins): New function. (arm_init_builtins): Initialise CRC32 builtins. (arm_file_start): Handle architecture extensions. * config/arm/arm.h (TARGET_CPU_CPP_BUILTINS): Define __ARM_FEATURE_CRC32. Define __ARM_32BIT_STATE. (TARGET_CRC32): Define. * config/arm/arm-arches.def: Add armv8-a+crc. * config/arm/arm-tables.opt: Regenerate. * config/arm/arm.md (type): Add crc. (<crc_variant>): New insn. * config/arm/arm_acle.h: New file. * config/arm/iterators.md (CRC): New int iterator. (crc_variant, crc_mode): New int attributes. * confg/arm/unspecs.md (UNSPEC_CRC32B, UNSPEC_CRC32H, UNSPEC_CRC32W, UNSPEC_CRC32CB, UNSPEC_CRC32CH, UNSPEC_CRC32CW): New unspecs. * doc/invoke.texi: Document -march=armv8-a+crc option. * doc/extend.texi: Document ACLE intrinsics. * doc/arm-acle-intrinsics.texi: New. gcc/testsuite 2013-11-19 Kyrylo Tkachov <kyrylo.tkac...@arm.com> * lib/target-supports.exp (add_options_for_arm_crc): New procedure. (check_effective_target_arm_crc_ok_nocache): Likewise. (check_effective_target_arm_crc_ok): Likewise. * gcc.target/arm/acle/: New directory. * gcc.target/arm/acle/acle.exp: New. * gcc.target/arm/acle/crc32b.c: New test. * gcc.target/arm/acle/crc32h.c: Likewise. * gcc.target/arm/acle/crc32w.c: Likewise. * gcc.target/arm/acle/crc32d.c: Likewise. * gcc.target/arm/acle/crc32cb.c: Likewise. * gcc.target/arm/acle/crc32ch.c: Likewise. * gcc.target/arm/acle/crc32cw.c: Likewise. * gcc.target/arm/acle/crc32cd.c: Likewise.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 77fba80..08f1ea1 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2793,7 +2793,8 @@ TEXI_GCC_FILES = gcc.texi gcc-common.texi gcc-vers.texi frontends.texi \ gcov.texi trouble.texi bugreport.texi service.texi \ contribute.texi compat.texi funding.texi gnu.texi gpl_v3.texi \ fdl.texi contrib.texi cppenv.texi cppopts.texi avr-mmcu.texi \ - implement-c.texi implement-cxx.texi arm-neon-intrinsics.texi + implement-c.texi implement-cxx.texi arm-neon-intrinsics.texi \ + arm-acle-intrinsics.texi # we explicitly use $(srcdir)/doc/tm.texi here to avoid confusion with # the generated tm.texi; the latter might have a more recent timestamp, diff --git a/gcc/config.gcc b/gcc/config.gcc index 2907018..ebbdc59 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -329,8 +329,8 @@ arc*-*-*) ;; arm*-*-*) cpu_type=arm - extra_headers="mmintrin.h arm_neon.h" extra_objs="aarch-common.o" + extra_headers="mmintrin.h arm_neon.h arm_acle.h" target_type_format_char='%' c_target_objs="arm-c.o" cxx_target_objs="arm-c.o" diff --git a/gcc/config/arm/arm-arches.def b/gcc/config/arm/arm-arches.def index fcf3401..9b7d20c 100644 --- a/gcc/config/arm/arm-arches.def +++ b/gcc/config/arm/arm-arches.def @@ -54,5 +54,6 @@ ARM_ARCH("armv7-r", cortexr4, 7R, FL_CO_PROC | FL_FOR_ARCH7R) ARM_ARCH("armv7-m", cortexm3, 7M, FL_CO_PROC | FL_FOR_ARCH7M) ARM_ARCH("armv7e-m", cortexm4, 7EM, FL_CO_PROC | FL_FOR_ARCH7EM) ARM_ARCH("armv8-a", cortexa53, 8A, FL_CO_PROC | FL_FOR_ARCH8A) +ARM_ARCH("armv8-a+crc",cortexa53, 8A,FL_CO_PROC | FL_CRC32 | FL_FOR_ARCH8A) ARM_ARCH("iwmmxt", iwmmxt, 5TE, FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT) ARM_ARCH("iwmmxt2", iwmmxt2, 5TE, FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT | FL_IWMMXT2) diff --git a/gcc/config/arm/arm-tables.opt b/gcc/config/arm/arm-tables.opt index b3e7a7c..8851876 100644 --- a/gcc/config/arm/arm-tables.opt +++ b/gcc/config/arm/arm-tables.opt @@ -362,10 +362,13 @@ EnumValue Enum(arm_arch) String(armv8-a) Value(23) EnumValue -Enum(arm_arch) String(iwmmxt) Value(24) +Enum(arm_arch) String(armv8-a+crc) Value(24) EnumValue -Enum(arm_arch) String(iwmmxt2) Value(25) +Enum(arm_arch) String(iwmmxt) Value(25) + +EnumValue +Enum(arm_arch) String(iwmmxt2) Value(26) Enum Name(arm_fpu) Type(int) diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 1686f1d..cb35e56 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -732,6 +732,7 @@ static int thumb_call_reg_needed; #define FL_ARCH7 (1 << 22) /* Architecture 7. */ #define FL_ARM_DIV (1 << 23) /* Hardware divide (ARM mode). */ #define FL_ARCH8 (1 << 24) /* Architecture 8. */ +#define FL_CRC32 (1 << 25) /* ARMv8 CRC32 instructions. */ #define FL_IWMMXT (1 << 29) /* XScale v2 or "Intel Wireless MMX technology". */ #define FL_IWMMXT2 (1 << 30) /* "Intel Wireless MMX2 technology". */ @@ -894,6 +895,9 @@ int arm_condexec_mask = 0; /* The number of bits used in arm_condexec_mask. */ int arm_condexec_masklen = 0; +/* Nonzero if chip supports the ARMv8 CRC instructions. */ +int arm_arch_crc = 0; + /* The condition codes of the ARM, and the inverse function. */ static const char * const arm_condition_codes[] = { @@ -2370,6 +2374,7 @@ arm_option_override (void) arm_arch_thumb_hwdiv = (insn_flags & FL_THUMB_DIV) != 0; arm_arch_arm_hwdiv = (insn_flags & FL_ARM_DIV) != 0; arm_tune_cortex_a9 = (arm_tune == cortexa9) != 0; + arm_arch_crc = (insn_flags & FL_CRC32) != 0; if (arm_restrict_it == 2) arm_restrict_it = arm_arch8 && TARGET_THUMB2; @@ -22916,6 +22921,13 @@ enum arm_builtins ARM_BUILTIN_WMERGE, + ARM_BUILTIN_CRC32B, + ARM_BUILTIN_CRC32H, + ARM_BUILTIN_CRC32W, + ARM_BUILTIN_CRC32CB, + ARM_BUILTIN_CRC32CH, + ARM_BUILTIN_CRC32CW, + #include "arm_neon_builtins.def" ,ARM_BUILTIN_MAX @@ -23495,7 +23507,7 @@ struct builtin_description const enum rtx_code comparison; const unsigned int flag; }; - + static const struct builtin_description bdesc_2arg[] = { #define IWMMXT_BUILTIN(code, string, builtin) \ @@ -23601,6 +23613,17 @@ static const struct builtin_description bdesc_2arg[] = IWMMXT_BUILTIN2 (iwmmxt_wpackdus, WPACKDUS) IWMMXT_BUILTIN2 (iwmmxt_wmacuz, WMACUZ) IWMMXT_BUILTIN2 (iwmmxt_wmacsz, WMACSZ) + +#define CRC32_BUILTIN(L, U) \ + {0, CODE_FOR_##L, "__builtin_arm_"#L, ARM_BUILTIN_##U, \ + UNKNOWN, 0}, + CRC32_BUILTIN (crc32b, CRC32B) + CRC32_BUILTIN (crc32h, CRC32H) + CRC32_BUILTIN (crc32w, CRC32W) + CRC32_BUILTIN (crc32cb, CRC32CB) + CRC32_BUILTIN (crc32ch, CRC32CH) + CRC32_BUILTIN (crc32cw, CRC32CW) +#undef CRC32_BUILTIN }; static const struct builtin_description bdesc_1arg[] = @@ -24020,6 +24043,42 @@ arm_init_fp16_builtins (void) } static void +arm_init_crc32_builtins () +{ + tree si_ftype_si_qi + = build_function_type_list (unsigned_intSI_type_node, + unsigned_intSI_type_node, + unsigned_intQI_type_node, NULL_TREE); + tree si_ftype_si_hi + = build_function_type_list (unsigned_intSI_type_node, + unsigned_intSI_type_node, + unsigned_intHI_type_node, NULL_TREE); + tree si_ftype_si_si + = build_function_type_list (unsigned_intSI_type_node, + unsigned_intSI_type_node, + unsigned_intSI_type_node, NULL_TREE); + + arm_builtin_decls[ARM_BUILTIN_CRC32B] + = add_builtin_function ("__builtin_arm_crc32b", si_ftype_si_qi, + ARM_BUILTIN_CRC32B, BUILT_IN_MD, NULL, NULL_TREE); + arm_builtin_decls[ARM_BUILTIN_CRC32H] + = add_builtin_function ("__builtin_arm_crc32h", si_ftype_si_hi, + ARM_BUILTIN_CRC32H, BUILT_IN_MD, NULL, NULL_TREE); + arm_builtin_decls[ARM_BUILTIN_CRC32W] + = add_builtin_function ("__builtin_arm_crc32w", si_ftype_si_si, + ARM_BUILTIN_CRC32W, BUILT_IN_MD, NULL, NULL_TREE); + arm_builtin_decls[ARM_BUILTIN_CRC32CB] + = add_builtin_function ("__builtin_arm_crc32cb", si_ftype_si_qi, + ARM_BUILTIN_CRC32CB, BUILT_IN_MD, NULL, NULL_TREE); + arm_builtin_decls[ARM_BUILTIN_CRC32CH] + = add_builtin_function ("__builtin_arm_crc32ch", si_ftype_si_hi, + ARM_BUILTIN_CRC32CH, BUILT_IN_MD, NULL, NULL_TREE); + arm_builtin_decls[ARM_BUILTIN_CRC32CW] + = add_builtin_function ("__builtin_arm_crc32cw", si_ftype_si_si, + ARM_BUILTIN_CRC32CW, BUILT_IN_MD, NULL, NULL_TREE); +} + +static void arm_init_builtins (void) { if (TARGET_REALLY_IWMMXT) @@ -24030,6 +24089,9 @@ arm_init_builtins (void) if (arm_fp16_format) arm_init_fp16_builtins (); + + if (TARGET_CRC32) + arm_init_crc32_builtins (); } /* Return the ARM builtin for CODE. */ @@ -27303,7 +27365,22 @@ arm_file_start (void) { const char *fpu_name; if (arm_selected_arch) - asm_fprintf (asm_out_file, "\t.arch %s\n", arm_selected_arch->name); + { + const char* pos = strchr (arm_selected_arch->name, '+'); + if (pos) + { + char buf[15]; + gcc_assert (strlen (arm_selected_arch->name) + <= sizeof (buf) / sizeof (*pos)); + strncpy (buf, arm_selected_arch->name, + (pos - arm_selected_arch->name) * sizeof (*pos)); + buf[pos - arm_selected_arch->name] = '\0'; + asm_fprintf (asm_out_file, "\t.arch %s\n", buf); + asm_fprintf (asm_out_file, "\t.arch_extension %s\n", pos + 1); + } + else + asm_fprintf (asm_out_file, "\t.arch %s\n", arm_selected_arch->name); + } else if (strncmp (arm_selected_cpu->name, "generic", 7) == 0) asm_fprintf (asm_out_file, "\t.arch %s\n", arm_selected_cpu->name + 8); else diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 1781b75..85eeb2a 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -51,6 +51,10 @@ extern char arm_arch_name[]; builtin_define ("__ARM_FEATURE_SAT"); \ if (unaligned_access) \ builtin_define ("__ARM_FEATURE_UNALIGNED"); \ + if (TARGET_CRC32) \ + builtin_define ("__ARM_FEATURE_CRC32"); \ + if (TARGET_32BIT) \ + builtin_define ("__ARM_32BIT_STATE"); \ if (TARGET_ARM_FEATURE_LDREX) \ builtin_define_with_int_value ( \ "__ARM_FEATURE_LDREX", TARGET_ARM_FEATURE_LDREX); \ @@ -274,6 +278,8 @@ extern void (*arm_lang_output_object_attributes_hook)(void); #define TARGET_LDRD (arm_arch5e && ARM_DOUBLEWORD_ALIGN \ && !TARGET_THUMB1) +#define TARGET_CRC32 (arm_arch_crc) + /* The following two macros concern the ability to execute coprocessor instructions for VFPv3 or NEON. TARGET_VFP3/TARGET_VFPD32 are currently only ever tested when we know we are generating for VFP hardware; we need @@ -554,6 +560,9 @@ extern int arm_arch_thumb_hwdiv; than core registers. */ extern int prefer_neon_for_64bits; +/* Nonzero if chip supports the ARMv8 CRC instructions. */ +extern int arm_arch_crc; + #ifndef TARGET_DEFAULT #define TARGET_DEFAULT (MASK_APCS_FRAME) #endif diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 3726201..75444d2 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -12756,6 +12756,16 @@ (set_attr "predicable" "yes") (set_attr "predicable_short_it" "no")]) +;; ARMv8 CRC32 instructions. +(define_insn "<crc_variant>" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:<crc_mode> 2 "s_register_operand" "r")] + CRC))] + "TARGET_CRC32" + "<crc_variant>\\t%0, %1, %2" + [(set_attr "type" "crc")] +) ;; Load the load/store double peephole optimizations. (include "ldrdstrd.md") diff --git a/gcc/config/arm/arm_acle.h b/gcc/config/arm/arm_acle.h new file mode 100644 index 0000000..b04605b --- /dev/null +++ b/gcc/config/arm/arm_acle.h @@ -0,0 +1,100 @@ +/* ARM Non-NEON ACLE intrinsics include file. + + Copyright (C) 2013 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _GCC_ARM_ACLE_H +#define _GCC_ARM_ACLE_H + +#include <stdint.h> +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __ARM_FEATURE_CRC32 +__extension__ static __inline uint32_t __attribute__ ((__always_inline__)) +__crc32b (uint32_t a, uint8_t b) +{ + return __builtin_arm_crc32b (a, b); +} + +__extension__ static __inline uint32_t __attribute__ ((__always_inline__)) +__crc32h (uint32_t a, uint16_t b) +{ + return __builtin_arm_crc32h (a, b); +} + +__extension__ static __inline uint32_t __attribute__ ((__always_inline__)) +__crc32w (uint32_t a, uint32_t b) +{ + return __builtin_arm_crc32w (a, b); +} + +#ifdef __ARM_32BIT_STATE +__extension__ static __inline uint32_t __attribute__ ((__always_inline__)) +__crc32d (uint32_t a, uint64_t b) +{ + uint32_t d; + + d = __crc32w (__crc32w (a, b & 0xffffffffULL), b >> 32); + return d; +} +#endif + +__extension__ static __inline uint32_t __attribute__ ((__always_inline__)) +__crc32cb (uint32_t a, uint8_t b) +{ + return __builtin_arm_crc32cb (a, b); +} + +__extension__ static __inline uint32_t __attribute__ ((__always_inline__)) +__crc32ch (uint32_t a, uint16_t b) +{ + return __builtin_arm_crc32ch (a, b); +} + +__extension__ static __inline uint32_t __attribute__ ((__always_inline__)) +__crc32cw (uint32_t a, uint32_t b) +{ + return __builtin_arm_crc32cw (a, b); +} + +#ifdef __ARM_32BIT_STATE +__extension__ static __inline uint32_t __attribute__ ((__always_inline__)) +__crc32cd (uint32_t a, uint64_t b) +{ + uint32_t d; + + d = __crc32cw (__crc32cw (a, b & 0xffffffffULL), b >> 32); + return d; +} +#endif + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md index 38777b8..fcffc87 100644 --- a/gcc/config/arm/iterators.md +++ b/gcc/config/arm/iterators.md @@ -201,6 +201,9 @@ (define_int_iterator NEON_VRINT [UNSPEC_NVRINTP UNSPEC_NVRINTZ UNSPEC_NVRINTM UNSPEC_NVRINTX UNSPEC_NVRINTA UNSPEC_NVRINTN]) +(define_int_iterator CRC [UNSPEC_CRC32B UNSPEC_CRC32H UNSPEC_CRC32W + UNSPEC_CRC32CB UNSPEC_CRC32CH UNSPEC_CRC32CW]) + ;;---------------------------------------------------------------------------- ;; Mode attributes ;;---------------------------------------------------------------------------- @@ -514,6 +517,15 @@ (define_int_attr nvrint_variant [(UNSPEC_NVRINTZ "z") (UNSPEC_NVRINTP "p") (UNSPEC_NVRINTA "a") (UNSPEC_NVRINTM "m") (UNSPEC_NVRINTX "x") (UNSPEC_NVRINTN "n")]) + +(define_int_attr crc_variant [(UNSPEC_CRC32B "crc32b") (UNSPEC_CRC32H "crc32h") + (UNSPEC_CRC32W "crc32w") (UNSPEC_CRC32CB "crc32cb") + (UNSPEC_CRC32CH "crc32ch") (UNSPEC_CRC32CW "crc32cw")]) + +(define_int_attr crc_mode [(UNSPEC_CRC32B "QI") (UNSPEC_CRC32H "HI") + (UNSPEC_CRC32W "SI") (UNSPEC_CRC32CB "QI") + (UNSPEC_CRC32CH "HI") (UNSPEC_CRC32CW "SI")]) + ;; Both kinds of return insn. (define_code_iterator returns [return simple_return]) (define_code_attr return_str [(return "") (simple_return "simple_")]) diff --git a/gcc/config/arm/types.md b/gcc/config/arm/types.md index 1c4b9e3..b505be3 100644 --- a/gcc/config/arm/types.md +++ b/gcc/config/arm/types.md @@ -543,6 +543,7 @@ clz,\ no_insn,\ csel,\ + crc,\ extend,\ f_cvt,\ f_cvtf2i,\ diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md index 508603c..f8faba3 100644 --- a/gcc/config/arm/unspecs.md +++ b/gcc/config/arm/unspecs.md @@ -149,6 +149,12 @@ (define_c_enum "unspec" [ UNSPEC_ASHIFT_SIGNED UNSPEC_ASHIFT_UNSIGNED + UNSPEC_CRC32B + UNSPEC_CRC32H + UNSPEC_CRC32W + UNSPEC_CRC32CB + UNSPEC_CRC32CH + UNSPEC_CRC32CW UNSPEC_LOAD_COUNT UNSPEC_VABD UNSPEC_VABDL diff --git a/gcc/doc/arm-acle-intrinsics.texi b/gcc/doc/arm-acle-intrinsics.texi new file mode 100644 index 0000000..bb6290b --- /dev/null +++ b/gcc/doc/arm-acle-intrinsics.texi @@ -0,0 +1,55 @@ +@c Copyright (C) 2013 Free Software Foundation, Inc. +@c This is part of the GCC manual. +@c For copying conditions, see the file gcc.texi. + +@subsubsection CRC32 intrinsics + +@itemize @bullet +@item uint32_t __crc32b (uint32_t, uint8_t) +@*@emph{Form of expected instruction(s):} @code{crc32b @var{r0}, @var{r0}, @var{r0}} +@end itemize + + +@itemize @bullet +@item uint32_t __crc32h (uint32_t, uint16_t) +@*@emph{Form of expected instruction(s):} @code{crc32h @var{r0}, @var{r0}, @var{r0}} +@end itemize + + +@itemize @bullet +@item uint32_t __crc32w (uint32_t, uint32_t) +@*@emph{Form of expected instruction(s):} @code{crc32w @var{r0}, @var{r0}, @var{r0}} +@end itemize + + +@itemize @bullet +@item uint32_t __crc32d (uint32_t, uint64_t) +@*@emph{Form of expected instruction(s):} Two @code{crc32w @var{r0}, @var{r0}, @var{r0}} +instructions for AArch32. One @code{crc32w @var{w0}, @var{w0}, @var{x0}} instruction for +AArch64. +@end itemize + +@itemize @bullet +@item uint32_t __crc32cb (uint32_t, uint8_t) +@*@emph{Form of expected instruction(s):} @code{crc32cb @var{r0}, @var{r0}, @var{r0}} +@end itemize + + +@itemize @bullet +@item uint32_t __crc32ch (uint32_t, uint16_t) +@*@emph{Form of expected instruction(s):} @code{crc32ch @var{r0}, @var{r0}, @var{r0}} +@end itemize + + +@itemize @bullet +@item uint32_t __crc32cw (uint32_t, uint32_t) +@*@emph{Form of expected instruction(s):} @code{crc32cw @var{r0}, @var{r0}, @var{r0}} +@end itemize + + +@itemize @bullet +@item uint32_t __crc32cd (uint32_t, uint64_t) +@*@emph{Form of expected instruction(s):} Two @code{crc32cw @var{r0}, @var{r0}, @var{r0}} +instructions for AArch32. One @code{crc32cw @var{w0}, @var{w0}, @var{x0}} instruction for +AArch64. +@end itemize diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 88eba80..2880953 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -9204,6 +9204,7 @@ instructions, but allow the compiler to schedule those calls. * ARC SIMD Built-in Functions:: * ARM iWMMXt Built-in Functions:: * ARM NEON Intrinsics:: +* ARM ACLE Intrinsics:: * AVR Built-in Functions:: * Blackfin Built-in Functions:: * FR-V Built-in Functions:: @@ -9895,6 +9896,14 @@ when the @option{-mfpu=neon} switch is used: @include arm-neon-intrinsics.texi +@node ARM ACLE Intrinsics +@subsection ARM ACLE Intrinsics + +These built-in intrinsics for the ARMv8-A CRC32 extension are available when +the @option{-march=armv8-a+crc} switch is used: + +@include arm-acle-intrinsics.texi + @node AVR Built-in Functions @subsection AVR Built-in Functions diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 8855fb7..87bcc1c 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -12093,9 +12093,12 @@ of the @option{-mcpu=} option. Permissible names are: @samp{armv2}, @samp{armv6}, @samp{armv6j}, @samp{armv6t2}, @samp{armv6z}, @samp{armv6zk}, @samp{armv6-m}, @samp{armv7}, @samp{armv7-a}, @samp{armv7-r}, @samp{armv7-m}, -@samp{armv8-a}, +@samp{armv8-a}, @samp{armv8-a+crc}, @samp{iwmmxt}, @samp{iwmmxt2}, @samp{ep9312}. +@option{-march=armv8-a+crc} enables code generation for the ARMv8-A +architecture together with the optional CRC32 extensions. + @option{-march=native} causes the compiler to auto-detect the architecture of the build computer. At present, this feature is only supported on Linux, and not all architectures are recognized. If the auto-detect is diff --git a/gcc/testsuite/gcc.target/arm/acle/acle.exp b/gcc/testsuite/gcc.target/arm/acle/acle.exp new file mode 100644 index 0000000..a1822a1 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/acle/acle.exp @@ -0,0 +1,35 @@ +# Copyright (C) 2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't an ARM target. +if ![istarget arm*-*-*] then { + return +} + +# Load support procs. +load_lib gcc-dg.exp + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \ + "" "" + +# All done. +dg-finish diff --git a/gcc/testsuite/gcc.target/arm/acle/crc32b.c b/gcc/testsuite/gcc.target/arm/acle/crc32b.c new file mode 100644 index 0000000..d6f35e9 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/acle/crc32b.c @@ -0,0 +1,20 @@ +/* Test the crc32b ACLE intrinsic. */ + +/* { dg-do assemble } */ +/* { dg-require-effective-target arm_crc_ok } */ +/* { dg-options "-save-temps -O0" } */ +/* { dg-add-options arm_crc } */ + +#include "arm_acle.h" + +void test_crc32b (void) +{ + uint32_t out_uint32_t; + uint32_t arg0_uint32_t; + uint8_t arg1_uint8_t; + + out_uint32_t = __crc32b (arg0_uint32_t, arg1_uint8_t); +} + +/* { dg-final { scan-assembler "crc32b\t...?, ...?, ...?\n" } } */ +/* { dg-final { cleanup-saved-temps } } */ diff --git a/gcc/testsuite/gcc.target/arm/acle/crc32cb.c b/gcc/testsuite/gcc.target/arm/acle/crc32cb.c new file mode 100644 index 0000000..44aea21 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/acle/crc32cb.c @@ -0,0 +1,20 @@ +/* Test the crc32cb ACLE intrinsic. */ + +/* { dg-do assemble } */ +/* { dg-require-effective-target arm_crc_ok } */ +/* { dg-options "-save-temps -O0" } */ +/* { dg-add-options arm_crc } */ + +#include "arm_acle.h" + +void test_crc32cb (void) +{ + uint32_t out_uint32_t; + uint32_t arg0_uint32_t; + uint8_t arg1_uint8_t; + + out_uint32_t = __crc32cb (arg0_uint32_t, arg1_uint8_t); +} + +/* { dg-final { scan-assembler "crc32cb\t...?, ...?, ...?\n" } } */ +/* { dg-final { cleanup-saved-temps } } */ diff --git a/gcc/testsuite/gcc.target/arm/acle/crc32cd.c b/gcc/testsuite/gcc.target/arm/acle/crc32cd.c new file mode 100644 index 0000000..cb7ee0d --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/acle/crc32cd.c @@ -0,0 +1,20 @@ +/* Test the crc32cd ACLE intrinsic. */ + +/* { dg-do assemble } */ +/* { dg-require-effective-target arm_crc_ok } */ +/* { dg-options "-save-temps -O0" } */ +/* { dg-add-options arm_crc } */ + +#include "arm_acle.h" + +void test_crc32cd (void) +{ + uint32_t out_uint32_t; + uint32_t arg0_uint32_t; + uint64_t arg1_uint64_t; + + out_uint32_t = __crc32cd (arg0_uint32_t, arg1_uint64_t); +} + +/* { dg-final { scan-assembler-times "crc32cw\t...?, ...?, ...?\n" 2 } } */ +/* { dg-final { cleanup-saved-temps } } */ diff --git a/gcc/testsuite/gcc.target/arm/acle/crc32ch.c b/gcc/testsuite/gcc.target/arm/acle/crc32ch.c new file mode 100644 index 0000000..d8e7338 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/acle/crc32ch.c @@ -0,0 +1,20 @@ +/* Test the crc32ch ACLE intrinsic. */ + +/* { dg-do assemble } */ +/* { dg-require-effective-target arm_crc_ok } */ +/* { dg-options "-save-temps -O0" } */ +/* { dg-add-options arm_crc } */ + +#include "arm_acle.h" + +void test_crc32ch (void) +{ + uint32_t out_uint32_t; + uint32_t arg0_uint32_t; + uint16_t arg1_uint16_t; + + out_uint32_t = __crc32ch (arg0_uint32_t, arg1_uint16_t); +} + +/* { dg-final { scan-assembler "crc32ch\t...?, ...?, ...?\n" } } */ +/* { dg-final { cleanup-saved-temps } } */ diff --git a/gcc/testsuite/gcc.target/arm/acle/crc32cw.c b/gcc/testsuite/gcc.target/arm/acle/crc32cw.c new file mode 100644 index 0000000..84384c5 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/acle/crc32cw.c @@ -0,0 +1,20 @@ +/* Test the crc32cw ACLE intrinsic. */ + +/* { dg-do assemble } */ +/* { dg-require-effective-target arm_crc_ok } */ +/* { dg-options "-save-temps -O0" } */ +/* { dg-add-options arm_crc } */ + +#include "arm_acle.h" + +void test_crc32cw (void) +{ + uint32_t out_uint32_t; + uint32_t arg0_uint32_t; + uint32_t arg1_uint32_t; + + out_uint32_t = __crc32cw (arg0_uint32_t, arg1_uint32_t); +} + +/* { dg-final { scan-assembler "crc32cw\t...?, ...?, ...?\n" } } */ +/* { dg-final { cleanup-saved-temps } } */ diff --git a/gcc/testsuite/gcc.target/arm/acle/crc32d.c b/gcc/testsuite/gcc.target/arm/acle/crc32d.c new file mode 100644 index 0000000..c90fad9 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/acle/crc32d.c @@ -0,0 +1,20 @@ +/* Test the crc32d ACLE intrinsic. */ + +/* { dg-do assemble } */ +/* { dg-require-effective-target arm_crc_ok } */ +/* { dg-options "-save-temps -O0" } */ +/* { dg-add-options arm_crc } */ + +#include "arm_acle.h" + +void test_crc32d (void) +{ + uint32_t out_uint32_t; + uint32_t arg0_uint32_t; + uint64_t arg1_uint64_t; + + out_uint32_t = __crc32d (arg0_uint32_t, arg1_uint64_t); +} + +/* { dg-final { scan-assembler-times "crc32w\t...?, ...?, ...?\n" 2 } } */ +/* { dg-final { cleanup-saved-temps } } */ diff --git a/gcc/testsuite/gcc.target/arm/acle/crc32h.c b/gcc/testsuite/gcc.target/arm/acle/crc32h.c new file mode 100644 index 0000000..c21a4ae --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/acle/crc32h.c @@ -0,0 +1,20 @@ +/* Test the crc32h ACLE intrinsic. */ + +/* { dg-do assemble } */ +/* { dg-require-effective-target arm_crc_ok } */ +/* { dg-options "-save-temps -O0" } */ +/* { dg-add-options arm_crc } */ + +#include "arm_acle.h" + +void test_crc32h (void) +{ + uint32_t out_uint32_t; + uint32_t arg0_uint32_t; + uint16_t arg1_uint16_t; + + out_uint32_t = __crc32h (arg0_uint32_t, arg1_uint16_t); +} + +/* { dg-final { scan-assembler "crc32h\t...?, ...?, ...?\n" } } */ +/* { dg-final { cleanup-saved-temps } } */ diff --git a/gcc/testsuite/gcc.target/arm/acle/crc32w.c b/gcc/testsuite/gcc.target/arm/acle/crc32w.c new file mode 100644 index 0000000..60cd09e4 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/acle/crc32w.c @@ -0,0 +1,20 @@ +/* Test the crc32w ACLE intrinsic. */ + +/* { dg-do assemble } */ +/* { dg-require-effective-target arm_crc_ok } */ +/* { dg-options "-save-temps -O0" } */ +/* { dg-add-options arm_crc } */ + +#include "arm_acle.h" + +void test_crc32w (void) +{ + uint32_t out_uint32_t; + uint32_t arg0_uint32_t; + uint32_t arg1_uint32_t; + + out_uint32_t = __crc32w (arg0_uint32_t, arg1_uint32_t); +} + +/* { dg-final { scan-assembler "crc32w\t...?, ...?, ...?\n" } } */ +/* { dg-final { cleanup-saved-temps } } */ diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 104818d..a256b12 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -2300,6 +2300,14 @@ proc add_options_for_arm_v8_neon { flags } { return "$flags $et_arm_v8_neon_flags -march=armv8-a" } +proc add_options_for_arm_crc { flags } { + if { ! [check_effective_target_arm_crc_ok] } { + return "$flags" + } + global et_arm_crc_flags + return "$flags $et_arm_crc_flags" +} + # Add the options needed for NEON. We need either -mfloat-abi=softfp # or -mfloat-abi=hard, but if one is already specified by the # multilib, use it. Similarly, if a -mfpu option already enables @@ -2341,6 +2349,21 @@ proc check_effective_target_arm_neon_ok { } { check_effective_target_arm_neon_ok_nocache] } +proc check_effective_target_arm_crc_ok_nocache { } { + global et_arm_crc_flags + set et_arm_crc_flags "-march=armv8-a+crc" + return [check_no_compiler_messages_nocache arm_crc_ok object { + #if !defined (__ARM_FEATURE_CRC32) + #error FOO + #endif + } "$et_arm_crc_flags"] +} + +proc check_effective_target_arm_crc_ok { } { + return [check_cached_effective_target arm_crc_ok \ + check_effective_target_arm_crc_ok_nocache] +} + # Return 1 if this is an ARM target supporting -mfpu=neon-fp16 # -mfloat-abi=softfp or equivalent options. Some multilibs may be # incompatible with these options. Also set et_arm_neon_flags to the