Aaron Merey bb289a
From e39336df6588c3f9853be7d02819aee262ba2121 Mon Sep 17 00:00:00 2001
Aaron Merey bb289a
From: Mark Wielaard <mark@klomp.org>
Aaron Merey bb289a
Date: Tue, 19 Mar 2024 22:43:10 +0000
Aaron Merey bb289a
Subject: [PATCH] riscv: Partial implementation of flatten_aggregate
Aaron Merey bb289a
Aaron Merey bb289a
dwfl_module_return_value_location would fail on riscv for functions
Aaron Merey bb289a
which return a (small) struct. This patch implements the simplest
Aaron Merey bb289a
cases of flatten_aggregate in backends/riscv_retval.c. It just handles
Aaron Merey bb289a
structs containing one or two members of the same base type which fit
Aaron Merey bb289a
completely or in pieces in one or two general or floating point
Aaron Merey bb289a
registers.
Aaron Merey bb289a
Aaron Merey bb289a
It also adds a specific test case run-funcretval-struct.sh containing
Aaron Merey bb289a
small structs of ints, longs, floats and doubles. All these testscases
Aaron Merey bb289a
now work for riscv. There is already a slightly more extensive
Aaron Merey bb289a
testcase for this in tests/run-funcretval.sh but that only has a
Aaron Merey bb289a
testcase for aarch64.
Aaron Merey bb289a
Aaron Merey bb289a
	 * backends/riscv_retval.c (flatten_aggregate_arg): Implement
Aaron Merey bb289a
         for the simple cases where we have a struct with one or two
Aaron Merey bb289a
         members of the same base type.
Aaron Merey bb289a
	 (pass_by_flattened_arg): Likewise. Call either
Aaron Merey bb289a
	 pass_in_gpr_lp64 or pass_in_fpr_lp64d.
Aaron Merey bb289a
	 (riscv_return_value_location_lp64ifd): Call
Aaron Merey bb289a
	 flatten_aggregate_arg including size.
Aaron Merey bb289a
	 * tests/Makefile.am (TESTS): Add run-funcretval-struct.sh
Aaron Merey bb289a
	 and run-funcretval-struct-native.sh.
Aaron Merey bb289a
	 (check_PROGRAMS): Add funcretval_test_struct.
Aaron Merey bb289a
	 (funcretval_test_struct_SOURCES): New.
Aaron Merey bb289a
	 (EXTRA_DIST): Add run-funcretval-struct.sh,
Aaron Merey bb289a
	 funcretval_test_struct_riscv.bz2 and
Aaron Merey bb289a
	 run-funcretval-struct-native.sh.
Aaron Merey bb289a
	 * tests/funcretval_test_struct_riscv.bz2: New test binary.
Aaron Merey bb289a
	 * tests/run-funcretval-struct-native.sh: New test.
Aaron Merey bb289a
	 * tests/run-funcretval-struct.sh: Likewise.
Aaron Merey bb289a
Aaron Merey bb289a
https://sourceware.org/bugzilla/show_bug.cgi?id=31142
Aaron Merey bb289a
Aaron Merey bb289a
Signed-off-by: Mark Wielaard <mark@klomp.org>
Aaron Merey bb289a
---
Aaron Merey bb289a
 backends/riscv_retval.c                | 123 ++++++++++++++++++++++---
Aaron Merey bb289a
 tests/Makefile.am                      |   7 ++
Aaron Merey bb289a
 tests/funcretval_test_struct.c         |  86 +++++++++++++++++
Aaron Merey bb289a
 tests/funcretval_test_struct_riscv.bz2 | Bin 0 -> 3821 bytes
Aaron Merey bb289a
 tests/run-funcretval-struct-native.sh  |  22 +++++
Aaron Merey bb289a
 tests/run-funcretval-struct.sh         |  35 +++++++
Aaron Merey bb289a
 6 files changed, 262 insertions(+), 11 deletions(-)
Aaron Merey bb289a
 create mode 100644 tests/funcretval_test_struct.c
Aaron Merey bb289a
 create mode 100755 tests/funcretval_test_struct_riscv.bz2
