[PATCH] expmed: TRUNCATE value1 if needed in store_bit_field_using_insv

YunQiang Su syq@gcc.gnu.org
Wed Jun 5 14:57:47 GMT 2024


Richard Sandiford <richard.sandiford@arm.com> 于2024年6月5日周三 22:14写道:
>
> YunQiang Su <syq@gcc.gnu.org> writes:
> > PR target/113179.
> >
> > In `store_bit_field_using_insv`, we just use SUBREG if value_mode
> >>= op_mode, while in some ports, a sign_extend will be needed,
> > such as MIPS64:
> >   If either GPR rs or GPR rt does not contain sign-extended 32-bit
> >   values (bits 63..31 equal), then the result of the operation is
> >   UNPREDICTABLE.
> >
> > The problem happens for the code like:
> >   struct xx {
> >         int a:4;
> >         int b:24;
> >         int c:3;
> >         int d:1;
> >   };
> >
> >   void xx (struct xx *a, long long b) {
> >         a->d = b;
> >   }
> >
> > In the above code, the hard register contains `b`, may be note well
> > sign-extended.
> >
> > gcc/
> >       PR target/113179
> >       * expmed.c(store_bit_field_using_insv): TRUNCATE value1 if
> >       needed.
> >
> > gcc/testsuite
> >       PR target/113179
> >       * gcc.target/mips/pr113179.c: New tests.
> > ---
> >  gcc/expmed.cc                            | 12 +++++++++---
> >  gcc/testsuite/gcc.target/mips/pr113179.c | 18 ++++++++++++++++++
> >  2 files changed, 27 insertions(+), 3 deletions(-)
> >  create mode 100644 gcc/testsuite/gcc.target/mips/pr113179.c
> >
> > diff --git a/gcc/expmed.cc b/gcc/expmed.cc
> > index 4ec035e4843..6a582593da8 100644
> > --- a/gcc/expmed.cc
> > +++ b/gcc/expmed.cc
> > @@ -704,9 +704,15 @@ store_bit_field_using_insv (const extraction_insn *insv, rtx op0,
> >           }
> >         else
> >           {
> > -           tmp = gen_lowpart_if_possible (op_mode, value1);
> > -           if (! tmp)
> > -             tmp = gen_lowpart (op_mode, force_reg (value_mode, value1));
> > +           if (targetm.mode_rep_extended (op_mode, value_mode))
> > +             tmp = simplify_gen_unary (TRUNCATE, op_mode,
> > +                                       value1, value_mode);
> > +           else
> > +             {
> > +               tmp = gen_lowpart_if_possible (op_mode, value1);
> > +               if (! tmp)
> > +                 tmp = gen_lowpart (op_mode, force_reg (value_mode, value1));
> > +             }
> >           }
> >         value1 = tmp;
> >       }
>
> I notice this patch is already applied.  Was it approved?  I didn't
> see an approval in my feed or in the archives.
>

Sorry. I was supposed that it only effects MIPS targets since only MIPS defines
  targetm.mode_rep_extended

> Although it might not make any difference on current targets,
> I think the conditional should logically be based on
> TRULY_NOOP_TRUNCATION(_MODES_P) rather than targetm.mode_rep_extended.
>
> TRULY_NOOP_TRUNCATION is a correctness question: can I use subregs
> to do this truncation?  targetm.mode_rep_extended is instead an
> optimisation question: can I assume that a particular extension is free?
> Here we're trying to avoid a subreg for correctness, rather than trying
> to take advantage of a cheap extension.
>
> So I think the code should be:
>
>           if (GET_MODE_SIZE (value_mode) < GET_MODE_SIZE (op_mode))
>             {
>               tmp = simplify_subreg (op_mode, value1, value_mode, 0);
>               if (! tmp)
>                 tmp = simplify_gen_subreg (op_mode,
>                                            force_reg (value_mode, value1),
>                                            value_mode, 0);
>             }
>           else if (GET_MODE_SIZE (op_mode) < GET_MODE_SIZE (value_mode)
>                    && !TRULY_NOOP_TRUNCATION_MODES_P (op_mode, value_mode))

In fact I don't think so. For other targets besides MIPS, it is safe even
    !TRULY_NOOP_TRUNCATION_MODES_P (op_mode, value_mode)
as INS instruction may use the low part of a register safely.

It is only not true on MIPS ISA documents as
     If either GPR rs or GPR rt does not contain sign-extended 32-bit
     values (bits 63..31 equal), then the result of the operation is
     UNPREDICTABLE.

It is very annoying. I haven't noticed a similar problem on any other
ISA documents.
In fact I don't know any real MIPS hardware that is "UNPREDICTABLE" in
this case.

>             tmp = simplify_gen_unary (TRUNCATE, op_mode, value1, value_mode);
>           else
>             {
>               tmp = gen_lowpart_if_possible (op_mode, value1);
>               if (! tmp)
>                 tmp = gen_lowpart (op_mode, force_reg (value_mode, value1));
>             }
>
> (also inclues unnesting of the else).  Could you try changing the code
> to do that and push the change if it works?
>
> IMO the patch (in that form) is OK for backports after it has had a
> couple of weeks on trunk.
>
> Thanks,
> Richard
>
> > diff --git a/gcc/testsuite/gcc.target/mips/pr113179.c b/gcc/testsuite/gcc.target/mips/pr113179.c
> > new file mode 100644
> > index 00000000000..f32c5a16765
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/mips/pr113179.c
> > @@ -0,0 +1,18 @@
> > +/* Check if the operand of INS is sign-extended on MIPS64.  */
> > +/* { dg-options "-mips64r2 -mabi=64" } */
> > +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> > +
> > +struct xx {
> > +        int a:1;
> > +        int b:24;
> > +        int c:6;
> > +        int d:1;
> > +};
> > +
> > +long long xx (struct xx *a, long long b) {
> > +        a->d = b;
> > +        return b+1;
> > +}
> > +
> > +/* { dg-final { scan-assembler "\tsll\t\\\$3,\\\$5,0" } } */
> > +/* { dg-final { scan-assembler "\tdaddiu\t\\\$2,\\\$5,1" } } */


More information about the Gcc-patches mailing list