[ARM] Implement support for ACLE Coprocessor LDC and STC intrinsics

gcc/ChangeLog:
2017-01-06  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	* config/arm/arm.md (*ldc): New.
	(*stc): New.
	(<ldc>): New.
	(<stc>): New.
	* config/arm/arm.c (arm_coproc_builtin_available): Add
	support for ldc,ldcl,stc,stcl,ldc2,ldc2l,stc2 and stc2l.
	(arm_coproc_ldc_stc_legitimate_address): New.
	* config/arm/arm-builtins.c (arm_type_qualifiers): Add
	'qualifier_const_pointer'.
	(LDC_QUALIFIERS): Define to...
	(arm_ldc_qualifiers): ... this. New.
	(STC_QUALIFIERS): Define to...
	(arm_stc_qualifiers): ... this. New.
	* config/arm/arm-protos.h
	(arm_coproc_ldc_stc_legitimate_address): New.
	* config/arm/arm_acle.h (__arm_ldc, __arm_ldcl, __arm_stc,
	__arm_stcl, __arm_ldc2, __arm_ldc2l, __arm_stc2, __arm_stc2l): New.
	* config/arm/arm_acle_builtins.def (ldc, ldc2, ldcl, ldc2l, stc,
	stc2, stcl, stc2l): New.
	* config/arm/constraints.md (Uz): New.
	* config/arm/iterators.md (LDCI, STCI, ldc, stc, LDC STC): New.
	* config/arm/unspecs.md (VUNSPEC_LDC, VUNSPEC_LDC2, VUNSPEC_LDCL,
	VUNSPEC_LDC2L, VUNSPEC_STC, VUNSPEC_STC2, VUNSPEC_STCL,
	VUNSPEC_STC2L): New.

gcc/testsuite/ChangeLog:
2017-01-06  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	* gcc.target/arm/acle/ldc: New.
	* gcc.target/arm/acle/ldc2: New.
	* gcc.target/arm/acle/ldcl: New.
	* gcc.target/arm/acle/ldc2l: New.
	* gcc.target/arm/acle/stc: New.
	* gcc.target/arm/acle/stc2: New.
	* gcc.target/arm/acle/stcl: New.
	* gcc.target/arm/acle/stc2l: New.

From-SVN: r244173
This commit is contained in:
Andre Vieira 2017-01-06 17:37:39 +00:00 committed by Andre Vieira
parent d57daa0c9d
commit 3811581f8b
19 changed files with 392 additions and 0 deletions

View File

@ -1,3 +1,30 @@
2017-01-06 Andre Vieira <andre.simoesdiasvieira@arm.com>
* config/arm/arm.md (*ldc): New.
(*stc): New.
(<ldc>): New.
(<stc>): New.
* config/arm/arm.c (arm_coproc_builtin_available): Add
support for ldc,ldcl,stc,stcl,ldc2,ldc2l,stc2 and stc2l.
(arm_coproc_ldc_stc_legitimate_address): New.
* config/arm/arm-builtins.c (arm_type_qualifiers): Add
'qualifier_const_pointer'.
(LDC_QUALIFIERS): Define to...
(arm_ldc_qualifiers): ... this. New.
(STC_QUALIFIERS): Define to...
(arm_stc_qualifiers): ... this. New.
* config/arm/arm-protos.h
(arm_coproc_ldc_stc_legitimate_address): New.
* config/arm/arm_acle.h (__arm_ldc, __arm_ldcl, __arm_stc,
__arm_stcl, __arm_ldc2, __arm_ldc2l, __arm_stc2, __arm_stc2l): New.
* config/arm/arm_acle_builtins.def (ldc, ldc2, ldcl, ldc2l, stc,
stc2, stcl, stc2l): New.
* config/arm/constraints.md (Uz): New.
* config/arm/iterators.md (LDCI, STCI, ldc, stc, LDC STC): New.
* config/arm/unspecs.md (VUNSPEC_LDC, VUNSPEC_LDC2, VUNSPEC_LDCL,
VUNSPEC_LDC2L, VUNSPEC_STC, VUNSPEC_STC2, VUNSPEC_STCL,
VUNSPEC_STC2L): New.
2017-01-06 Andre Vieira <andre.simoesdiasvieira@arm.com>
* config/arm/arm.md (<cdp>): New.

View File

