diff mbox

[5/6,ARM] Implement support for ACLE Coprocessor MCR and MRC intrinsics

Message ID 5822F68D.3050006@arm.com
State New
Headers show

Commit Message

Andre Vieira (lists) Nov. 9, 2016, 10:12 a.m. UTC
Hi,

This patch implements support for the ARM ACLE Coprocessor MCR and MRC
intrinsics. See below a table mapping the intrinsics to their respective
instructions:

+-------------------------------------------------------------------+---------------------------------------+
| Intrinsic signature                                               |
Instruction pattern                   |
+-------------------------------------------------------------------+---------------------------------------+
|void __arm_mcr(coproc, opc1, uint32_t value, CRn, CRm, opc2)       |
MCR coproc, opc1, Rt, CRn, CRm, opc2  |
+-------------------------------------------------------------------+---------------------------------------+
|void __arm_mcr2(coproc, opc1, uint32_t value, CRn, CRm, opc2)      |
MCR2 coproc, opc1, Rt, CRn, CRm, opc2 |
+-------------------------------------------------------------------+---------------------------------------+
|uint32_t __arm_mrc(coproc, opc1, CRn, CRm, opc2)                   |
MRC coproc, opc1, Rt, CRn, CRm, opc2  |
+-------------------------------------------------------------------+---------------------------------------+
|uint32_t __arm_mrc2(coproc, opc1, CRn, CRm, opc2)                  |
MRC2 coproc, opc1, Rt, CRn, CRm, opc2 |
+-------------------------------------------------------------------+---------------------------------------+
Note that any untyped variable in the intrinsic signature is required to
be a compiler-time constant and has the type 'unsigned int'.  We do some
boundary checks for coproc:[0-15], opc1[0-7] CR*:[0-31],opc2:[0-7].  If
either of these requirements are not met a diagnostic is issued.

Is this OK for trunk?

Regards,
Andre

gcc/ChangeLog:
2016-11-09  Andre Vieira  <andre.simoesdiasvieira@arm.com>

  * config/arm/arm.md (<mcr>): New.
  (<mrc>): New.
  * config/arm/arm.c (arm_coproc_builtin_available): Add
  support for mcr, mrc, mcr2 and mrc2.
  * config/arm/arm-builtins.c (MCR_QUALIFIERS): Define to...
  (arm_mcr_qualifiers): ... this. New.
  (MRC_QUALIFIERS): Define to ...
  (arm_mrc_qualifiers): ... this. New.
  (MCR_QUALIFIERS): Define to ...
  (arm_mcr_qualifiers): ... this. New.
  * config/arm/arm_acle.h (__arm_mcr, __arm_mrc, __arm_mcr2,
  __arm_mrc2): New.
  * config/arm/arm_acle_builtins.def (mcr, mcr2, mrc, mrc2): New.
  * config/arm/iterators.md (MCRI, mcr, MCR, MRCI, mrc, MRC): New.
  * config/arm/unspecs.md (VUNSPEC_MCR, VUNSPEC_MCR2, VUNSPEC_MRC,
  VUNSPEC_MRC2): New.


gcc/ChangeLog:
2016-11-09  Andre Vieira  <andre.simoesdiasvieira@arm.com>

  * gcc.target/arm/acle/mcr.c: New.
  * gcc.target/arm/acle/mrc.c: New.
  * gcc.target/arm/acle/mcr2.c: New.
  * gcc.target/arm/acle/mrc2.c: New.

Comments

