arm: Enable no-writeback vldr.16/vstr.16.
There was previously no way to specify that a register operand cannot have any writeback modifiers, and as a result the argument to vldr.16 and vstr.16 could be erroneously output with post-increment. This change adds a constraint which forbids all writeback, and selects it in the relevant case for vldr.16 and vstr.16 Bootstrapped on arm-linux, gcc and CMSIS-DSP testsuites are clean. Is this patch OK for trunk? If yes, please commit on my behalf as I don't have commit rights. gcc/ChangeLog: * config/arm/arm-protos.h (arm_coproc_mem_operand_no_writeback): Declare prototype. (arm_mve_mode_and_operands_type_check): Declare prototype. * config/arm/arm.c (arm_coproc_mem_operand): Refactor to use _arm_coproc_mem_operand. (arm_coproc_mem_operand_wb): New function to cover full, limited and no writeback. (arm_coproc_mem_operand_no_writeback): New constraint for memory operand with no writeback. (arm_print_operand): Extend 'E' specifier for memory operand that does not support writeback. (arm_mve_mode_and_operands_type_check): New constraint check for MVE memory operands. * config/arm/constraints.md: Add Uj constraint for VFP vldr.16 and vstr.16. * config/arm/vfp.md (*mov_load_vfp_hf16): New pattern for vldr.16. (*mov_store_vfp_hf16): New pattern for vstr.16. (*mov<mode>_vfp_<mode>16): Remove MVE moves.
This commit is contained in:
parent
5175857714
commit
9f6abd2db9
|
@ -116,8 +116,11 @@ extern enum reg_class coproc_secondary_reload_class (machine_mode, rtx,
|
||||||
extern bool arm_tls_referenced_p (rtx);
|
extern bool arm_tls_referenced_p (rtx);
|
||||||
|
|
||||||
extern int arm_coproc_mem_operand (rtx, bool);
|
extern int arm_coproc_mem_operand (rtx, bool);
|
||||||
|
extern int arm_coproc_mem_operand_no_writeback (rtx);
|
||||||
|
extern int arm_coproc_mem_operand_wb (rtx, int);
|
||||||
extern int neon_vector_mem_operand (rtx, int, bool);
|
extern int neon_vector_mem_operand (rtx, int, bool);
|
||||||
extern int mve_vector_mem_operand (machine_mode, rtx, bool);
|
extern int mve_vector_mem_operand (machine_mode, rtx, bool);
|
||||||
|
bool arm_mve_mode_and_operands_type_check (machine_mode, rtx, rtx);
|
||||||
extern int neon_struct_mem_operand (rtx);
|
extern int neon_struct_mem_operand (rtx);
|
||||||
|
|
||||||
extern rtx *neon_vcmla_lane_prepare_operands (rtx *);
|
extern rtx *neon_vcmla_lane_prepare_operands (rtx *);
|
||||||
|
|
|
@ -13235,13 +13235,14 @@ neon_element_bits (machine_mode mode)
|
||||||
/* Predicates for `match_operand' and `match_operator'. */
|
/* Predicates for `match_operand' and `match_operator'. */
|
||||||
|
|
||||||
/* Return TRUE if OP is a valid coprocessor memory address pattern.
|
/* Return TRUE if OP is a valid coprocessor memory address pattern.
|
||||||
WB is true if full writeback address modes are allowed and is false
|
WB level is 2 if full writeback address modes are allowed, 1
|
||||||
if limited writeback address modes (POST_INC and PRE_DEC) are
|
if limited writeback address modes (POST_INC and PRE_DEC) are
|
||||||
allowed. */
|
allowed and 0 if no writeback at all is supported. */
|
||||||
|
|
||||||
int
|
int
|
||||||
arm_coproc_mem_operand (rtx op, bool wb)
|
arm_coproc_mem_operand_wb (rtx op, int wb_level)
|
||||||
{
|
{
|
||||||
|
gcc_assert (wb_level == 0 || wb_level == 1 || wb_level == 2);
|
||||||
rtx ind;
|
rtx ind;
|
||||||
|
|
||||||
/* Reject eliminable registers. */
|
/* Reject eliminable registers. */
|
||||||
|
@ -13274,16 +13275,18 @@ arm_coproc_mem_operand (rtx op, bool wb)
|
||||||
|
|
||||||
/* Autoincremment addressing modes. POST_INC and PRE_DEC are
|
/* Autoincremment addressing modes. POST_INC and PRE_DEC are
|
||||||
acceptable in any case (subject to verification by
|
acceptable in any case (subject to verification by
|
||||||
arm_address_register_rtx_p). We need WB to be true to accept
|
arm_address_register_rtx_p). We need full writeback to accept
|
||||||
|
PRE_INC and POST_DEC, and at least restricted writeback for
|
||||||
PRE_INC and POST_DEC. */
|
PRE_INC and POST_DEC. */
|
||||||
if (GET_CODE (ind) == POST_INC
|
if (wb_level > 0
|
||||||
|| GET_CODE (ind) == PRE_DEC
|
&& (GET_CODE (ind) == POST_INC
|
||||||
|| (wb
|
|| GET_CODE (ind) == PRE_DEC
|
||||||
&& (GET_CODE (ind) == PRE_INC
|
|| (wb_level > 1
|
||||||
|| GET_CODE (ind) == POST_DEC)))
|
&& (GET_CODE (ind) == PRE_INC
|
||||||
|
|| GET_CODE (ind) == POST_DEC))))
|
||||||
return arm_address_register_rtx_p (XEXP (ind, 0), 0);
|
return arm_address_register_rtx_p (XEXP (ind, 0), 0);
|
||||||
|
|
||||||
if (wb
|
if (wb_level > 1
|
||||||
&& (GET_CODE (ind) == POST_MODIFY || GET_CODE (ind) == PRE_MODIFY)
|
&& (GET_CODE (ind) == POST_MODIFY || GET_CODE (ind) == PRE_MODIFY)
|
||||||
&& arm_address_register_rtx_p (XEXP (ind, 0), 0)
|
&& arm_address_register_rtx_p (XEXP (ind, 0), 0)
|
||||||
&& GET_CODE (XEXP (ind, 1)) == PLUS
|
&& GET_CODE (XEXP (ind, 1)) == PLUS
|
||||||
|
@ -13305,6 +13308,25 @@ arm_coproc_mem_operand (rtx op, bool wb)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return TRUE if OP is a valid coprocessor memory address pattern.
|
||||||
|
WB is true if full writeback address modes are allowed and is false
|
||||||
|
if limited writeback address modes (POST_INC and PRE_DEC) are
|
||||||
|
allowed. */
|
||||||
|
|
||||||
|
int arm_coproc_mem_operand (rtx op, bool wb)
|
||||||
|
{
|
||||||
|
return arm_coproc_mem_operand_wb (op, wb ? 2 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return TRUE if OP is a valid coprocessor memory address pattern in a
|
||||||
|
context in which no writeback address modes are allowed. */
|
||||||
|
|
||||||
|
int
|
||||||
|
arm_coproc_mem_operand_no_writeback (rtx op)
|
||||||
|
{
|
||||||
|
return arm_coproc_mem_operand_wb (op, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* This function returns TRUE on matching mode and op.
|
/* This function returns TRUE on matching mode and op.
|
||||||
1. For given modes, check for [Rn], return TRUE for Rn <= LO_REGS.
|
1. For given modes, check for [Rn], return TRUE for Rn <= LO_REGS.
|
||||||
2. For other modes, check for [Rn], return TRUE for Rn < R15 (expect R13). */
|
2. For other modes, check for [Rn], return TRUE for Rn < R15 (expect R13). */
|
||||||
|
@ -23568,7 +23590,7 @@ arm_print_condition (FILE *stream)
|
||||||
/* Globally reserved letters: acln
|
/* Globally reserved letters: acln
|
||||||
Puncutation letters currently used: @_|?().!#
|
Puncutation letters currently used: @_|?().!#
|
||||||
Lower case letters currently used: bcdefhimpqtvwxyz
|
Lower case letters currently used: bcdefhimpqtvwxyz
|
||||||
Upper case letters currently used: ABCDFGHJKLMNOPQRSTU
|
Upper case letters currently used: ABCDEFGHIJKLMNOPQRSTU
|
||||||
Letters previously used, but now deprecated/obsolete: sVWXYZ.
|
Letters previously used, but now deprecated/obsolete: sVWXYZ.
|
||||||
|
|
||||||
Note that the global reservation for 'c' is only for CONSTANT_ADDRESS_P.
|
Note that the global reservation for 'c' is only for CONSTANT_ADDRESS_P.
|
||||||
|
@ -24134,11 +24156,12 @@ arm_print_operand (FILE *stream, rtx x, int code)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* To print the memory operand with "Ux" constraint. Based on the rtx_code
|
/* To print the memory operand with "Ux" or "Uj" constraint. Based on the
|
||||||
the memory operands output looks like following.
|
rtx_code the memory operands output looks like following.
|
||||||
1. [Rn], #+/-<imm>
|
1. [Rn], #+/-<imm>
|
||||||
2. [Rn, #+/-<imm>]!
|
2. [Rn, #+/-<imm>]!
|
||||||
3. [Rn]. */
|
3. [Rn, #+/-<imm>]
|
||||||
|
4. [Rn]. */
|
||||||
case 'E':
|
case 'E':
|
||||||
{
|
{
|
||||||
rtx addr;
|
rtx addr;
|
||||||
|
@ -24173,6 +24196,16 @@ arm_print_operand (FILE *stream, rtx x, int code)
|
||||||
asm_fprintf (stream, ", #%wd]!",INTVAL (postinc_reg));
|
asm_fprintf (stream, ", #%wd]!",INTVAL (postinc_reg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (code == PLUS)
|
||||||
|
{
|
||||||
|
rtx base = XEXP (addr, 0);
|
||||||
|
rtx index = XEXP (addr, 1);
|
||||||
|
|
||||||
|
gcc_assert (REG_P (base) && CONST_INT_P (index));
|
||||||
|
|
||||||
|
HOST_WIDE_INT offset = INTVAL (index);
|
||||||
|
asm_fprintf (stream, "[%r, #%wd]", REGNO (base), offset);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gcc_assert (REG_P (addr));
|
gcc_assert (REG_P (addr));
|
||||||
|
@ -33548,4 +33581,17 @@ arm_mode_base_reg_class (machine_mode mode)
|
||||||
|
|
||||||
struct gcc_target targetm = TARGET_INITIALIZER;
|
struct gcc_target targetm = TARGET_INITIALIZER;
|
||||||
|
|
||||||
|
bool
|
||||||
|
arm_mve_mode_and_operands_type_check (machine_mode mode, rtx op0, rtx op1)
|
||||||
|
{
|
||||||
|
if (!(TARGET_HAVE_MVE || TARGET_HAVE_MVE_FLOAT))
|
||||||
|
return true;
|
||||||
|
else if (mode == E_BFmode)
|
||||||
|
return false;
|
||||||
|
else if ((s_register_operand (op0, mode) && MEM_P (op1))
|
||||||
|
|| (s_register_operand (op1, mode) && MEM_P (op0)))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#include "gt-arm.h"
|
#include "gt-arm.h"
|
||||||
|
|
|
@ -452,6 +452,13 @@
|
||||||
(and (match_code "mem")
|
(and (match_code "mem")
|
||||||
(match_test "TARGET_32BIT && arm_coproc_mem_operand (op, FALSE)")))
|
(match_test "TARGET_32BIT && arm_coproc_mem_operand (op, FALSE)")))
|
||||||
|
|
||||||
|
(define_memory_constraint "Uj"
|
||||||
|
"@internal
|
||||||
|
In ARM/Thumb-2 state an VFP load/store address which does not support
|
||||||
|
writeback at all (eg vldr.16)."
|
||||||
|
(and (match_code "mem")
|
||||||
|
(match_test "TARGET_32BIT && arm_coproc_mem_operand_no_writeback (op)")))
|
||||||
|
|
||||||
(define_memory_constraint "Uy"
|
(define_memory_constraint "Uy"
|
||||||
"@internal
|
"@internal
|
||||||
In ARM/Thumb-2 state a valid iWMMX load/store address."
|
In ARM/Thumb-2 state a valid iWMMX load/store address."
|
||||||
|
|
|
@ -387,6 +387,20 @@
|
||||||
(set_attr "arch" "t2,any,any,any,a,t2,any,any,any,any,any,any")]
|
(set_attr "arch" "t2,any,any,any,a,t2,any,any,any,any,any,any")]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(define_insn "*mov_load_vfp_hf16"
|
||||||
|
[(set (match_operand:HF 0 "s_register_operand" "=t")
|
||||||
|
(match_operand:HF 1 "memory_operand" "Uj"))]
|
||||||
|
"TARGET_HAVE_MVE_FLOAT"
|
||||||
|
"vldr.16\\t%0, %E1"
|
||||||
|
)
|
||||||
|
|
||||||
|
(define_insn "*mov_store_vfp_hf16"
|
||||||
|
[(set (match_operand:HF 0 "memory_operand" "=Uj")
|
||||||
|
(match_operand:HF 1 "s_register_operand" "t"))]
|
||||||
|
"TARGET_HAVE_MVE_FLOAT"
|
||||||
|
"vstr.16\\t%1, %E0"
|
||||||
|
)
|
||||||
|
|
||||||
;; HFmode and BFmode moves
|
;; HFmode and BFmode moves
|
||||||
|
|
||||||
(define_insn "*mov<mode>_vfp_<mode>16"
|
(define_insn "*mov<mode>_vfp_<mode>16"
|
||||||
|
@ -396,6 +410,8 @@
|
||||||
" m,r,t,r,r,t,Dv,Um,t, F"))]
|
" m,r,t,r,r,t,Dv,Um,t, F"))]
|
||||||
"TARGET_32BIT
|
"TARGET_32BIT
|
||||||
&& TARGET_VFP_FP16INST
|
&& TARGET_VFP_FP16INST
|
||||||
|
&& arm_mve_mode_and_operands_type_check (<MODE>mode, operands[0],
|
||||||
|
operands[1])
|
||||||
&& (s_register_operand (operands[0], <MODE>mode)
|
&& (s_register_operand (operands[0], <MODE>mode)
|
||||||
|| s_register_operand (operands[1], <MODE>mode))"
|
|| s_register_operand (operands[1], <MODE>mode))"
|
||||||
{
|
{
|
||||||
|
@ -414,15 +430,9 @@
|
||||||
case 6: /* S register from immediate. */
|
case 6: /* S register from immediate. */
|
||||||
return \"vmov.f16\\t%0, %1\t%@ __<fporbf>\";
|
return \"vmov.f16\\t%0, %1\t%@ __<fporbf>\";
|
||||||
case 7: /* S register from memory. */
|
case 7: /* S register from memory. */
|
||||||
if (TARGET_HAVE_MVE)
|
return \"vld1.16\\t{%z0}, %A1\";
|
||||||
return \"vldr.16\\t%0, %A1\";
|
|
||||||
else
|
|
||||||
return \"vld1.16\\t{%z0}, %A1\";
|
|
||||||
case 8: /* Memory from S register. */
|
case 8: /* Memory from S register. */
|
||||||
if (TARGET_HAVE_MVE)
|
return \"vst1.16\\t{%z1}, %A0\";
|
||||||
return \"vstr.16\\t%1, %A0\";
|
|
||||||
else
|
|
||||||
return \"vst1.16\\t{%z1}, %A0\";
|
|
||||||
case 9: /* ARM register from constant. */
|
case 9: /* ARM register from constant. */
|
||||||
{
|
{
|
||||||
long bits;
|
long bits;
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
/* { dg-require-effective-target arm_v8_1m_mve_fp_ok } */
|
||||||
|
/* { dg-add-options arm_v8_1m_mve_fp } */
|
||||||
|
/* { dg-additional-options "-O2" } */
|
||||||
|
|
||||||
|
void
|
||||||
|
fn1 (__fp16 *pSrc)
|
||||||
|
{
|
||||||
|
__fp16 high;
|
||||||
|
__fp16 *pDst = 0;
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0;; i++)
|
||||||
|
if (pSrc[i])
|
||||||
|
pDst[i] = high;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-assembler {vldr\.16\ts[0-9]+, \[r[0-9]+\]\n} } } */
|
||||||
|
/* { dg-final { scan-assembler {vstr\.16\ts[0-9]+, \[r[0-9]+\]\n} } } */
|
Loading…
Reference in New Issue