From 7d5d2b879ae7636ca118fb4f3a08b22705cdeacb Mon Sep 17 00:00:00 2001 From: YunQiang Su Date: Mon, 29 Apr 2024 00:33:44 +0800 Subject: [PATCH] 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. --- 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..20f3a36f38c 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) != 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; } 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" } } */