@ -51,6 +51,8 @@ enum arm_type_qualifiers
qualifier_const = 0x2, /* 1 << 1 */
/* T *foo. */
qualifier_pointer = 0x4, /* 1 << 2 */
/* const T * foo. */
qualifier_const_pointer = 0x6,
/* Used when expanding arguments if an operand could
be an immediate. */
qualifier_immediate = 0x8, /* 1 << 3 */
@ -178,6 +180,23 @@ arm_cdp_qualifiers[SIMD_MAX_BUILTIN_ARGS]
qualifier_unsigned_immediate };
#define CDP_QUALIFIERS \
(arm_cdp_qualifiers)
/* void (unsigned immediate, unsigned immediate, const void *). */
static enum arm_type_qualifiers
arm_ldc_qualifiers[SIMD_MAX_BUILTIN_ARGS]
= { qualifier_void, qualifier_unsigned_immediate,
qualifier_unsigned_immediate, qualifier_const_pointer };
#define LDC_QUALIFIERS \
(arm_ldc_qualifiers)
/* void (unsigned immediate, unsigned immediate, void *). */
static enum arm_type_qualifiers
arm_stc_qualifiers[SIMD_MAX_BUILTIN_ARGS]
= { qualifier_void, qualifier_unsigned_immediate,
qualifier_unsigned_immediate, qualifier_pointer };
#define STC_QUALIFIERS \
(arm_stc_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

View File

@ -177,6 +177,7 @@ extern void arm_split_compare_and_swap (rtx op[]);
extern void arm_split_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx, rtx);
extern rtx arm_load_tp (rtx);
extern bool arm_coproc_builtin_available (enum unspecv);
extern bool arm_coproc_ldc_stc_legitimate_address (rtx);
#if defined TREE_CODE
extern void arm_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree);

View File

@ -30904,10 +30904,18 @@ arm_coproc_builtin_available (enum unspecv builtin)
switch (builtin)
{
case VUNSPEC_CDP:
case VUNSPEC_LDC:
case VUNSPEC_LDCL:
case VUNSPEC_STC:
case VUNSPEC_STCL:
if (arm_arch4)
return true;
break;
case VUNSPEC_CDP2:
case VUNSPEC_LDC2:
case VUNSPEC_LDC2L:
case VUNSPEC_STC2:
case VUNSPEC_STC2L:
/* Only present in ARMv5*, ARMv6 (but not ARMv6-M), ARMv7* and
ARMv8-{A,M}. */
if (arm_arch5)
@ -30918,4 +30926,55 @@ arm_coproc_builtin_available (enum unspecv builtin)
}
return false;
}
/* This function returns true if OP is a valid memory operand for the ldc and
stc coprocessor instructions and false otherwise. */
bool
arm_coproc_ldc_stc_legitimate_address (rtx op)
{
HOST_WIDE_INT range;
/* Has to be a memory operand. */
if (!MEM_P (op))
return false;
op = XEXP (op, 0);
/* We accept registers. */
if (REG_P (op))
return true;
switch GET_CODE (op)
{
case PLUS:
{
/* Or registers with an offset. */
if (!REG_P (XEXP (op, 0)))
return false;
op = XEXP (op, 1);
/* The offset must be an immediate though. */
if (!CONST_INT_P (op))
return false;
range = INTVAL (op);
/* Within the range of [-1020,1020]. */
if (!IN_RANGE (range, -1020, 1020))
return false;
/* And a multiple of 4. */
return (range % 4) == 0;
}
case PRE_INC:
case POST_INC:
case PRE_DEC:
case POST_DEC:
return REG_P (XEXP (op, 0));
default:
gcc_unreachable ();
}
return false;
}
#include "gt-arm.h"

View File

