Commit 3811581f by Andre Vieira Committed by Andre Vieira

[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
parent d57daa0c
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.
* config/arm/arm.c (neon_const_bounds): Rename this ...
(arm_const_bounds): ... this.
......
......@@ -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
......
......@@ -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);
......
......@@ -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"
......@@ -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
......
......@@ -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. */
......
......@@ -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)
......@@ -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.
......
......@@ -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")])
......@@ -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.
......
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
and make sure fat-lto-objects is used such that we can still do
assemble scans.
......
/* 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" } } */
/* 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" } } */
/* 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" } } */
/* 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" } } */
/* 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" } } */
/* 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" } } */
/* 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" } } */
/* 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" } } */
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