Aaron Merey bb289a
 create mode 100755 tests/run-funcretval-struct-native.sh
Aaron Merey bb289a
 create mode 100755 tests/run-funcretval-struct.sh
Aaron Merey bb289a
Aaron Merey bb289a
Fedora NOTE: Both the riscv specific test files weren't included
Aaron Merey bb289a
             (funcretval_test_struct_riscv.bz2 and run-funcretval-struct.sh)
Aaron Merey bb289a
             Because it contained a binary test. The native test is included
Aaron Merey bb289a
             though.
Aaron Merey bb289a
Aaron Merey bb289a
diff --git a/backends/riscv_retval.c b/backends/riscv_retval.c
Aaron Merey bb289a
index 0a1e02f81cd2..50c451a4ba32 100644
Aaron Merey bb289a
--- a/backends/riscv_retval.c
Aaron Merey bb289a
+++ b/backends/riscv_retval.c
Aaron Merey bb289a
@@ -1,6 +1,7 @@
Aaron Merey bb289a
 /* Function return value location for Linux/RISC-V ABI.
Aaron Merey bb289a
    Copyright (C) 2018 Sifive, Inc.
Aaron Merey bb289a
    Copyright (C) 2013 Red Hat, Inc.
Aaron Merey bb289a
+   Copyright (C) 2024 Mark J. Wielaard <mark@klomp.org>
Aaron Merey bb289a
    This file is part of elfutils.
Aaron Merey bb289a
 
Aaron Merey bb289a
    This file is free software; you can redistribute it and/or modify
Aaron Merey bb289a
@@ -105,23 +106,123 @@ pass_in_fpr_lp64d (const Dwarf_Op **locp, Dwarf_Word size)
Aaron Merey bb289a
   return size <= 8 ? 1 : 4;
Aaron Merey bb289a
 }
Aaron Merey bb289a
 
Aaron Merey bb289a
+/* Checks if we can "flatten" the given type, Only handles the simple
Aaron Merey bb289a
+   cases where we have a struct with one or two the same base type
Aaron Merey bb289a
+   elements.  */
Aaron Merey bb289a
 static int
