This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][AArch64][1/2] Implement CRC32 ACLE intrinsics


Hi all,

This is an implementation of the ACLE intrinsics that can be used to access the CRC32 instructions. We have them already implemented in aarch32.

You can find their definition and documentation at
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0053c/IHI0053C_acle_2_0.pdf

The CRC32 intrinsics are non-AdvancedSIMD intrinsics that live in a header file called arm_acle.h There's only 8 of them, so I didn't create a separate .def file for them. The ACLE predefine "__ARM_FEATURE_CRC32" is now defined when the +crc arch extension is used. Builtins for each CRC instruction form are defined and the intrinsics map to them straightforwardly.

Documentation is included.

Bootstrapped and tested aarch64-none-linux-gnu.

Ok for trunk?

Thanks,
Kyrill

2014-06-10  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>

    * config.gcc (aarch64*-*-*): Add arm_acle.h to extra headers.
    * Makefile.in (TEXI_GCC_FILES): Add aarch64-acle-intrinsics.texi to
    dependencies.
    * config/aarch64/aarch64-builtins.c (AARCH64_CRC32_BUILTINS): Define.
    (aarch64_crc_builtin_datum): New struct.
    (aarch64_crc_builtin_data): New.
    (aarch64_init_crc32_builtins): New function.
    (aarch64_init_builtins): Initialise CRC32 builtins when appropriate.
    (aarch64_crc32_expand_builtin): New.
    (aarch64_expand_builtin): Add CRC32 builtin expansion case.
    * config/aarch64/aarch64.h (TARGET_CPU_CPP_BUILTINS): Define
    __ARM_FEATURE_CRC32 when appropriate.
    (TARGET_CRC32): Define.
    * config/aarch64/aarch64.md (UNSPEC_CRC32B, UNSPEC_CRC32H,
    UNSPEC_CRC32W, UNSPEC_CRC32X, UNSPEC_CRC32CB, UNSPEC_CRC32CH,
    UNSPEC_CRC32CW, UNSPEC_CRC32CX): New unspec values.
    (aarch64_<crc_variant>): New pattern.
    * config/aarch64/arm_acle.h: New file.
    * config/aarch64/iterators.md (CRC): New int iterator.
    (crc_variant, crc_mode): New int attributes.
    * doc/aarch64-acle-intrinsics.texi: New file.
    * doc/extend.texi (aarch64): Document aarch64 ACLE intrinsics.
    Include aarch64-acle-intrinsics.texi.
commit e686eaa8ac08683969e53c4c0eb4e912e0a46d54
Author: Kyrylo Tkachov <kyrylo.tkachov@arm.com>
Date:   Fri May 16 15:38:03 2014 +0100

    [AArch64] Implement CRC32 ACLE intrinsics

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 3350186..a6fba33 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -2801,7 +2801,7 @@ TEXI_GCC_FILES = gcc.texi gcc-common.texi gcc-vers.texi frontends.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	\
-	 arm-acle-intrinsics.texi
+	 arm-acle-intrinsics.texi aarch64-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 c3f3ea6..80bb3db 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -302,7 +302,7 @@ m32c*-*-*)
         ;;
 aarch64*-*-*)
 	cpu_type=aarch64
-	extra_headers="arm_neon.h"
+	extra_headers="arm_neon.h arm_acle.h"
 	extra_objs="aarch64-builtins.o aarch-common.o"
 	target_has_targetm_common=yes
 	;;
diff --git a/gcc/config/aarch64/aarch64-builtins.c b/gcc/config/aarch64/aarch64-builtins.c
index fe4d392..a94ef52 100644
--- a/gcc/config/aarch64/aarch64-builtins.c
+++ b/gcc/config/aarch64/aarch64-builtins.c
@@ -411,6 +411,28 @@ static aarch64_simd_builtin_datum aarch64_simd_builtin_data[] = {
 #include "aarch64-simd-builtins.def"
 };
 
+/* There's only 8 CRC32 builtins.  Probably not worth their own .def file.  */
+#define AARCH64_CRC32_BUILTINS \
+  CRC32_BUILTIN (crc32b, QI) \
+  CRC32_BUILTIN (crc32h, HI) \
+  CRC32_BUILTIN (crc32w, SI) \
+  CRC32_BUILTIN (crc32x, DI) \
+  CRC32_BUILTIN (crc32cb, QI) \
+  CRC32_BUILTIN (crc32ch, HI) \
+  CRC32_BUILTIN (crc32cw, SI) \
+  CRC32_BUILTIN (crc32cx, DI)
+
+typedef struct
+{
+  const char *name;
+  enum machine_mode mode;
+  const enum insn_code icode;
+  unsigned int fcode;
+} aarch64_crc_builtin_datum;
+
+#define CRC32_BUILTIN(N, M) \
+  AARCH64_BUILTIN_##N,
+
 #undef VAR1
 #define VAR1(T, N, MAP, A) \
   AARCH64_SIMD_BUILTIN_##T##_##N##A,