Kyrill Tkachov Jan. 5, 2017, 11:08 a.m. UTC | #1
On 09/11/16 10:12, Andre Vieira (lists) wrote:
> Hi,
>
> This patch implements support for the ARM ACLE Coprocessor MCR and MRC
> intrinsics. See below a table mapping the intrinsics to their respective
> instructions:
>
> +-------------------------------------------------------------------+---------------------------------------+
> | Intrinsic signature                                               |
> Instruction pattern                   |
> +-------------------------------------------------------------------+---------------------------------------+
> |void __arm_mcr(coproc, opc1, uint32_t value, CRn, CRm, opc2)       |
> MCR coproc, opc1, Rt, CRn, CRm, opc2  |
> +-------------------------------------------------------------------+---------------------------------------+
> |void __arm_mcr2(coproc, opc1, uint32_t value, CRn, CRm, opc2)      |
> MCR2 coproc, opc1, Rt, CRn, CRm, opc2 |
> +-------------------------------------------------------------------+---------------------------------------+
> |uint32_t __arm_mrc(coproc, opc1, CRn, CRm, opc2)                   |
> MRC coproc, opc1, Rt, CRn, CRm, opc2  |
> +-------------------------------------------------------------------+---------------------------------------+
> |uint32_t __arm_mrc2(coproc, opc1, CRn, CRm, opc2)                  |
> MRC2 coproc, opc1, Rt, CRn, CRm, opc2 |
> +-------------------------------------------------------------------+---------------------------------------+
> Note that any untyped variable in the intrinsic signature is required to
> be a compiler-time constant and has the type 'unsigned int'.  We do some
> boundary checks for coproc:[0-15], opc1[0-7] CR*:[0-31],opc2:[0-7].  If
> either of these requirements are not met a diagnostic is issued.
>
> Is this OK for trunk?
>
> Regards,
> Andre
>
> gcc/ChangeLog:
> 2016-11-09  Andre Vieira  <andre.simoesdiasvieira@arm.com>
>
>    * config/arm/arm.md (<mcr>): New.
>    (<mrc>): New.
>    * config/arm/arm.c (arm_coproc_builtin_available): Add
>    support for mcr, mrc, mcr2 and mrc2.
>    * config/arm/arm-builtins.c (MCR_QUALIFIERS): Define to...
>    (arm_mcr_qualifiers): ... this. New.
>    (MRC_QUALIFIERS): Define to ...
>    (arm_mrc_qualifiers): ... this. New.
>    (MCR_QUALIFIERS): Define to ...
>    (arm_mcr_qualifiers): ... this. New.
>    * config/arm/arm_acle.h (__arm_mcr, __arm_mrc, __arm_mcr2,
>    __arm_mrc2): New.
>    * config/arm/arm_acle_builtins.def (mcr, mcr2, mrc, mrc2): New.
>    * config/arm/iterators.md (MCRI, mcr, MCR, MRCI, mrc, MRC): New.
>    * config/arm/unspecs.md (VUNSPEC_MCR, VUNSPEC_MCR2, VUNSPEC_MRC,
>    VUNSPEC_MRC2): New.
>
>
> gcc/ChangeLog:
> 2016-11-09  Andre Vieira  <andre.simoesdiasvieira@arm.com>
>
>    * gcc.target/arm/acle/mcr.c: New.
>    * gcc.target/arm/acle/mrc.c: New.
>    * gcc.target/arm/acle/mcr2.c: New.
>    * gcc.target/arm/acle/mrc2.c: New.

+(define_insn "<mcr>"
+  [(unspec_volatile [(match_operand:SI 0 "immediate_operand")
+		     (match_operand:SI 1 "immediate_operand")
+		     (match_operand:SI 2 "s_register_operand")
+		     (match_operand:SI 3 "immediate_operand")
+		     (match_operand:SI 4 "immediate_operand")
+		     (match_operand:SI 5 "immediate_operand")] MCRI)
+   (use (match_dup 2))]
+  "arm_coproc_builtin_available (VUNSPEC_<MCR>)"
+{
+  arm_const_bounds (operands[0], 0, 16);
+  arm_const_bounds (operands[1], 0, 8);
+  arm_const_bounds (operands[3], 0, (1 << 5));
+  arm_const_bounds (operands[4], 0, (1 << 5));
+  arm_const_bounds (operands[5], 0, 8);
+  return "<mcr>\\tp%c0, %1, %2, CR%c3, CR%c4, %5";
+}
+  [(set_attr "length" "4")
+   (set_attr "type" "coproc")])
+
+(define_insn "<mrc>"
+  [(set (match_operand:SI 0 "s_register_operand")
+	(unspec_volatile [(match_operand:SI 1 "immediate_operand")
+			  (match_operand:SI 2 "immediate_operand")
+			  (match_operand:SI 3 "immediate_operand")
+			  (match_operand:SI 4 "immediate_operand")
+			  (match_operand:SI 5 "immediate_operand")] MRCI))]
+  "arm_coproc_builtin_available (VUNSPEC_<MRC>)"
+{
+  arm_const_bounds (operands[1], 0, 16);
+  arm_const_bounds (operands[2], 0, 8);
+  arm_const_bounds (operands[3], 0, (1 << 5));
+  arm_const_bounds (operands[4], 0, (1 << 5));
+  arm_const_bounds (operands[5], 0, 8);
+  return "<mrc>\\tp%c1, %2, %0, CR%c3, CR%c4, %5";
+}
+  [(set_attr "length" "4")
+   (set_attr "type" "coproc")])

