103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* Function return value location for Linux/AArch64 ABI.
203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   Copyright (C) 2013 Red Hat, Inc.
303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is part of elfutils.
403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is free software; you can redistribute it and/or modify
603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   it under the terms of either
703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     * the GNU Lesser General Public License as published by the Free
903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       Software Foundation; either version 3 of the License, or (at
1003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       your option) any later version
1103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   or
1303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     * the GNU General Public License as published by the Free
1503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       Software Foundation; either version 2 of the License, or (at
1603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       your option) any later version
1703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   or both in parallel, as here.
1903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
2003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   elfutils is distributed in the hope that it will be useful, but
2103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   WITHOUT ANY WARRANTY; without even the implied warranty of
2203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   General Public License for more details.
2403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
2503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   You should have received copies of the GNU General Public License and
2603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   the GNU Lesser General Public License along with this program.  If
2703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   not, see <http://www.gnu.org/licenses/>.  */
2803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
2903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#ifdef HAVE_CONFIG_H
3003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes# include <config.h>
3103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#endif
3203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
3303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <stdio.h>
3403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <inttypes.h>
3503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
3603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <assert.h>
3703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <dwarf.h>
3803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
3903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#define BACKEND aarch64_
4003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include "libebl_CPU.h"
4103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
4203333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int
4303333823c75a1c1887e923828113a1b0fd12020cElliott Hughesskip_until (Dwarf_Die *child, int tag)
4403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
4503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int i;
4603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  while (DWARF_TAG_OR_RETURN (child) != tag)
4703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    if ((i = dwarf_siblingof (child, child)) != 0)
4803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      /* If there are no members, then this is not a HFA.  Errors
4903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	 are propagated.  */
5003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return i;
5103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return 0;
5203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
5303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
5403333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int
5503333823c75a1c1887e923828113a1b0fd12020cElliott Hughesdwarf_bytesize_aux (Dwarf_Die *die, Dwarf_Word *sizep)
5603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
5703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int bits;
5803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (((bits = 8 * dwarf_bytesize (die)) < 0
5903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       && (bits = dwarf_bitsize (die)) < 0)
6003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      || bits % 8 != 0)
6103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    return -1;
6203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
6303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  *sizep = bits / 8;
6403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return 0;
6503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
6603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
6703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* HFA (Homogeneous Floating-point Aggregate) is an aggregate type
6803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   whose members are all of the same floating-point type, which is
6903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   then base type of this HFA.  Instead of being floating-point types
7003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   directly, members can instead themselves be HFA.  Such HFA fields
7103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   are handled as if their type were HFA base type.
7203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
7303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This function returns 0 if TYPEDIE is HFA, 1 if it is not, or -1 if
7403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   there were errors.  In the former case, *SIZEP contains byte size
7503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   of the base type (e.g. 8 for IEEE double).  *COUNT is set to the
7603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   number of leaf members of the HFA.  */
7703333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int hfa_type (Dwarf_Die *ftypedie, int tag,
7803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		     Dwarf_Word *sizep, Dwarf_Word *countp);
7903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
8003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* Return 0 if MEMBDIE refers to a member with a floating-point or HFA
8103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   type, or 1 if it's not.  Return -1 for errors.  The meaning of the
8203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   remaining arguments is as documented at hfa_type.  */
8303333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int
8403333823c75a1c1887e923828113a1b0fd12020cElliott Hughesmember_is_fp (Dwarf_Die *membdie, Dwarf_Word *sizep, Dwarf_Word *countp)
8503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
8603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Dwarf_Die typedie;
8703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int tag = dwarf_peeled_die_type (membdie, &typedie);
8803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  switch (tag)
8903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
9003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DW_TAG_base_type:;
9103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwarf_Word encoding;
9203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwarf_Attribute attr_mem;
9303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (dwarf_attr_integrate (&typedie, DW_AT_encoding, &attr_mem) == NULL
9403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  || dwarf_formudata (&attr_mem, &encoding) != 0)
9503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	return -1;
9603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
9703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      switch (encoding)
9803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
9903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	case DW_ATE_complex_float:
10003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  *countp = 2;
10103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  break;
10203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
10303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	case DW_ATE_float:
10403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  *countp = 1;
10503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  break;
10603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
10703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	default:
10803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  return 1;
10903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
11003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
11103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (dwarf_bytesize_aux (&typedie, sizep) < 0)
11203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	return -1;
11303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
11403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      *sizep /= *countp;
11503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return 0;
11603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
11703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DW_TAG_structure_type:
11803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DW_TAG_union_type:
11903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DW_TAG_array_type:
12003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return hfa_type (&typedie, tag, sizep, countp);
12103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
12203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
12303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return 1;
12403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
12503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
12603333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int
12703333823c75a1c1887e923828113a1b0fd12020cElliott Hugheshfa_type (Dwarf_Die *ftypedie, int tag, Dwarf_Word *sizep, Dwarf_Word *countp)
12803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
12903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  assert (tag == DW_TAG_structure_type || tag == DW_TAG_class_type
13003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  || tag == DW_TAG_union_type || tag == DW_TAG_array_type);
13103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
13203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int i;
13303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (tag == DW_TAG_array_type)
13403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
13503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwarf_Word tot_size;
13603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (dwarf_aggregate_size (ftypedie, &tot_size) < 0)
13703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	return -1;
13803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
13903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      /* For vector types, we don't care about the underlying
14003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	 type, but only about the vector type itself.  */
14103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      bool vec;
14203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwarf_Attribute attr_mem;
14303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (dwarf_formflag (dwarf_attr_integrate (ftypedie, DW_AT_GNU_vector,
14403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						&attr_mem), &vec) == 0
14503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  && vec)
14603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
14703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  *sizep = tot_size;
14803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  *countp = 1;
14903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
15003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  return 0;
15103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
15203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
15303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if ((i = member_is_fp (ftypedie, sizep, countp)) == 0)
15403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
15503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  *countp = tot_size / *sizep;
15603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  return 0;
15703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
15803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
15903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return i;
16003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
16103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
16203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* Find first DW_TAG_member and determine its type.  */
16303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Dwarf_Die member;
16403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if ((i = dwarf_child (ftypedie, &member) != 0))
16503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    return i;
16603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
16703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if ((i = skip_until (&member, DW_TAG_member)) != 0)
16803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    return i;
16903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
17003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  *countp = 0;
17103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if ((i = member_is_fp (&member, sizep, countp)) != 0)
17203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    return i;
17303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
17403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  while ((i = dwarf_siblingof (&member, &member)) == 0
17503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	 && (i = skip_until (&member, DW_TAG_member)) == 0)
17603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
17703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwarf_Word size, count;
17803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if ((i = member_is_fp (&member, &size, &count)) != 0)
17903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	return i;
18003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
18103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (*sizep != size)
18203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	return 1;
18303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
18403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      *countp += count;
18503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
18603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
18703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* At this point we already have at least one FP member, which means
18803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     FTYPEDIE is an HFA.  So either return 0, or propagate error.  */
18903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return i < 0 ? i : 0;
19003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
19103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
19203333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int
19303333823c75a1c1887e923828113a1b0fd12020cElliott Hughespass_in_gpr (const Dwarf_Op **locp, Dwarf_Word size)
19403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
19503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  static const Dwarf_Op loc[] =
19603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
19703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 8 },
19803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 8 }
19903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    };
20003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
20103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  *locp = loc;
20203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return size <= 8 ? 1 : 4;
20303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
20403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
20503333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int
20603333823c75a1c1887e923828113a1b0fd12020cElliott Hughespass_by_ref (const Dwarf_Op **locp)
20703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
20803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  static const Dwarf_Op loc[] = { { .atom = DW_OP_breg0 } };
20903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
21003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  *locp = loc;
21103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return 1;
21203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
21303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
21403333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int
21503333823c75a1c1887e923828113a1b0fd12020cElliott Hughespass_hfa (const Dwarf_Op **locp, Dwarf_Word size, Dwarf_Word count)
21603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
21703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  assert (count >= 1 && count <= 4);
21803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  assert (size == 2 || size == 4 || size == 8 || size == 16);
21903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
22003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#define DEFINE_FPREG(NAME, SIZE)		\
22103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  static const Dwarf_Op NAME[] = {		\
22203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    { .atom = DW_OP_regx, .number = 64 },	\
22303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    { .atom = DW_OP_piece, .number = SIZE },	\
22403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    { .atom = DW_OP_regx, .number = 65 },	\
22503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    { .atom = DW_OP_piece, .number = SIZE },	\
22603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    { .atom = DW_OP_regx, .number = 66 },	\
22703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    { .atom = DW_OP_piece, .number = SIZE },	\
22803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    { .atom = DW_OP_regx, .number = 67 },	\
22903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    { .atom = DW_OP_piece, .number = SIZE }	\
23003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  }
23103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
23203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  switch (size)
23303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
23403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 2:;
23503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      DEFINE_FPREG (loc_hfa_2, 2);
23603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      *locp = loc_hfa_2;
23703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
23803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
23903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 4:;
24003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      DEFINE_FPREG (loc_hfa_4, 4);
24103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      *locp = loc_hfa_4;
24203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
24303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
24403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 8:;
24503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      DEFINE_FPREG (loc_hfa_8, 8);
24603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      *locp = loc_hfa_8;
24703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
24803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
24903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 16:;
25003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      DEFINE_FPREG (loc_hfa_16, 16);
25103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      *locp = loc_hfa_16;
25203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
25303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
25403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#undef DEFINE_FPREG
25503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
25603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return count == 1 ? 1 : 2 * count;
25703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
25803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
25903333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int
26003333823c75a1c1887e923828113a1b0fd12020cElliott Hughespass_in_simd (const Dwarf_Op **locp)
26103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
26203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* This is like passing single-element HFA.  Size doesn't matter, so
26303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     pretend it's for example double.  */
26403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return pass_hfa (locp, 8, 1);
26503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
26603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
26703333823c75a1c1887e923828113a1b0fd12020cElliott Hughesint
26803333823c75a1c1887e923828113a1b0fd12020cElliott Hughesaarch64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
26903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
27003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* Start with the function's type, and get the DW_AT_type attribute,
27103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     which is the type of the return value.  */
27203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Dwarf_Die typedie;
27303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int tag = dwarf_peeled_die_type (functypedie, &typedie);
27403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (tag <= 0)
27503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    return tag;
27603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
27703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Dwarf_Word size = (Dwarf_Word)-1;
27803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
27903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* If the argument type is a Composite Type that is larger than 16
28003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     bytes, then the argument is copied to memory allocated by the
28103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     caller and the argument is replaced by a pointer to the copy.  */
28203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type
28303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      || tag == DW_TAG_class_type || tag == DW_TAG_array_type)
28403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
28503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwarf_Word base_size, count;
28603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      switch (hfa_type (&typedie, tag, &base_size, &count))
28703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
28803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	default:
28903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  return -1;
29003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
29103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	case 0:
29203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  assert (count > 0);
29303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (count <= 4)
29403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    return pass_hfa (locp, base_size, count);
29503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* Fall through.  */
29603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
29703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	case 1:
29803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* Not a HFA.  */
29903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (dwarf_aggregate_size (&typedie, &size) < 0)
30003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    return -1;
30103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (size > 16)
30203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    return pass_by_ref (locp);
30303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
30403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
30503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
30603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (tag == DW_TAG_base_type
30703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      || tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
30803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
30903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (dwarf_bytesize_aux (&typedie, &size) < 0)
31003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
31103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
31203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    size = 8;
31303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  else
31403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    return -1;
31503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
31603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
31703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwarf_Attribute attr_mem;
31803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (tag == DW_TAG_base_type)
31903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
32003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  Dwarf_Word encoding;
32103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (dwarf_formudata (dwarf_attr_integrate (&typedie, DW_AT_encoding,
32203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						     &attr_mem),
32303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			       &encoding) != 0)
32403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    return -1;
32503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
32603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  switch (encoding)
32703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    {
32803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      /* If the argument is a Half-, Single-, Double- or Quad-
32903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		 precision Floating-point [...] the argument is allocated
33003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		 to the least significant bits of register v[NSRN].  */
33103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    case DW_ATE_float:
33203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      switch (size)
33303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		{
33403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		case 2: /* half */
33503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		case 4: /* sigle */
33603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		case 8: /* double */
33703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		case 16: /* quad */
33803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  return pass_in_simd (locp);
33903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
34003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		default:
34103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  return -2;
34203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		}
34303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
34403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    case DW_ATE_complex_float:
34503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      switch (size)
34603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		{
34703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		case 8: /* float _Complex */
34803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		case 16: /* double _Complex */
34903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		case 32: /* long double _Complex */
35003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  return pass_hfa (locp, size / 2, 2);
35103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
35203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		default:
35303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  return -2;
35403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		}
35503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
35603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      /* If the argument is an Integral or Pointer Type, the
35703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		 size of the argument is less than or equal to 8 bytes
35803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		 [...] the argument is copied to the least significant
35903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		 bits in x[NGRN].  */
36003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    case DW_ATE_boolean:
36103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    case DW_ATE_signed:
36203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    case DW_ATE_unsigned:
36303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    case DW_ATE_unsigned_char:
36403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    case DW_ATE_signed_char:
36503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      return pass_in_gpr (locp, size);
36603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    }
36703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
36803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  return -2;
36903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
37003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      else
37103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	return pass_in_gpr (locp, size);
37203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
37303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
37403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  *locp = NULL;
37503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return 0;
37603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
377