@@ -428,9 +450,22 @@ enum aarch64_builtins
 #include "aarch64-simd-builtins.def"
   AARCH64_SIMD_BUILTIN_MAX = AARCH64_SIMD_BUILTIN_BASE
 			      + ARRAY_SIZE (aarch64_simd_builtin_data),
+  AARCH64_CRC32_BUILTIN_BASE,
+  AARCH64_CRC32_BUILTINS
+  AARCH64_CRC32_BUILTIN_MAX,
   AARCH64_BUILTIN_MAX
 };
 
+#undef CRC32_BUILTIN
+#define CRC32_BUILTIN(N, M) \
+  {"__builtin_aarch64_"#N, M##mode, CODE_FOR_aarch64_##N, AARCH64_BUILTIN_##N},
+
+static aarch64_crc_builtin_datum aarch64_crc_builtin_data[] = {
+  AARCH64_CRC32_BUILTINS
+};
+
+#undef CRC32_BUILTIN
+
 static GTY(()) tree aarch64_builtin_decls[AARCH64_BUILTIN_MAX];
 
 #define NUM_DREG_TYPES 6
@@ -802,6 +837,24 @@ aarch64_init_simd_builtins (void)
     }
 }
 
+static void
+aarch64_init_crc32_builtins ()
+{
+  tree usi_type = aarch64_build_unsigned_type (SImode);
+  unsigned int i = 0;
+
+  for (i = 0; i < ARRAY_SIZE (aarch64_crc_builtin_data); ++i)
+    {
+      aarch64_crc_builtin_datum* d = &aarch64_crc_builtin_data[i];
+      tree argtype = aarch64_build_unsigned_type (d->mode);
+      tree ftype = build_function_type_list (usi_type, usi_type, argtype, NULL_TREE);
+      tree fndecl = add_builtin_function (d->name, ftype, d->fcode,
+                                          BUILT_IN_MD, NULL, NULL_TREE);
+
+      aarch64_builtin_decls[d->fcode] = fndecl;
+    }
+}
+
 void
 aarch64_init_builtins (void)
 {
@@ -825,6 +878,8 @@ aarch64_init_builtins (void)
 
   if (TARGET_SIMD)
     aarch64_init_simd_builtins ();
+  if (TARGET_CRC32)
+    aarch64_init_crc32_builtins ();
 }
 
 tree
@@ -1024,6 +1079,41 @@ aarch64_simd_expand_builtin (int fcode, tree exp, rtx target)
 	   SIMD_ARG_STOP);
 }
 
+rtx
+aarch64_crc32_expand_builtin (int fcode, tree exp, rtx target)
+{
+  rtx pat;
+  aarch64_crc_builtin_datum *d
+    = &aarch64_crc_builtin_data[fcode - (AARCH64_CRC32_BUILTIN_BASE + 1)];
+  enum insn_code icode = d->icode;
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  tree arg1 = CALL_EXPR_ARG (exp, 1);
+  rtx op0 = expand_normal (arg0);
+  rtx op1 = expand_normal (arg1);
+  enum machine_mode tmode = insn_data[icode].operand[0].mode;
+  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
+
+  if (! target
+      || GET_MODE (target) != tmode
+      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+    target = gen_reg_rtx (tmode);
+
+  gcc_assert ((GET_MODE (op0) == mode0 || GET_MODE (op0) == VOIDmode)
+	      && (GET_MODE (op1) == mode1 || GET_MODE (op1) == VOIDmode));
+
+  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+    op0 = copy_to_mode_reg (mode0, op0);
+  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
+    op1 = copy_to_mode_reg (mode1, op1);
+
+  pat = GEN_FCN (icode) (target, op0, op1);
+  if (! pat)
+    return 0;
+  emit_insn (pat);
+  return target;
+}
+
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient.  */
 rtx
@@ -1066,8 +1156,10 @@ aarch64_expand_builtin (tree exp,
       return target;
     }
 
-  if (fcode >= AARCH64_SIMD_BUILTIN_BASE)
+  if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
     return aarch64_simd_expand_builtin (fcode, exp, target);
+  else if (fcode >= AARCH64_CRC32_BUILTIN_BASE && fcode <= AARCH64_CRC32_BUILTIN_MAX)
+    return aarch64_crc32_expand_builtin (fcode, exp, target);
 
   return NULL_RTX;
 }
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index a191162..b95365a 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -35,6 +35,9 @@
       if (TARGET_SIMD)					\
 	builtin_define ("__ARM_NEON");			\
 							\