@ -11939,6 +11939,44 @@
[(set_attr "length" "4")
(set_attr "type" "coproc")])
(define_insn "*ldc"
[(unspec_volatile [(match_operand:SI 0 "immediate_operand" "n")
(match_operand:SI 1 "immediate_operand" "n")
(match_operand:SI 2 "memory_operand" "Uz")] LDCI)]
"arm_coproc_builtin_available (VUNSPEC_<LDC>)"
{
arm_const_bounds (operands[0], 0, 16);
arm_const_bounds (operands[1], 0, (1 << 5));
return "<ldc>\\tp%c0, CR%c1, %2";
}
[(set_attr "length" "4")
(set_attr "type" "coproc")])
(define_insn "*stc"
[(unspec_volatile [(match_operand:SI 0 "immediate_operand" "n")
(match_operand:SI 1 "immediate_operand" "n")
(match_operand:SI 2 "memory_operand" "=Uz")] STCI)]
"arm_coproc_builtin_available (VUNSPEC_<STC>)"
{
arm_const_bounds (operands[0], 0, 16);
arm_const_bounds (operands[1], 0, (1 << 5));
return "<stc>\\tp%c0, CR%c1, %2";
}
[(set_attr "length" "4")
(set_attr "type" "coproc")])
(define_expand "<ldc>"
[(unspec_volatile [(match_operand:SI 0 "immediate_operand")
(match_operand:SI 1 "immediate_operand")
(mem:SI (match_operand:SI 2 "s_register_operand"))] LDCI)]
"arm_coproc_builtin_available (VUNSPEC_<LDC>)")
(define_expand "<stc>"
[(unspec_volatile [(match_operand:SI 0 "immediate_operand")
(match_operand:SI 1 "immediate_operand")
(mem:SI (match_operand:SI 2 "s_register_operand"))] STCI)]
"arm_coproc_builtin_available (VUNSPEC_<STC>)")
;; Vector bits common to IWMMXT and Neon
(include "vec-common.md")
;; Load the Intel Wireless Multimedia Extension patterns

View File

@ -41,6 +41,33 @@ __arm_cdp (const unsigned int __coproc, const unsigned int __opc1,
return __builtin_arm_cdp (__coproc, __opc1, __CRd, __CRn, __CRm, __opc2);
}
__extension__ static __inline void __attribute__ ((__always_inline__))
__arm_ldc (const unsigned int __coproc, const unsigned int __CRd,
const void * __p)
{
return __builtin_arm_ldc (__coproc, __CRd, __p);
}
__extension__ static __inline void __attribute__ ((__always_inline__))
__arm_ldcl (const unsigned int __coproc, const unsigned int __CRd,
const void * __p)
{
return __builtin_arm_ldcl (__coproc, __CRd, __p);
}
__extension__ static __inline void __attribute__ ((__always_inline__))
__arm_stc (const unsigned int __coproc, const unsigned int __CRd,
void * __p)
{
return __builtin_arm_stc (__coproc, __CRd, __p);
}
__extension__ static __inline void __attribute__ ((__always_inline__))
__arm_stcl (const unsigned int __coproc, const unsigned int __CRd,
void * __p)
{
return __builtin_arm_stcl (__coproc, __CRd, __p);
}
#if __ARM_ARCH >= 5
__extension__ static __inline void __attribute__ ((__always_inline__))
__arm_cdp2 (const unsigned int __coproc, const unsigned int __opc1,
@ -49,6 +76,34 @@ __arm_cdp2 (const unsigned int __coproc, const unsigned int __opc1,
{
return __builtin_arm_cdp2 (__coproc, __opc1, __CRd, __CRn, __CRm, __opc2);
}
__extension__ static __inline void __attribute__ ((__always_inline__))
__arm_ldc2 (const unsigned int __coproc, const unsigned int __CRd,
const void * __p)
{
return __builtin_arm_ldc2 (__coproc, __CRd, __p);
}
__extension__ static __inline void __attribute__ ((__always_inline__))
__arm_ldc2l (const unsigned int __coproc, const unsigned int __CRd,
const void * __p)
{
return __builtin_arm_ldc2l (__coproc, __CRd, __p);
}
__extension__ static __inline void __attribute__ ((__always_inline__))
__arm_stc2 (const unsigned int __coproc, const unsigned int __CRd,
void * __p)
{
return __builtin_arm_stc2 (__coproc, __CRd, __p);
}
__extension__ static __inline void __attribute__ ((__always_inline__))
__arm_stc2l (const unsigned int __coproc, const unsigned int __CRd,
void * __p)
{
return __builtin_arm_stc2l (__coproc, __CRd, __p);
}
#endif /* __ARM_ARCH >= 5. */
#endif /* (!__thumb__ || __thumb2__) && __ARM_ARCH >= 4. */

View File

@ -26,3 +26,11 @@ VAR1 (UBINOP, crc32ch, si)
VAR1 (UBINOP, crc32cw, si)
VAR1 (CDP, cdp, void)
VAR1 (CDP, cdp2, void)
VAR1 (LDC, ldc, void)
VAR1 (LDC, ldc2, void)
VAR1 (LDC, ldcl, void)
VAR1 (LDC, ldc2l, void)
VAR1 (STC, stc, void)
VAR1 (STC, stc2, void)
VAR1 (STC, stcl, void)
VAR1 (STC, stc2l, void)

View File

@ -447,6 +447,12 @@
(match_code "symbol_ref")
)
(define_memory_constraint "Uz"
"@internal
A memory access that is accessible as an LDC/STC operand"
(and (match_code "mem")
(match_test "arm_coproc_ldc_stc_legitimate_address (op)")))
;; We used to have constraint letters for S and R in ARM state, but
;; all uses of these now appear to have been removed.

View File

@ -948,3 +948,19 @@
(define_int_iterator CDPI [VUNSPEC_CDP VUNSPEC_CDP2])
(define_int_attr cdp [(VUNSPEC_CDP "cdp") (VUNSPEC_CDP2 "cdp2")])
(define_int_attr CDP [(VUNSPEC_CDP "CDP") (VUNSPEC_CDP2 "CDP2")])
;; An iterator for the LDC coprocessor instruction
(define_int_iterator LDCI [VUNSPEC_LDC VUNSPEC_LDC2
VUNSPEC_LDCL VUNSPEC_LDC2L])
(define_int_attr ldc [(VUNSPEC_LDC "ldc") (VUNSPEC_LDC2 "ldc2")
(VUNSPEC_LDCL "ldcl") (VUNSPEC_LDC2L "ldc2l")])
(define_int_attr LDC [(VUNSPEC_LDC "LDC") (VUNSPEC_LDC2 "LDC2")
(VUNSPEC_LDCL "LDCL") (VUNSPEC_LDC2L "LDC2L")])
;; An iterator for the STC coprocessor instructions
(define_int_iterator STCI [VUNSPEC_STC VUNSPEC_STC2
VUNSPEC_STCL VUNSPEC_STC2L])
(define_int_attr stc [(VUNSPEC_STC "stc") (VUNSPEC_STC2 "stc2")
(VUNSPEC_STCL "stcl") (VUNSPEC_STC2L "stc2l")])
(define_int_attr STC [(VUNSPEC_STC "STC") (VUNSPEC_STC2 "STC2")
(VUNSPEC_STCL "STCL") (VUNSPEC_STC2L "STC2L")])

View File

@ -152,6 +152,14 @@
VUNSPEC_PROBE_STACK_RANGE ; Represent stack range probing.
VUNSPEC_CDP ; Represent the coprocessor cdp instruction.
VUNSPEC_CDP2 ; Represent the coprocessor cdp2 instruction.
VUNSPEC_LDC ; Represent the coprocessor ldc instruction.
VUNSPEC_LDC2 ; Represent the coprocessor ldc2 instruction.
VUNSPEC_LDCL ; Represent the coprocessor ldcl instruction.
VUNSPEC_LDC2L ; Represent the coprocessor ldc2l instruction.
VUNSPEC_STC ; Represent the coprocessor stc instruction.
VUNSPEC_STC2 ; Represent the coprocessor stc2 instruction.
VUNSPEC_STCL ; Represent the coprocessor stcl instruction.
VUNSPEC_STC2L ; Represent the coprocessor stc2l instruction.
])
;; Enumerators for NEON unspecs.