Same as the previous patch, these operands need constraints.
The MRC ones in particular need a '=' in their constraint string.
diff mbox

Patch

diff --git a/gcc/config/arm/arm-builtins.c b/gcc/config/arm/arm-builtins.c
index e6e58cd6a656732e37c6bca23ad980eea522a710..44f255356dcc3ea6b8f554ba96f99fd7856bf6a1 100644
--- a/gcc/config/arm/arm-builtins.c
+++ b/gcc/config/arm/arm-builtins.c
@@ -196,6 +196,26 @@  arm_stc_qualifiers[SIMD_MAX_BUILTIN_ARGS]
 #define STC_QUALIFIERS \
   (arm_stc_qualifiers)
 
+/* void (unsigned immediate, unsigned immediate,  T, unsigned immediate,
+	 unsigned immediate, unsigned immediate).  */
+static enum arm_type_qualifiers
+arm_mcr_qualifiers[SIMD_MAX_BUILTIN_ARGS]
+  = { qualifier_void, qualifier_unsigned_immediate,
+      qualifier_unsigned_immediate, qualifier_none,
+      qualifier_unsigned_immediate, qualifier_unsigned_immediate,
+      qualifier_unsigned_immediate };
+#define MCR_QUALIFIERS \
+  (arm_mcr_qualifiers)
+
+/* T (unsigned immediate, unsigned immediate, unsigned immediate,
+      unsigned immediate, unsigned immediate).  */
+static enum arm_type_qualifiers
+arm_mrc_qualifiers[SIMD_MAX_BUILTIN_ARGS]
+  = { qualifier_none, qualifier_unsigned_immediate,
+      qualifier_unsigned_immediate, qualifier_unsigned_immediate,
+      qualifier_unsigned_immediate, qualifier_unsigned_immediate };
+#define MRC_QUALIFIERS \
+  (arm_mrc_qualifiers)
 /* The first argument (return type) of a store should be void type,
    which we represent with qualifier_void.  Their first operand will be
    a DImode pointer to the location to store to, so we must use
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index d3191abee163d5fbf753fb5072be50fdb2b4c785..25439a343e8540c5fca5cbe19e8b76e2fdb97a73 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -30803,6 +30803,8 @@  bool arm_coproc_builtin_available (enum unspecv builtin)
       case VUNSPEC_LDCL:
       case VUNSPEC_STC:
       case VUNSPEC_STCL:
+      case VUNSPEC_MCR:
+      case VUNSPEC_MRC:
 	if (arm_arch4)
 	  return true;
 	break;
@@ -30811,6 +30813,8 @@  bool arm_coproc_builtin_available (enum unspecv builtin)
       case VUNSPEC_LDC2L:
       case VUNSPEC_STC2:
       case VUNSPEC_STC2L:
+      case VUNSPEC_MCR2:
+      case VUNSPEC_MRC2:
 	/* Only present in ARMv5*, ARMv6 (but not ARMv6-M), ARMv7* and
 	   ARMv8-{A,M}.  */
 	if (arm_arch5)
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 45cdd576fa5b7f26e2d1cfa2c86a8c8767537e54..b74d0519f0c218167192bedeaa493468e301943b 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -11877,6 +11877,45 @@ 
 		     (mem:SI (match_operand:SI 2 "s_register_operand"))] LDCSTCI)]
   "arm_coproc_builtin_available (VUNSPEC_<LDCSTC>)")
 
