expr.c (store_field): In the bitfield case...
authorEric Botcazou <ebotcazou@adacore.com>
Mon, 9 Jan 2017 22:17:17 +0000 (22:17 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Mon, 9 Jan 2017 22:17:17 +0000 (22:17 +0000)
* expr.c (store_field): In the bitfield case, if the value comes from
a function call and is of an aggregate type returned in registers, do
not modify the field mode; extract the value in all cases if the mode
is BLKmode and the size is not larger than a word.

From-SVN: r244249

14 files changed:
gcc/ChangeLog
gcc/expr.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/opt/call2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/opt/call3.C [new file with mode: 0644]
gcc/testsuite/gnat.dg/array26.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/array26_pkg.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/array26_pkg.ads [new file with mode: 0644]
gcc/testsuite/gnat.dg/array27.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/array27_pkg.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/array27_pkg.ads [new file with mode: 0644]
gcc/testsuite/gnat.dg/array28.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/array28_pkg.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/array28_pkg.ads [new file with mode: 0644]

index 4b2bd761dcc5a1a5425b4b9a4617ab25b0cfe5db..5f728841fe8c60797058bdc9ea0fcf99862d2a8f 100644 (file)
@@ -1,3 +1,10 @@
+2017-01-09  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * expr.c (store_field): In the bitfield case, if the value comes from
+       a function call and is of an aggregate type returned in registers, do
+       not modify the field mode; extract the value in all cases if the mode
+       is BLKmode and the size is not larger than a word.
+
 2017-01-09  Dominique d'Humieres  <dominiq@lps.ens.fr>
 
        PR target/71017
index a7692157a5fb84e6d501c3c46536645c0b251df3..e1d70c3b189d121e4d2a6ed9c08772f7d20505e9 100644 (file)
@@ -6888,33 +6888,30 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
       if (GET_CODE (temp) == PARALLEL)
        {
          HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
-         rtx temp_target;
-         if (mode == BLKmode || mode == VOIDmode)
-           mode = smallest_mode_for_size (size * BITS_PER_UNIT, MODE_INT);
-         temp_target = gen_reg_rtx (mode);
+         machine_mode temp_mode
+           = smallest_mode_for_size (size * BITS_PER_UNIT, MODE_INT);
+         rtx temp_target = gen_reg_rtx (temp_mode);
          emit_group_store (temp_target, temp, TREE_TYPE (exp), size);
          temp = temp_target;
        }
-      else if (mode == BLKmode)
+
+      /* Handle calls that return BLKmode values in registers.  */
+      else if (mode == BLKmode && REG_P (temp) && TREE_CODE (exp) == CALL_EXPR)
        {
-         /* Handle calls that return BLKmode values in registers.  */
-         if (REG_P (temp) && TREE_CODE (exp) == CALL_EXPR)
-           {
-             rtx temp_target = gen_reg_rtx (GET_MODE (temp));
-             copy_blkmode_from_reg (temp_target, temp, TREE_TYPE (exp));
-             temp = temp_target;
-           }
-         else
-           {
-             HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
-             rtx temp_target;
-             mode = smallest_mode_for_size (size * BITS_PER_UNIT, MODE_INT);
-             temp_target = gen_reg_rtx (mode);
-             temp_target
-               = extract_bit_field (temp, size * BITS_PER_UNIT, 0, 1,
-                                    temp_target, mode, mode, false);
-             temp = temp_target;
-           }
+         rtx temp_target = gen_reg_rtx (GET_MODE (temp));
+         copy_blkmode_from_reg (temp_target, temp, TREE_TYPE (exp));
+         temp = temp_target;
+       }
+
+      /* The behavior of store_bit_field is awkward when mode is BLKmode:
+        it always takes its value from the lsb up to the word size but
+        expects it left justified beyond it.  At this point TEMP is left
+        justified so extract the value in the former case.  */
+      if (mode == BLKmode && bitsize <= BITS_PER_WORD)
+       {
+         machine_mode temp_mode = smallest_mode_for_size (bitsize, MODE_INT);
+         temp = extract_bit_field (temp, bitsize, 0, 1, NULL_RTX, temp_mode,
+                                   temp_mode, false);
        }
 
       /* Store the value in the bitfield.  */
index 60f5c28aa8271068815ef48882a801ab5144cb2b..724763f65130af9a8337eddbd7eff03a7f8713ef 100644 (file)
@@ -1,3 +1,14 @@
+2017-01-09  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * g++.dg/opt/call2.C: New test.
+       * g++.dg/opt/call3.C: Likewise.
+       * gnat.dg/array26.adb: New test.
+       * gnat.dg/array26_pkg.ad[sb]: New helper.
+       * gnat.dg/array27.adb: New test.
+       * gnat.dg/array27_pkg.ad[sb]: New helper.
+       * gnat.dg/array28.adb: New test.
+       * gnat.dg/array28_pkg.ad[sb]: New helper.
+
 2017-01-09  Jakub Jelinek  <jakub@redhat.com>
 
        PR translation/79019
diff --git a/gcc/testsuite/g++.dg/opt/call2.C b/gcc/testsuite/g++.dg/opt/call2.C
new file mode 100644 (file)
index 0000000..1b4d4b3
--- /dev/null
@@ -0,0 +1,34 @@
+// { dg-do run }
+// { dg-options "-O" }
+
+struct Foo
+{
+  Foo() : a(1), b(1), c('a') {}
+  int a;
+  int b;
+  char c;
+};
+
+static Foo copy_foo(Foo) __attribute__((noinline, noclone));
+
+static Foo copy_foo(Foo A)
+{
+  return A;
+}
+
+struct Bar : Foo
+{
+  Bar(Foo t) : Foo(copy_foo(t)) {}
+};
+
+Foo F;
+
+int main (void)
+{
+  Bar B (F);
+
+  if (B.a != 1 || B.b != 1 || B.c != 'a')
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/opt/call3.C b/gcc/testsuite/g++.dg/opt/call3.C
new file mode 100644 (file)
index 0000000..9aac7e2
--- /dev/null
@@ -0,0 +1,33 @@
+// { dg-do run }
+// { dg-options "-O" }
+
+struct Foo
+{
+  Foo() : a(1), c('a') {}
+  short int a;
+  char c;
+};
+
+static Foo copy_foo(Foo) __attribute__((noinline, noclone));
+
+static Foo copy_foo(Foo A)
+{
+  return A;
+}
+
+struct Bar : Foo
+{
+  Bar(Foo t) : Foo(copy_foo(t)) {}
+};
+
+Foo F;
+
+int main (void)
+{
+  Bar B (F);
+
+  if (B.a != 1 || B.c != 'a')
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gnat.dg/array26.adb b/gcc/testsuite/gnat.dg/array26.adb
new file mode 100644 (file)
index 0000000..659d596
--- /dev/null
@@ -0,0 +1,22 @@
+-- { dg-do run }
+-- { dg-options "-O" }
+
+with Array26_Pkg; use Array26_Pkg;
+
+procedure Array26 is
+
+  function Get return Outer_type is
+    Ret : Outer_Type;
+  begin
+    Ret (Inner_Type'Range) := F;
+    return Ret;
+  end;
+
+  A : Outer_Type := Get;
+  B : Inner_Type := A (Inner_Type'Range);
+
+begin
+  if B /= "123" then
+    raise Program_Error;
+  end if;
+end;
diff --git a/gcc/testsuite/gnat.dg/array26_pkg.adb b/gcc/testsuite/gnat.dg/array26_pkg.adb
new file mode 100644 (file)
index 0000000..f324bd2
--- /dev/null
@@ -0,0 +1,8 @@
+package body Array26_Pkg is
+
+  function F return Inner_Type is
+  begin
+    return "123";
+  end;
+
+end Array26_Pkg;
diff --git a/gcc/testsuite/gnat.dg/array26_pkg.ads b/gcc/testsuite/gnat.dg/array26_pkg.ads
new file mode 100644 (file)
index 0000000..ae84a74
--- /dev/null
@@ -0,0 +1,8 @@
+package Array26_Pkg is
+
+  subtype Outer_Type is String (1 .. 4);
+  subtype Inner_Type is String (1 .. 3);
+
+  function F return Inner_Type;
+
+end Array26_Pkg;
diff --git a/gcc/testsuite/gnat.dg/array27.adb b/gcc/testsuite/gnat.dg/array27.adb
new file mode 100644 (file)
index 0000000..db821c5
--- /dev/null
@@ -0,0 +1,22 @@
+-- { dg-do run }
+-- { dg-options "-O" }
+
+with Array27_Pkg; use Array27_Pkg;
+
+procedure Array27 is
+
+  function Get return Outer_type is
+    Ret : Outer_Type;
+  begin
+    Ret (Inner_Type'Range) := F;
+    return Ret;
+  end;
+
+  A : Outer_Type := Get;
+  B : Inner_Type := A (Inner_Type'Range);
+
+begin
+    if B /= "123" then
+    raise Program_Error;
+  end if;
+end;
diff --git a/gcc/testsuite/gnat.dg/array27_pkg.adb b/gcc/testsuite/gnat.dg/array27_pkg.adb
new file mode 100644 (file)
index 0000000..92c61b9
--- /dev/null
@@ -0,0 +1,8 @@
+package body Array27_Pkg is
+
+  function F return Inner_Type is
+  begin
+    return "123";
+  end;
+
+end Array27_Pkg;
diff --git a/gcc/testsuite/gnat.dg/array27_pkg.ads b/gcc/testsuite/gnat.dg/array27_pkg.ads
new file mode 100644 (file)
index 0000000..1473fbb
--- /dev/null
@@ -0,0 +1,8 @@
+package Array27_Pkg is
+
+  subtype Outer_Type is String (1 .. 8);
+  subtype Inner_Type is String (1 .. 3);
+
+  function F return Inner_Type;
+
+end Array27_Pkg;
diff --git a/gcc/testsuite/gnat.dg/array28.adb b/gcc/testsuite/gnat.dg/array28.adb
new file mode 100644 (file)
index 0000000..aa31445
--- /dev/null
@@ -0,0 +1,22 @@
+-- { dg-do run }
+-- { dg-options "-O" }
+
+with Array28_Pkg; use Array28_Pkg;
+
+procedure Array28 is
+
+  function Get return Outer_type is
+    Ret : Outer_Type;
+  begin
+    Ret (Inner_Type'Range) := F;
+    return Ret;
+  end;
+
+  A : Outer_Type := Get;
+  B : Inner_Type := A (Inner_Type'Range);
+
+begin
+  if B /= "12345" then
+    raise Program_Error;
+  end if;
+end;
diff --git a/gcc/testsuite/gnat.dg/array28_pkg.adb b/gcc/testsuite/gnat.dg/array28_pkg.adb
new file mode 100644 (file)
index 0000000..726810b
--- /dev/null
@@ -0,0 +1,8 @@
+package body Array28_Pkg is
+
+  function F return Inner_Type is
+  begin
+    return "12345";
+  end;
+
+end Array28_Pkg;
diff --git a/gcc/testsuite/gnat.dg/array28_pkg.ads b/gcc/testsuite/gnat.dg/array28_pkg.ads
new file mode 100644 (file)
index 0000000..6189010
--- /dev/null
@@ -0,0 +1,8 @@
+package Array28_Pkg is
+
+  subtype Outer_Type is String (1 .. 8);
+  subtype Inner_Type is String (1 .. 5);
+
+  function F return Inner_Type;
+
+end Array28_Pkg;