View File

@ -1,3 +1,14 @@
2017-01-06 Andre Vieira <andre.simoesdiasvieira@arm.com>
* gcc.target/arm/acle/ldc: New.
* gcc.target/arm/acle/ldc2: New.
* gcc.target/arm/acle/ldcl: New.
* gcc.target/arm/acle/ldc2l: New.
* gcc.target/arm/acle/stc: New.
* gcc.target/arm/acle/stc2: New.
* gcc.target/arm/acle/stcl: New.
* gcc.target/arm/acle/stc2l: New.
2017-01-06 Andre Vieira <andre.simoesdiasvieira@arm.com>
* gcc.target/arm/acle/acle.exp: Run tests for different options

View File

@ -0,0 +1,18 @@
/* Test the ldc ACLE intrinsic. */
/* { dg-do assemble } */
/* { dg-options "-save-temps" } */
/* { dg-require-effective-target arm_coproc1_ok } */
#include "arm_acle.h"
extern void * p;
void test_ldc (void)
{
__arm_ldc (10, 1, p + 4);
__arm_ldc (11, 1, p + 1024);
}
/* { dg-final { scan-assembler "ldc\tp10, CR1, \[r\[0-9\]+" } } */
/* { dg-final { scan-assembler "ldc\tp11, CR1, \[r\[0-9\]+\]\n" } } */

View File