+(define_insn "<mcr>"
+  [(unspec_volatile [(match_operand:SI 0 "immediate_operand")
+		     (match_operand:SI 1 "immediate_operand")
+		     (match_operand:SI 2 "s_register_operand")
+		     (match_operand:SI 3 "immediate_operand")
+		     (match_operand:SI 4 "immediate_operand")
+		     (match_operand:SI 5 "immediate_operand")] MCRI)
+   (use (match_dup 2))]
+  "arm_coproc_builtin_available (VUNSPEC_<MCR>)"
+{
+  arm_const_bounds (operands[0], 0, 16);
+  arm_const_bounds (operands[1], 0, 8);
+  arm_const_bounds (operands[3], 0, (1 << 5));
+  arm_const_bounds (operands[4], 0, (1 << 5));
+  arm_const_bounds (operands[5], 0, 8);
+  return "<mcr>\\tp%c0, %1, %2, CR%c3, CR%c4, %5";
+}
+  [(set_attr "length" "4")
+   (set_attr "type" "coproc")])
+
+(define_insn "<mrc>"
+  [(set (match_operand:SI 0 "s_register_operand")
+	(unspec_volatile [(match_operand:SI 1 "immediate_operand")
+			  (match_operand:SI 2 "immediate_operand")
+			  (match_operand:SI 3 "immediate_operand")
+			  (match_operand:SI 4 "immediate_operand")
+			  (match_operand:SI 5 "immediate_operand")] MRCI))]
+  "arm_coproc_builtin_available (VUNSPEC_<MRC>)"
+{
+  arm_const_bounds (operands[1], 0, 16);
+  arm_const_bounds (operands[2], 0, 8);
+  arm_const_bounds (operands[3], 0, (1 << 5));
+  arm_const_bounds (operands[4], 0, (1 << 5));
+  arm_const_bounds (operands[5], 0, 8);
+  return "<mrc>\\tp%c1, %2, %0, CR%c3, CR%c4, %5";
+}
+  [(set_attr "length" "4")
+   (set_attr "type" "coproc")])
+
 ;; Vector bits common to IWMMXT and Neon
 (include "vec-common.md")
 ;; Load the Intel Wireless Multimedia Extension patterns
