Hi Joe, > -----Original Message----- > From: Gcc-patches <gcc-patches-boun...@gcc.gnu.org> On Behalf Of Joe > Ramsay > Sent: 27 July 2020 15:08 > To: Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> > Subject: [PATCH] [PATCH][GCC] arm: Enable no-writeback vldr.16/vstr.16. > > Hi, > > 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 an operand specifier 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. > > Thanks, > Joe > > gcc/ChangeLog: > > 2020-05-20 Joe Ramsay <joe.ram...@arm.com> > > * 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): Implement 'j' 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. > > gcc/testsuite/ChangeLog: > > 2020-05-20 Joe Ramsay <joe.ram...@arm.com> > > * gcc.target/arm/mve/intrinsics/mve-vldstr16-no-writeback.c: New test. > > --- > gcc/config/arm/arm-protos.h | 3 + > gcc/config/arm/arm.c | 100 > ++++++++++++++++++--- > gcc/config/arm/constraints.md | 7 ++ > gcc/config/arm/vfp.md | 28 ++++-- > .../arm/mve/intrinsics/mve-vldstr16-no-writeback.c | 17 ++++ > 5 files changed, 135 insertions(+), 20 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/arm/mve/intrinsics/mve- > vldstr16-no-writeback.c > > diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h > index 33d162c..e811da4 100644 > --- a/gcc/config/arm/arm-protos.h > +++ b/gcc/config/arm/arm-protos.h > @@ -115,8 +115,11 @@ extern enum reg_class > coproc_secondary_reload_class (machine_mode, rtx, > extern bool arm_tls_referenced_p (rtx); > > 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 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 rtx *neon_vcmla_lane_prepare_operands (rtx *); > diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c > index 6b7ca82..ed080d2 100644 > --- a/gcc/config/arm/arm.c > +++ b/gcc/config/arm/arm.c > @@ -13217,13 +13217,14 @@ neon_element_bits (machine_mode mode) > /* Predicates for `match_operand' and `match_operator'. */ > > /* 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 > - allowed. */ > + allowed and 0 if no writeback at all is supported. */ > > 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; > > /* Reject eliminable registers. */ > @@ -13256,16 +13257,18 @@ arm_coproc_mem_operand (rtx op, bool wb) > > /* Autoincremment addressing modes. POST_INC and PRE_DEC are > 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. */ > - if (GET_CODE (ind) == POST_INC > - || GET_CODE (ind) == PRE_DEC > - || (wb > - && (GET_CODE (ind) == PRE_INC > - || GET_CODE (ind) == POST_DEC))) > + if (wb_level > 0 > + && (GET_CODE (ind) == POST_INC > + || GET_CODE (ind) == PRE_DEC > + || (wb_level > 1 > + && (GET_CODE (ind) == PRE_INC > + || GET_CODE (ind) == POST_DEC)))) > 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) > && arm_address_register_rtx_p (XEXP (ind, 0), 0) > && GET_CODE (XEXP (ind, 1)) == PLUS > @@ -13287,6 +13290,25 @@ arm_coproc_mem_operand (rtx op, bool wb) > 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. > 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). > */ > @@ -23549,8 +23571,8 @@ arm_print_condition (FILE *stream) > > /* Globally reserved letters: acln > Puncutation letters currently used: @_|?().!# > - Lower case letters currently used: bcdefhimpqtvwxyz > - Upper case letters currently used: ABCDFGHJKLMNOPQRSTU > + Lower case letters currently used: bcdefhijmpqtvwxyz > + Upper case letters currently used: ABCDEFGHIJKLMNOPQRSTU > Letters previously used, but now deprecated/obsolete: sVWXYZ. > > Note that the global reservation for 'c' is only for CONSTANT_ADDRESS_P. > @@ -24163,6 +24185,41 @@ arm_print_operand (FILE *stream, rtx x, int > code) > } > return; > > + /* To print memory operand in the case that the instruction does > + not support writeback. i.e. the output will look like either of > + the following: > + 1. [Rn] > + 2. [Rn, #+/-<imm>] */
I'm unsure why we need a new output modifier here ('j'). Shouldn't the constraints/predicates on the patterns prevent the formation of writeback addresses that should be handled by the normal address printing code? Thanks, Kyrill > + case 'j': > + { > + gcc_assert (MEM_P (x)); > + rtx addr = XEXP (x, 0); > + > + switch (GET_CODE (addr)) > + { > + case REG: > + asm_fprintf (stream, "[%r]", REGNO (addr)); > + return; > + > + case PLUS: > + { > + rtx base = XEXP (addr, 0); > + rtx index = XEXP (addr, 1); > + > + if (!REG_P (base) || !CONST_INT_P (index)) > + gcc_unreachable (); > + > + HOST_WIDE_INT offset = INTVAL (index); > + asm_fprintf (stream, "[%r, #%wd]", REGNO (base), offset); > + return; > + } > + > + default: > + gcc_unreachable (); > + } > + return; > + } > + > case 'C': > { > rtx addr; > @@ -33496,4 +33553,23 @@ arm_mode_base_reg_class (machine_mode > mode) > > 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" > diff --git a/gcc/config/arm/constraints.md b/gcc/config/arm/constraints.md > index 011badc..ff229aa 100644 > --- a/gcc/config/arm/constraints.md > +++ b/gcc/config/arm/constraints.md > @@ -452,6 +452,13 @@ > (and (match_code "mem") > (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" > "@internal > In ARM/Thumb-2 state a valid iWMMX load/store address." > diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md > index 3470679..13174bb 100644 > --- a/gcc/config/arm/vfp.md > +++ b/gcc/config/arm/vfp.md > @@ -387,6 +387,22 @@ > (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, %j1" > + [(set_attr "length" "4")] > +) > + > +(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, %j0" > + [(set_attr "length" "4")] > +) > + > ;; HFmode and BFmode moves > > (define_insn "*mov<mode>_vfp_<mode>16" > @@ -396,6 +412,8 @@ > " m,r,t,r,r,t,Dv,Um,t, F"))] > "TARGET_32BIT > && 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[1], <MODE>mode))" > { > @@ -414,15 +432,9 @@ > case 6: /* S register from immediate. */ > return \"vmov.f16\\t%0, %1\t%@ __<fporbf>\"; > case 7: /* S register from memory. */ > - if (TARGET_HAVE_MVE) > - return \"vldr.16\\t%0, %A1\"; > - else > - return \"vld1.16\\t{%z0}, %A1\"; > + return \"vld1.16\\t{%z0}, %A1\"; > case 8: /* Memory from S register. */ > - if (TARGET_HAVE_MVE) > - return \"vstr.16\\t%1, %A0\"; > - else > - return \"vst1.16\\t{%z1}, %A0\"; > + return \"vst1.16\\t{%z1}, %A0\"; > case 9: /* ARM register from constant. */ > { > long bits; > diff --git a/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve-vldstr16-no- > writeback.c b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve-vldstr16-no- > writeback.c > new file mode 100644 > index 0000000..0a69ace > --- /dev/null > +++ b/gcc/testsuite/gcc.target/arm/mve/intrinsics/mve-vldstr16-no- > writeback.c > @@ -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} } } */ > -- > 2.7.4 >