Aaron Merey bb289a
-flatten_aggregate_arg (Dwarf_Die *typedie __attribute__ ((unused)),
Aaron Merey bb289a
-		       Dwarf_Die *arg0 __attribute__ ((unused)),
Aaron Merey bb289a
-		       Dwarf_Die *arg1 __attribute__ ((unused)))
Aaron Merey bb289a
+flatten_aggregate_arg (Dwarf_Die *typedie,
Aaron Merey bb289a
+		       Dwarf_Word size,
Aaron Merey bb289a
+		       Dwarf_Die *arg0,
Aaron Merey bb289a
+		       Dwarf_Die *arg1)
Aaron Merey bb289a
 {
Aaron Merey bb289a
-  /* ??? */
Aaron Merey bb289a
+  int tag0, tag1;
Aaron Merey bb289a
+  Dwarf_Die member;
Aaron Merey bb289a
+  Dwarf_Word encoding0, encoding1;
Aaron Merey bb289a
+  Dwarf_Attribute attr;
Aaron Merey bb289a
+  Dwarf_Word size0, size1;
Aaron Merey bb289a
+
Aaron Merey bb289a
+  if (size < 8 || size > 16)
Aaron Merey bb289a
+    return 0;
Aaron Merey bb289a
+
Aaron Merey bb289a
+  if (dwarf_child (typedie, arg0) != 0)
Aaron Merey bb289a
+    return 0;
Aaron Merey bb289a
+
Aaron Merey bb289a
+  tag0 = dwarf_tag (arg0);
Aaron Merey bb289a
+  while (tag0 != -1 && tag0 != DW_TAG_member)
Aaron Merey bb289a
+    {
Aaron Merey bb289a
+      if (dwarf_siblingof (arg0, arg0) != 0)
Aaron Merey bb289a
+	return 0;
Aaron Merey bb289a
+      tag0 = dwarf_tag (arg0);
Aaron Merey bb289a
+    }
Aaron Merey bb289a
+
Aaron Merey bb289a
+  if (tag0 != DW_TAG_member)
Aaron Merey bb289a
+    return 0;
Aaron Merey bb289a
+
Aaron Merey bb289a
+  /* Remember where we are.  */
Aaron Merey bb289a
+  member = *arg0;
Aaron Merey bb289a
+
Aaron Merey bb289a
+  tag0 = dwarf_peeled_die_type (arg0, arg0);
Aaron Merey bb289a
+  if (tag0 != DW_TAG_base_type)
Aaron Merey bb289a
+    return 0;
Aaron Merey bb289a
+
Aaron Merey bb289a
+  if (dwarf_attr_integrate (arg0, DW_AT_encoding, &attr) == NULL
Aaron Merey bb289a
+      || dwarf_formudata (&attr, &encoding0) != 0)
Aaron Merey bb289a
+    return 0;
Aaron Merey bb289a
+
Aaron Merey bb289a
+  if (dwarf_bytesize_aux (arg0, &size0) != 0)
Aaron Merey bb289a
+    return 0;
Aaron Merey bb289a
+
Aaron Merey bb289a
+  if (size == size0)
Aaron Merey bb289a
+    return 1; /* This one member is the whole size. */
Aaron Merey bb289a
+
Aaron Merey bb289a
+  if (size != 2 * size0)
Aaron Merey bb289a
+    return 0; /* We only handle two of the same.  */
Aaron Merey bb289a
+
Aaron Merey bb289a
+  /* Look for another member with the same encoding.  */
Aaron Merey bb289a
+  if (dwarf_siblingof (&member, arg1) != 0)
Aaron Merey bb289a
+    return 0;
Aaron Merey bb289a
+
Aaron Merey bb289a
+  tag1 = dwarf_tag (arg1);
Aaron Merey bb289a
+  while (tag1 != -1 && tag1 != DW_TAG_member)
Aaron Merey bb289a
+    {
Aaron Merey bb289a
+      if (dwarf_siblingof (arg1, arg1) != 0)
Aaron Merey bb289a
+	return 0;
Aaron Merey bb289a
+      tag1 = dwarf_tag (arg1);
Aaron Merey bb289a
+    }
Aaron Merey bb289a
+
Aaron Merey bb289a
+  if (tag1 != DW_TAG_member)
Aaron Merey bb289a
+    return 0;
Aaron Merey bb289a
+
Aaron Merey bb289a
+  tag1 = dwarf_peeled_die_type (arg1, arg1);
Aaron Merey bb289a
+  if (tag1 != DW_TAG_base_type)
Aaron Merey bb289a
+    return 0; /* We can only handle two equal base types for now. */
Aaron Merey bb289a
+
Aaron Merey bb289a
+  if (dwarf_attr_integrate (arg1, DW_AT_encoding, &attr) == NULL
Aaron Merey bb289a
+      || dwarf_formudata (&attr, &encoding1) != 0
Aaron Merey bb289a
+      || encoding0 != encoding1)
Aaron Merey bb289a
+    return 0; /* We can only handle two of the same for now. */
Aaron Merey bb289a
+
Aaron Merey bb289a
+  if (dwarf_bytesize_aux (arg1, &size1) != 0)
Aaron Merey bb289a
+    return 0;
Aaron Merey bb289a
+
Aaron Merey bb289a
+  if (size0 != size1)
Aaron Merey bb289a
+    return 0; /* We can only handle two of the same for now. */
Aaron Merey bb289a
+
Aaron Merey bb289a
   return 1;
Aaron Merey bb289a
 }
Aaron Merey bb289a
 
Aaron Merey bb289a
+/* arg0 and arg1 should be the peeled die types found by
Aaron Merey bb289a
+   flatten_aggregate_arg.  */
Aaron Merey bb289a
 static int