+      if (TARGET_CRC32)				\
+	builtin_define ("__ARM_FEATURE_CRC32");		\
+							\
       switch (aarch64_cmodel)				\
 	{						\
 	  case AARCH64_CMODEL_TINY:			\
@@ -188,6 +191,9 @@ extern unsigned long aarch64_tune_flags;
 /* Crypto is an optional extension to AdvSIMD.  */
 #define TARGET_CRYPTO (TARGET_SIMD && AARCH64_ISA_CRYPTO)
 
+/* CRC instructions that can be enabled through +crc arch extension.  */
+#define TARGET_CRC32 (AARCH64_ISA_CRC)
+
 /* Standard register usage.  */
 
 /* 31 64-bit general purpose registers R0-R30:
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 661d784..0564017 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -68,6 +68,14 @@
 (define_c_enum "unspec" [
     UNSPEC_CASESI
     UNSPEC_CLS
+    UNSPEC_CRC32B
+    UNSPEC_CRC32CB
+    UNSPEC_CRC32CH
+    UNSPEC_CRC32CW
+    UNSPEC_CRC32CX
+    UNSPEC_CRC32H
+    UNSPEC_CRC32W
+    UNSPEC_CRC32X
     UNSPEC_FRECPE
     UNSPEC_FRECPS
     UNSPEC_FRECPX
@@ -2481,6 +2489,23 @@
   }
 )
 
+
+;; CRC32 instructions.
+(define_insn "aarch64_<crc_variant>"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (unspec:SI [(match_operand:SI 1 "register_operand" "r")
+                    (match_operand:<crc_mode> 2 "register_operand" "r")]
+         CRC))]
+  "TARGET_CRC32"
+  {
+    if (GET_MODE_BITSIZE (GET_MODE (operands[2])) >= 64)
+      return "<crc_variant>\\t%w0, %w1, %x2";
+    else
+      return "<crc_variant>\\t%w0, %w1, %w2";
+  }
+  [(set_attr "type" "crc")]
+)
+
 (define_insn "*csinc2<mode>_insn"
   [(set (match_operand:GPI 0 "register_operand" "=r")
         (plus:GPI (match_operator:GPI 2 "aarch64_comparison_operator"
diff --git a/gcc/config/aarch64/arm_acle.h b/gcc/config/aarch64/arm_acle.h
new file mode 100644
index 0000000..2e74696
--- /dev/null
+++ b/gcc/config/aarch64/arm_acle.h
@@ -0,0 +1,90 @@
+/* AArch64 Non-NEON ACLE intrinsics include file.
+
+   Copyright (C) 2014 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_aarch64_crc32b (__a, __b);
+}
+
+__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
+__crc32cb (uint32_t __a, uint8_t __b)
+{
+  return __builtin_aarch64_crc32cb (__a, __b);
+}
+
+__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
+__crc32ch (uint32_t __a, uint16_t __b)
+{
+  return __builtin_aarch64_crc32ch (__a, __b);
+}
+
+__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
+__crc32cw (uint32_t __a, uint32_t __b)
+{
+  return __builtin_aarch64_crc32cw (__a, __b);
+}
+
+__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
+__crc32cd (uint32_t __a, uint64_t __b)
+{
+  return __builtin_aarch64_crc32cx (__a, __b);
+}
+
+__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
+__crc32h (uint32_t __a, uint16_t __b)
+{
+  return __builtin_aarch64_crc32h (__a, __b);
+}
+
+__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
+__crc32w (uint32_t __a, uint32_t __b)
+{
+  return __builtin_aarch64_crc32w (__a, __b);
+}
+
+__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
+__crc32d (uint32_t __a, uint64_t __b)
+{
+  return __builtin_aarch64_crc32x (__a, __b);
+}
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index 05c4f7e..bf7b683 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -910,6 +910,10 @@
 
 (define_int_iterator FRECP [UNSPEC_FRECPE UNSPEC_FRECPX])
 
+(define_int_iterator CRC [UNSPEC_CRC32B UNSPEC_CRC32H UNSPEC_CRC32W
+                          UNSPEC_CRC32X UNSPEC_CRC32CB UNSPEC_CRC32CH
+                          UNSPEC_CRC32CW UNSPEC_CRC32CX])
+
 (define_int_iterator CRYPTO_AES [UNSPEC_AESE UNSPEC_AESD])
 (define_int_iterator CRYPTO_AESMC [UNSPEC_AESMC UNSPEC_AESIMC])
 
@@ -1038,6 +1042,16 @@
 
 (define_int_attr frecp_suffix  [(UNSPEC_FRECPE "e") (UNSPEC_FRECPX "x")])
 
+(define_int_attr crc_variant [(UNSPEC_CRC32B "crc32b") (UNSPEC_CRC32H "crc32h")
+                        (UNSPEC_CRC32W "crc32w") (UNSPEC_CRC32X "crc32x")
+                        (UNSPEC_CRC32CB "crc32cb") (UNSPEC_CRC32CH "crc32ch")
+                        (UNSPEC_CRC32CW "crc32cw") (UNSPEC_CRC32CX "crc32cx")])
+
+(define_int_attr crc_mode [(UNSPEC_CRC32B "QI") (UNSPEC_CRC32H "HI")
+                        (UNSPEC_CRC32W "SI") (UNSPEC_CRC32X "DI")
+                        (UNSPEC_CRC32CB "QI") (UNSPEC_CRC32CH "HI")
+                        (UNSPEC_CRC32CW "SI") (UNSPEC_CRC32CX "DI")])
+
 (define_int_attr aes_op [(UNSPEC_AESE "e") (UNSPEC_AESD "d")])
 (define_int_attr aesmc_op [(UNSPEC_AESMC "mc") (UNSPEC_AESIMC "imc")])
 
diff --git a/gcc/doc/aarch64-acle-intrinsics.texi b/gcc/doc/aarch64-acle-intrinsics.texi
new file mode 100644
index 0000000..3194511
--- /dev/null
+++ b/gcc/doc/aarch64-acle-intrinsics.texi
@@ -0,0 +1,55 @@
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c This is part of the GCC manual.
+@c For copying conditions, see the file gcc.texi.
+
+@subsubsection CRC32 intrinsics
+
+These intrinsics are available when the CRC32 architecture extension is
+specified, e.g. when the @option{-march=armv8-a+crc} switch is used, or when
+the target processor specified with @option{-mcpu} supports it.
+
+@itemize @bullet
+@item uint32_t __crc32b (uint32_t, uint8_t)
+@*@emph{Form of expected instruction(s):} @code{crc32b @var{w0}, @var{w1}, @var{w2}}
+@end itemize
+
+
+@itemize @bullet
+@item uint32_t __crc32h (uint32_t, uint16_t)
+@*@emph{Form of expected instruction(s):} @code{crc32h @var{w0}, @var{w1}, @var{w2}}
+@end itemize
+
+
+@itemize @bullet
+@item uint32_t __crc32w (uint32_t, uint32_t)
+@*@emph{Form of expected instruction(s):} @code{crc32w @var{w0}, @var{w1}, @var{w2}}
+@end itemize
+
+
+@itemize @bullet
+@item uint32_t __crc32d (uint32_t, uint64_t)
+@*@emph{Form of expected instruction(s):} @code{crc32x @var{w0}, @var{w1}, @var{x2}}
+@end itemize
+
+@itemize @bullet
+@item uint32_t __crc32cb (uint32_t, uint8_t)
+@*@emph{Form of expected instruction(s):} @code{crc32cb @var{w0}, @var{w1}, @var{w2}}
+@end itemize
+
+
+@itemize @bullet
+@item uint32_t __crc32ch (uint32_t, uint16_t)
+@*@emph{Form of expected instruction(s):} @code{crc32ch @var{w0}, @var{w1}, @var{w2}}
+@end itemize
+
+
+@itemize @bullet
+@item uint32_t __crc32cw (uint32_t, uint32_t)
+@*@emph{Form of expected instruction(s):} @code{crc32cw @var{w0}, @var{w1}, @var{w2}}
+@end itemize
+
+
+@itemize @bullet
+@item uint32_t __crc32cd (uint32_t, uint64_t)
+@*@emph{Form of expected instruction(s):} @code{crc32cx @var{w0}, @var{w1}, @var{x2}}
+@end itemize
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 42db985..6f78bc9 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -9697,6 +9697,7 @@ instructions, but allow the compiler to schedule those calls.
 
 @menu
 * AArch64 Built-in Functions::
+* AArch64 intrinsics::
 * Alpha Built-in Functions::
 * Altera Nios II Built-in Functions::
 * ARC Built-in Functions::
@@ -9742,6 +9743,11 @@ unsigned int __builtin_aarch64_get_fpsr ()
 void __builtin_aarch64_set_fpsr (unsigned int)
 @end smallexample
 
+@node AArch64 intrinsics
+@subsection ACLE Intrinsics for AArch64
+
+@include aarch64-acle-intrinsics.texi
+
 @node Alpha Built-in Functions
 @subsection Alpha Built-in Functions
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]