diff --git a/gcc/config/arm/arm_acle.h b/gcc/config/arm/arm_acle.h
index 81527782dfe16fa3be7638ddd38051e333f7e18c..2a202f3982176ba8fd7475ee75863034eff662e6 100644
--- a/gcc/config/arm/arm_acle.h
+++ b/gcc/config/arm/arm_acle.h
@@ -68,6 +68,22 @@  __arm_stcl (const unsigned int __coproc, const unsigned int __CRd,
 {
   return __builtin_arm_stcl (__coproc, __CRd, __p);
 }
+
+__extension__ static __inline void __attribute__ ((__always_inline__))
+__arm_mcr (const unsigned int __coproc, const unsigned int __opc1,
+	   uint32_t __value, const unsigned int __CRn, const unsigned int __CRm,
+	   const unsigned int __opc2)
+{
+  return __builtin_arm_mcr (__coproc, __opc1, __value, __CRn, __CRm, __opc2);
+}
+
+__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
+__arm_mrc (const unsigned int __coproc, const unsigned int __opc1,
+	   const unsigned int __CRn, const unsigned int __CRm,
+	   const unsigned int __opc2)
+{
+  return __builtin_arm_mrc (__coproc, __opc1, __CRn, __CRm, __opc2);
+}
 #if __ARM_ARCH >= 5
 __extension__ static __inline void __attribute__ ((__always_inline__))
 __arm_cdp2 (const unsigned int __coproc, const unsigned int __opc1,
@@ -104,6 +120,22 @@  __arm_stc2l (const unsigned int __coproc, const unsigned int __CRd,
 {
   return __builtin_arm_stc2l (__coproc, __CRd, __p);
 }
+
+__extension__ static __inline void __attribute__ ((__always_inline__))
+__arm_mcr2 (const unsigned int __coproc, const unsigned int __opc1,
+	    uint32_t __value, const unsigned int __CRn,
+	    const unsigned int __CRm, const unsigned int __opc2)
+{
+  return __builtin_arm_mcr2 (__coproc, __opc1, __value, __CRn, __CRm, __opc2);
+}
+
+__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
+__arm_mrc2 (const unsigned int __coproc, const unsigned int __opc1,
+	    const unsigned int __CRn, const unsigned int __CRm,
+	    const unsigned int __opc2)
+{
+  return __builtin_arm_mrc2 (__coproc, __opc1, __CRn, __CRm, __opc2);
+}
 #endif /*  __ARM_ARCH >= 5.  */
 #endif /* (!__thumb__ || __thumb2__) &&  __ARM_ARCH >= 4.  */
 
diff --git a/gcc/config/arm/arm_acle_builtins.def b/gcc/config/arm/arm_acle_builtins.def
index eb6168d98a897280aef2954372613487ca256fb0..d258f8a3748f6b4f0aeb3d4a28c6d4d79597f69c 100644
--- a/gcc/config/arm/arm_acle_builtins.def
+++ b/gcc/config/arm/arm_acle_builtins.def
@@ -34,3 +34,7 @@  VAR1 (STC, stc, void)
 VAR1 (STC, stc2, void)
 VAR1 (STC, stcl, void)
 VAR1 (STC, stc2l, void)
+VAR1 (MCR, mcr, void)
+VAR1 (MCR, mcr2, void)
+VAR1 (MRC, mrc, si)
+VAR1 (MRC, mrc2, si)
diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md
index e1f5e4911a8f76ae0cd283dd55328dd7720f50d6..899e5184c61bf7a2800df01b31d56a8dab1abcb3 100644
--- a/gcc/config/arm/iterators.md
+++ b/gcc/config/arm/iterators.md
@@ -963,3 +963,15 @@ 
 			 (VUNSPEC_LDCL "LDCL") (VUNSPEC_LDC2L "LDC2L")
 			 (VUNSPEC_STC "STC") (VUNSPEC_STC2 "STC2")
 			 (VUNSPEC_STCL "STCL") (VUNSPEC_STC2L "STC2L")])
+
+;; An iterator for the MCR coprocessor instructions
+(define_int_iterator MCRI [VUNSPEC_MCR VUNSPEC_MCR2])
+
+(define_int_attr mcr [(VUNSPEC_MCR "mcr") (VUNSPEC_MCR2 "mcr2")])
+(define_int_attr MCR [(VUNSPEC_MCR "MCR") (VUNSPEC_MCR2 "MCR2")])
+
+;; An iterator for the MRC coprocessor instructions
+(define_int_iterator MRCI [VUNSPEC_MRC VUNSPEC_MRC2])
+
+(define_int_attr mrc [(VUNSPEC_MRC "mrc") (VUNSPEC_MRC2 "mrc2")])
+(define_int_attr MRC [(VUNSPEC_MRC "MRC") (VUNSPEC_MRC2 "MRC2")])
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index 2b6ba8b4b4b08742204153462c3d0dff02374d42..48a711e6c7160a85435ae45b6668b55494a9a671 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -158,6 +158,10 @@ 
   VUNSPEC_STC2		; Represent the coprocessor stc2 instruction.
   VUNSPEC_STCL		; Represent the coprocessor stcl instruction.
   VUNSPEC_STC2L		; Represent the coprocessor stc2l instruction.
+  VUNSPEC_MCR		; Represent the coprocessor mcr instruction.
+  VUNSPEC_MCR2		; Represent the coprocessor mcr2 instruction.
+  VUNSPEC_MRC		; Represent the coprocessor mrc instruction.
+  VUNSPEC_MRC2		; Represent the coprocessor mrc2 instruction.
 ])
 
 ;; Enumerators for NEON unspecs.