Aaron Merey bb289a
-pass_by_flattened_arg (const Dwarf_Op **locp __attribute__ ((unused)),
Aaron Merey bb289a
-		       Dwarf_Word size __attribute__ ((unused)),
Aaron Merey bb289a
-		       Dwarf_Die *arg0 __attribute__ ((unused)),
Aaron Merey bb289a
-		       Dwarf_Die *arg1 __attribute__ ((unused)))
Aaron Merey bb289a
+pass_by_flattened_arg (const Dwarf_Op **locp,
Aaron Merey bb289a
+		       Dwarf_Word size,
Aaron Merey bb289a
+		       Dwarf_Die *arg0,
Aaron Merey bb289a
+		       Dwarf_Die *arg1 __attribute__((unused)))
Aaron Merey bb289a
 {
Aaron Merey bb289a
-  /* ??? */
Aaron Merey bb289a
-  return -2;
Aaron Merey bb289a
+  /* For now we just assume arg0 and arg1 are the same type and
Aaron Merey bb289a
+     encoding.  */
Aaron Merey bb289a
+  Dwarf_Word encoding;
Aaron Merey bb289a
+  Dwarf_Attribute attr;
Aaron Merey bb289a
+
Aaron Merey bb289a
+  if (dwarf_attr_integrate (arg0, DW_AT_encoding, &attr) == NULL
Aaron Merey bb289a
+      || dwarf_formudata (&attr, &encoding) != 0)
Aaron Merey bb289a
+    return -1;
Aaron Merey bb289a
+
Aaron Merey bb289a
+  switch (encoding)
Aaron Merey bb289a
+    {
Aaron Merey bb289a
+    case DW_ATE_boolean:
Aaron Merey bb289a
+    case DW_ATE_signed:
Aaron Merey bb289a
+    case DW_ATE_unsigned:
Aaron Merey bb289a
+    case DW_ATE_unsigned_char:
Aaron Merey bb289a
+    case DW_ATE_signed_char:
Aaron Merey bb289a
+      return pass_in_gpr_lp64 (locp, size);
Aaron Merey bb289a
+
Aaron Merey bb289a
+    case DW_ATE_float:
Aaron Merey bb289a
+      return pass_in_fpr_lp64d (locp, size);
Aaron Merey bb289a
+
Aaron Merey bb289a
+    default:
Aaron Merey bb289a
+      return -1;
Aaron Merey bb289a
+    }
Aaron Merey bb289a
 }
Aaron Merey bb289a
 
Aaron Merey bb289a
 int
Aaron Merey bb289a
@@ -158,7 +259,7 @@ riscv_return_value_location_lp64ifd (int fp, Dwarf_Die *functypedie,
Aaron Merey bb289a
 	 provided the floating-point real is no more than FLEN bits wide and
Aaron Merey bb289a
 	 the integer is no more than XLEN bits wide.  */
Aaron Merey bb289a
       if (tag == DW_TAG_structure_type
Aaron Merey bb289a
-	  && flatten_aggregate_arg (&typedie, &arg0, &arg1))
Aaron Merey bb289a
+	  && flatten_aggregate_arg (&typedie, size, &arg0, &arg1))
Aaron Merey bb289a
 	return pass_by_flattened_arg (locp, size, &arg0, &arg1);
Aaron Merey bb289a
       /* Aggregates larger than 2*XLEN bits are passed by reference.  */
Aaron Merey bb289a
       else if (size > 16)
Aaron Merey bb289a
diff --git a/tests/Makefile.am b/tests/Makefile.am
Aaron Merey bb289a
index 9141074fe44c..9315ec3bbe4c 100644
Aaron Merey bb289a
--- a/tests/Makefile.am
Aaron Merey bb289a
+++ b/tests/Makefile.am
Aaron Merey bb289a
@@ -284,6 +285,10 @@ funcretval_test__11_SOURCES = funcretval_test++11.cxx
Aaron Merey bb289a
 TESTS += run-funcretval++11.sh
Aaron Merey bb289a
 endif
Aaron Merey bb289a
 
Aaron Merey bb289a
+check_PROGRAMS += funcretval_test_struct
Aaron Merey bb289a
+funcretval_test_struct_SOURCES = funcretval_test_struct.c
Aaron Merey bb289a
+TESTS += run-funcretval-struct-native.sh
Aaron Merey bb289a
+
Aaron Merey bb289a
 EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
