aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYunQiang Su <syq@gcc.gnu.org>2024-04-29 00:33:44 +0800
committerYunQiang Su <syq@debian.org>2024-05-06 12:10:08 +0800
commit7d5d2b879ae7636ca118fb4f3a08b22705cdeacb (patch)
tree8cd054b225ca262d07690118fb86996a8c34ee15
parent70d30dd656957f518b8169a125f6b17f53da8237 (diff)
downloadgcc-7d5d2b879ae7636ca118fb4f3a08b22705cdeacb.zip
gcc-7d5d2b879ae7636ca118fb4f3a08b22705cdeacb.tar.gz
gcc-7d5d2b879ae7636ca118fb4f3a08b22705cdeacb.tar.bz2
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.
-rw-r--r--gcc/expmed.cc12
-rw-r--r--gcc/testsuite/gcc.target/mips/pr113179.c18
2 files changed, 27 insertions, 3 deletions
diff --git a/gcc/expmed.cc b/gcc/expmed.cc
index 4ec035e..20f3a36 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 0000000..f32c5a1
--- /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" } } */