expmed: TRUNCATE value1 if needed in store_bit_field_using_insv

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.cc(store_bit_field_using_insv): TRUNCATE value1 if
	needed.

gcc/testsuite
	PR target/113179
	* gcc.target/mips/pr113179.c: New tests.
This commit is contained in:
YunQiang Su 2024-04-29 00:33:44 +08:00 committed by YunQiang Su
parent 70d30dd656
commit 7d5d2b879a
2 changed files with 27 additions and 3 deletions

View file

@ -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) != UNKNOWN)
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;
}

View file

@ -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" } } */