Aaron Merey bb289a
 	     run-ar-N.sh \
Aaron Merey bb289a
 	     run-show-die-info.sh run-get-files.sh run-get-lines.sh \
Aaron Merey bb289a
@@ -635,6 +641,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
Aaron Merey bb289a
 	     testfile_nvidia_linemap.bz2 \
Aaron Merey bb289a
 	     testfile-largealign.o.bz2 run-strip-largealign.sh \
Aaron Merey bb289a
 	     run-funcretval++11.sh \
Aaron Merey bb289a
+	     run-funcretval-struct-native.sh \
Aaron Merey bb289a
 	     test-ar-duplicates.a.bz2 \
Aaron Merey bb289a
 	     run-dwfl-core-noncontig.sh testcore-noncontig.bz2 \
Aaron Merey bb289a
 	     testfile-dwarf5-line-clang.bz2 \
Aaron Merey bb289a
diff --git a/tests/funcretval_test_struct.c b/tests/funcretval_test_struct.c
Aaron Merey bb289a
new file mode 100644
Aaron Merey bb289a
index 000000000000..df94bde0a42d
Aaron Merey bb289a
--- /dev/null
Aaron Merey bb289a
+++ b/tests/funcretval_test_struct.c
Aaron Merey bb289a
@@ -0,0 +1,86 @@
Aaron Merey bb289a
+/* Copyright (C) 2024 Mark J. Wielaard <mark@klomp.org>
Aaron Merey bb289a
+   This file is part of elfutils.
Aaron Merey bb289a
+
Aaron Merey bb289a
+   This file is free software; you can redistribute it and/or modify
Aaron Merey bb289a
+   it under the terms of the GNU General Public License as published by
Aaron Merey bb289a
+   the Free Software Foundation; either version 3 of the License, or
Aaron Merey bb289a
+   (at your option) any later version.
Aaron Merey bb289a
+
Aaron Merey bb289a
+   elfutils is distributed in the hope that it will be useful, but
Aaron Merey bb289a
+   WITHOUT ANY WARRANTY; without even the implied warranty of
Aaron Merey bb289a
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Aaron Merey bb289a
+   GNU General Public License for more details.
Aaron Merey bb289a
+
Aaron Merey bb289a
+   You should have received a copy of the GNU General Public License
Aaron Merey bb289a
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Aaron Merey bb289a
+
Aaron Merey bb289a
+typedef struct
Aaron Merey bb289a
+  {
Aaron Merey bb289a
+    int q;
Aaron Merey bb289a
+    int r;
Aaron Merey bb289a
+  } div_t;
Aaron Merey bb289a
+
Aaron Merey bb289a
+typedef struct
Aaron Merey bb289a
+  {
Aaron Merey bb289a
+    long q;
Aaron Merey bb289a
+    long r;
Aaron Merey bb289a
+  } ldiv_t;
Aaron Merey bb289a
+
Aaron Merey bb289a
+typedef struct
Aaron Merey bb289a
+  {
Aaron Merey bb289a
+    float x;
Aaron Merey bb289a
+    float y;
Aaron Merey bb289a
+  } point_t;
Aaron Merey bb289a
+
Aaron Merey bb289a
+typedef struct
Aaron Merey bb289a
+  {
Aaron Merey bb289a
+    double x;
Aaron Merey bb289a
+    double y;
Aaron Merey bb289a
+  } dpoint_t;
Aaron Merey bb289a
+
Aaron Merey bb289a
+div_t __attribute__((__noinline__))
Aaron Merey bb289a
+div (int n, int d)
Aaron Merey bb289a
+{
Aaron Merey bb289a
+  div_t r;
Aaron Merey bb289a
+  r.q = n / d;
Aaron Merey bb289a
+  r.r = n % d;
Aaron Merey bb289a
+  return r;
Aaron Merey bb289a
+}
Aaron Merey bb289a
+
Aaron Merey bb289a
+ldiv_t __attribute__((__noinline__))
Aaron Merey bb289a
+ldiv (long n, long d)
Aaron Merey bb289a
+{
Aaron Merey bb289a
+  ldiv_t r;
Aaron Merey bb289a
+  r.q = n / d;
Aaron Merey bb289a
+  r.r = n % d;
Aaron Merey bb289a
+  return r;
Aaron Merey bb289a
+}
Aaron Merey bb289a
+
Aaron Merey bb289a
+point_t __attribute__((__noinline__))
Aaron Merey bb289a
+mkpt (float x, float y)
Aaron Merey bb289a
+{
Aaron Merey bb289a
+  point_t r;
Aaron Merey bb289a
+  r.x = x;
Aaron Merey bb289a
+  r.y = y;
Aaron Merey bb289a
+  return r;
Aaron Merey bb289a
+}
Aaron Merey bb289a
+
Aaron Merey bb289a
+dpoint_t __attribute__((__noinline__))
Aaron Merey bb289a
+dmkpt (double x, double y)
Aaron Merey bb289a
+{
Aaron Merey bb289a
+  dpoint_t r;
Aaron Merey bb289a
+  r.x = x;
Aaron Merey bb289a
+  r.y = y;
Aaron Merey bb289a
+  return r;
Aaron Merey bb289a
+}
Aaron Merey bb289a
+
Aaron Merey bb289a
+int
Aaron Merey bb289a
+main (void)
Aaron Merey bb289a
+{
Aaron Merey bb289a
+  div_t d = div (3, 2);
Aaron Merey bb289a
+  ldiv_t ld = ldiv (3, 2);
Aaron Merey bb289a
+  point_t p = mkpt (3.0f, 1.0f);
Aaron Merey bb289a
+  dpoint_t dp = dmkpt (3.0d, 1.0d);
Aaron Merey bb289a
+
Aaron Merey bb289a
+  return d.q - (int) p.y + ld.q - (int) dp.y;
Aaron Merey bb289a
+}
Aaron Merey bb289a
Aaron Merey bb289a
diff --git a/tests/run-funcretval-struct-native.sh b/tests/run-funcretval-struct-native.sh
Aaron Merey bb289a
new file mode 100755
Aaron Merey bb289a
index 000000000000..798edb3b61b3
Aaron Merey bb289a
--- /dev/null
Aaron Merey bb289a
+++ b/tests/run-funcretval-struct-native.sh
Aaron Merey bb289a
@@ -0,0 +1,22 @@
Aaron Merey bb289a
+#! /bin/sh
Aaron Merey bb289a
+# Copyright (C) 2024 Mark J. Wielaard <mark@klomp.org>
Aaron Merey bb289a
+# This file is part of elfutils.
Aaron Merey bb289a
+#
Aaron Merey bb289a
+# This file is free software; you can redistribute it and/or modify
Aaron Merey bb289a
+# it under the terms of the GNU General Public License as published by
Aaron Merey bb289a
+# the Free Software Foundation; either version 3 of the License, or
Aaron Merey bb289a
+# (at your option) any later version.
Aaron Merey bb289a
+#
Aaron Merey bb289a
+# elfutils is distributed in the hope that it will be useful, but
Aaron Merey bb289a
+# WITHOUT ANY WARRANTY; without even the implied warranty of
Aaron Merey bb289a
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Aaron Merey bb289a
+# GNU General Public License for more details.
Aaron Merey bb289a
+#
Aaron Merey bb289a
+# You should have received a copy of the GNU General Public License
Aaron Merey bb289a
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Aaron Merey bb289a
+
Aaron Merey bb289a
+. $srcdir/test-subr.sh
Aaron Merey bb289a
+
Aaron Merey bb289a
+# Just run it, we don't know what the native representation is.
Aaron Merey bb289a
+# But it should at least work and not error out.
Aaron Merey bb289a
+testrun $abs_builddir/funcretval -e $abs_builddir/funcretval_test_struct
Aaron Merey bb289a
-- 
Aaron Merey bb289a
2.44.0
Aaron Merey bb289a