+2019-04-15 Leszek Swirski <leszeks@google.com>
+
+ * amd64-tdep.c (amd64_classify_aggregate): Use cp_pass_by_reference
+ rather than a hand-rolled POD check when checking for forced MEMORY
+ classification.
+
2019-04-15 Alan Hayward <alan.hayward@arm.com>
* aarch64-linux-nat.c (store_sveregs_to_thread): Set vector length.
static void amd64_classify (struct type *type, enum amd64_reg_class theclass[2]);
-/* Return non-zero if TYPE is a non-POD structure or union type. */
+/* Return true if TYPE is a structure or union with unaligned fields. */
-static int
-amd64_non_pod_p (struct type *type)
+static bool
+amd64_has_unaligned_fields (struct type *type)
{
- /* ??? A class with a base class certainly isn't POD, but does this
- catch all non-POD structure types? */
- if (TYPE_CODE (type) == TYPE_CODE_STRUCT && TYPE_N_BASECLASSES (type) > 0)
- return 1;
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION)
+ {
+ for (int i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i));
+ int bitpos = TYPE_FIELD_BITPOS (type, i);
+ int align = type_align(subtype);
- return 0;
+ /* Ignore static fields, or empty fields, for example nested
+ empty structures. */
+ if (field_is_static (&TYPE_FIELD (type, i))
+ || (TYPE_FIELD_BITSIZE (type, i) == 0
+ && TYPE_LENGTH (subtype) == 0))
+ continue;
+
+ if (bitpos % 8 != 0)
+ return true;
+
+ int bytepos = bitpos / 8;
+ if (bytepos % align != 0)
+ return true;
+
+ if (amd64_has_unaligned_fields(subtype))
+ return true;
+ }
+ }
+
+ return false;
}
/* Classify TYPE according to the rules for aggregate (structures and
static void
amd64_classify_aggregate (struct type *type, enum amd64_reg_class theclass[2])
{
- /* 1. If the size of an object is larger than two eightbytes, or in
- C++, is a non-POD structure or union type, or contains
+ /* 1. If the size of an object is larger than two eightbytes, or it has
unaligned fields, it has class memory. */
- if (TYPE_LENGTH (type) > 16 || amd64_non_pod_p (type))
+ if (TYPE_LENGTH (type) > 16 || amd64_has_unaligned_fields (type))
{
theclass[0] = theclass[1] = AMD64_MEMORY;
return;
+2019-04-15 Leszek Swirski <leszeks@google.com>
+
+ * gdb.arch/amd64-eval.cc: New file.
+ * gdb.arch/amd64-eval.exp: New file.
+
2019-04-11 Alan Hayward <alan.hayward@arm.com>
* gdb.server/sysroot.c: New test.
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2019 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cassert>
+
+/* A simple structure with a single integer field. Should be returned in
+ a register. */
+struct SimpleBase
+{
+ SimpleBase (int32_t x) : x (x) {}
+
+ int32_t x;
+};
+
+/* A simple structure derived from the simple base. Should be returned in
+ a register. */
+struct SimpleDerived : public SimpleBase
+{
+ SimpleDerived (int32_t x) : SimpleBase (x) {}
+};
+
+/* A structure derived from the simple base with a non-trivial destructor.
+ Should be returned on the stack. */
+struct NonTrivialDestructorDerived : public SimpleBase
+{
+ NonTrivialDestructorDerived (int32_t x) : SimpleBase (x) {}
+ ~NonTrivialDestructorDerived() { x = 1; }
+};
+
+/* A structure with unaligned fields. Should be returned on the stack. */
+struct UnalignedFields
+{
+ UnalignedFields (int32_t x, double y) : x (x), y (y) {}
+
+ int32_t x;
+ double y;
+} __attribute__((packed));
+
+/* A structure with unaligned fields in its base class. Should be
+ returned on the stack. */
+struct UnalignedFieldsInBase : public UnalignedFields
+{
+ UnalignedFieldsInBase (int32_t x, double y, int32_t x2)
+ : UnalignedFields (x, y), x2 (x2) {}
+
+ int32_t x2;
+};
+
+class Foo
+{
+public:
+ SimpleBase
+ return_simple_base (int32_t x)
+ {
+ assert (this->tag == EXPECTED_TAG);
+ return SimpleBase (x);
+ }
+
+ SimpleDerived
+ return_simple_derived (int32_t x)
+ {
+ assert (this->tag == EXPECTED_TAG);
+ return SimpleDerived (x);
+ }
+
+ NonTrivialDestructorDerived
+ return_non_trivial_destructor (int32_t x)
+ {
+ assert (this->tag == EXPECTED_TAG);
+ return NonTrivialDestructorDerived (x);
+ }
+
+ UnalignedFields
+ return_unaligned (int32_t x, double y)
+ {
+ assert (this->tag == EXPECTED_TAG);
+ return UnalignedFields (x, y);
+ }
+
+ UnalignedFieldsInBase
+ return_unaligned_in_base (int32_t x, double y, int32_t x2)
+ {
+ assert (this->tag == EXPECTED_TAG);
+ return UnalignedFieldsInBase (x, y, x2);
+ }
+
+private:
+ /* Use a tag to detect if the "this" value is correct. */
+ static const int EXPECTED_TAG = 0xF00F00F0;
+ int tag = EXPECTED_TAG;
+};
+
+int
+main (int argc, char *argv[])
+{
+ Foo foo;
+ foo.return_simple_base(1);
+ foo.return_simple_derived(2);
+ foo.return_non_trivial_destructor(3);
+ foo.return_unaligned(4, 5);
+ foo.return_unaligned_in_base(6, 7, 8);
+ return 0; // break-here
+}
--- /dev/null
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This testcase exercises evaluation with amd64 calling conventions.
+
+standard_testfile .cc
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile \
+ { debug c++ }] } {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break-here"]
+gdb_continue_to_breakpoint "break-here"
+
+gdb_test "call foo.return_simple_base(12)" \
+ " = {x = 12}"
+gdb_test "call foo.return_simple_derived(34)" \
+ " = {<SimpleBase> = {x = 34}, <No data fields>}"
+gdb_test "call foo.return_non_trivial_destructor(56)" \
+ " = {<SimpleBase> = {x = 56}, <No data fields>}"
+gdb_test "call foo.return_unaligned(78, 9.25)" \
+ " = {x = 78, y = 9.25}"
+gdb_test "call foo.return_unaligned_in_base(23, 4.5, 67)" \
+ " = {<UnalignedFields> = {x = 23, y = 4.5}, x2 = 67}"