diff --git a/gcc/testsuite/gcc.target/arm/acle/mcr.c b/gcc/testsuite/gcc.target/arm/acle/mcr.c
new file mode 100644
index 0000000000000000000000000000000000000000..93f977a2bdb03ece206cf36b4d67f47811dd0073
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/acle/mcr.c
@@ -0,0 +1,16 @@ 
+/* Test the mcr ACLE intrinsic.  */
+
+/* { dg-do assemble } */
+/* { dg-options "-save-temps" } */
+/* { dg-require-effective-target arm_coproc1_ok } */
+
+#include "arm_acle.h"
+
+void test_mcr (uint32_t a)
+{
+  a += 77;
+  __arm_mcr (10, 5, a, 3, 4, 7);
+}
+
+/* { dg-final { scan-assembler "add\[^\n\]*#77\n" } } */
+/* { dg-final { scan-assembler "mcr\tp10, #5, r\[r0-9\]*, CR3, CR4, #7\n" } } */
diff --git a/gcc/testsuite/gcc.target/arm/acle/mcr2.c b/gcc/testsuite/gcc.target/arm/acle/mcr2.c
new file mode 100644
index 0000000000000000000000000000000000000000..5b60d10ff255a0a72dc93fcc13056b0d424ffec7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/acle/mcr2.c
@@ -0,0 +1,16 @@ 
+/* Test the mcr2 ACLE intrinsic.  */
+
+/* { dg-do assemble } */
+/* { dg-options "-save-temps" } */
+/* { dg-require-effective-target arm_coproc2_ok } */
+
+#include "arm_acle.h"
+
+void test_mcr2 (uint32_t a)
+{
+  a += 77;
+  __arm_mcr2 (10, 5, a, 3, 4, 7);
+}
+
+/* { dg-final { scan-assembler "add\[^\n\]*#77\n" } } */
+/* { dg-final { scan-assembler "mcr2\tp10, #5, r\[r0-9\]*, CR3, CR4, #7\n" } } */
diff --git a/gcc/testsuite/gcc.target/arm/acle/mrc.c b/gcc/testsuite/gcc.target/arm/acle/mrc.c
new file mode 100644
index 0000000000000000000000000000000000000000..34ca6a1638c5667b3ef529ebcf448caecc6e3492
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/acle/mrc.c
@@ -0,0 +1,14 @@ 
+/* Test the mrc ACLE intrinsic.  */
+
+/* { dg-do assemble } */
+/* { dg-options "-save-temps" } */
+/* { dg-require-effective-target arm_coproc1_ok } */
+
+#include "arm_acle.h"
+
+uint32_t test_mrc (void)
+{
+  return __arm_mrc (10, 0, 0, 15, 3);
+}
+
+/* { dg-final { scan-assembler "mrc\tp10, #0, r\[r0-9\]*, CR0, CR15, #3\n" } } */
diff --git a/gcc/testsuite/gcc.target/arm/acle/mrc2.c b/gcc/testsuite/gcc.target/arm/acle/mrc2.c
new file mode 100644
index 0000000000000000000000000000000000000000..3b72a402224dec5544349c9e4d79c9a8aa5a1f8c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/acle/mrc2.c
@@ -0,0 +1,14 @@ 
+/* Test the mrc2 ACLE intrinsic.  */
+
+/* { dg-do assemble } */
+/* { dg-options "-save-temps" } */
+/* { dg-require-effective-target arm_coproc2_ok } */
+
+#include "arm_acle.h"
+
+uint32_t test_mrc2 (void)
+{
+  return __arm_mrc2 (10, 0, 0, 15, 3);
+}
+
+/* { dg-final { scan-assembler "mrc2\tp10, #0, r\[r0-9\]*, CR0, CR15, #3\n" } } */