@ -0,0 +1,18 @@
/* Test the ldc2 ACLE intrinsic. */
/* { dg-do assemble } */
/* { dg-options "-save-temps" } */
/* { dg-require-effective-target arm_coproc2_ok } */
#include "arm_acle.h"
extern void * p;
void test_ldc2 (void)
{
__arm_ldc2 (10, 1, p - 120);
__arm_ldc2 (11, 1, p - 122);
}
/* { dg-final { scan-assembler "ldc2\tp10, CR1, \[r\[0-9\]+" } } */
/* { dg-final { scan-assembler "ldc2\tp11, CR1, \[r\[0-9\]+\]\n" } } */

View File

@ -0,0 +1,18 @@
/* Test the ldc2l ACLE intrinsic. */
/* { dg-do assemble } */
/* { dg-options "-save-temps" } */
/* { dg-require-effective-target arm_coproc2_ok } */
#include "arm_acle.h"
extern void * p;
void test_ldc2l (void)
{
__arm_ldc2l (10, 1, p - 120);
__arm_ldc2l (11, 1, p - 122);
}
/* { dg-final { scan-assembler "ldc2l\tp10, CR1, \[r\[0-9\]+" } } */
/* { dg-final { scan-assembler "ldc2l\tp11, CR1, \[r\[0-9\]+\]\n" } } */

View File

@ -0,0 +1,18 @@
/* Test the ldcl ACLE intrinsic. */
/* { dg-do assemble } */
/* { dg-options "-save-temps" } */
/* { dg-require-effective-target arm_coproc1_ok } */
#include "arm_acle.h"
extern void * p;
void test_ldcl (void)
{
__arm_ldcl (10, 1, p + 4);
__arm_ldcl (11, 1, p + 1024);
}
/* { dg-final { scan-assembler "ldcl\tp10, CR1, \[r\[0-9\]+" } } */
/* { dg-final { scan-assembler "ldcl\tp11, CR1, \[r\[0-9\]+\]\n" } } */

View File

@ -0,0 +1,18 @@
/* Test the stc ACLE intrinsic. */
/* { dg-do assemble } */
/* { dg-options "-save-temps" } */
/* { dg-require-effective-target arm_coproc1_ok } */
#include "arm_acle.h"
extern void * p;
void test_stc (void)
{
__arm_stc (10, 1, p + 4);
__arm_stc (11, 1, p + 1024);
}
/* { dg-final { scan-assembler "stc\tp10, CR1, \[r\[0-9\]+" } } */
/* { dg-final { scan-assembler "stc\tp11, CR1, \[r\[0-9\]+\]\n" } } */

View File

@ -0,0 +1,18 @@
/* Test the stc2 ACLE intrinsic. */
/* { dg-do assemble } */
/* { dg-options "-save-temps" } */
/* { dg-require-effective-target arm_coproc2_ok } */
#include "arm_acle.h"
extern void * p;
void test_stc2 (void)
{
__arm_stc2 (10, 1, p - 120);
__arm_stc2 (11, 1, p - 122);
}
/* { dg-final { scan-assembler "stc2\tp10, CR1, \[r\[0-9\]+" } } */
/* { dg-final { scan-assembler "stc2\tp11, CR1, \[r\[0-9\]+\]\n" } } */

View File

@ -0,0 +1,18 @@
/* Test the stc2l ACLE intrinsic. */
/* { dg-do assemble } */
/* { dg-options "-save-temps" } */
/* { dg-require-effective-target arm_coproc2_ok } */
#include "arm_acle.h"
extern void * p;
void test_stc2l (void)
{
__arm_stc2l (10, 1, p - 120);
__arm_stc2l (11, 1, p - 122);
}
/* { dg-final { scan-assembler "stc2l\tp10, CR1, \[r\[0-9\]+" } } */
/* { dg-final { scan-assembler "stc2l\tp11, CR1, \[r\[0-9\]+\]\n" } } */

View File

@ -0,0 +1,18 @@
/* Test the stcl ACLE intrinsic. */
/* { dg-do assemble } */
/* { dg-options "-save-temps" } */
/* { dg-require-effective-target arm_coproc1_ok } */
#include "arm_acle.h"
extern void * p;
void test_stcl (void)
{
__arm_stcl (14, 10, p + 4);
__arm_stcl (10, 10, p + 1024);
}
/* { dg-final { scan-assembler "stcl\tp14, CR10, \[r\[0-9\]+" } } */
/* { dg-final { scan-assembler "stcl\tp10, CR10, \[r\[0-9\]+\]\n" } } */