LCOV - code coverage report
Current view: top level - backends - aarch64_retval.c (source / functions) Hit Total Coverage
Test: elfutils-0.191 Lines: 120 134 89.6 %
Date: 2024-08-30 13:26:44 Functions: 6 6 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 65 104 62.5 %

           Branch data     Line data    Source code
       1                 :            : /* Function return value location for Linux/AArch64 ABI.
       2                 :            :    Copyright (C) 2013 Red Hat, Inc.
       3                 :            :    This file is part of elfutils.
       4                 :            : 
       5                 :            :    This file is free software; you can redistribute it and/or modify
       6                 :            :    it under the terms of either
       7                 :            : 
       8                 :            :      * the GNU Lesser General Public License as published by the Free
       9                 :            :        Software Foundation; either version 3 of the License, or (at
      10                 :            :        your option) any later version
      11                 :            : 
      12                 :            :    or
      13                 :            : 
      14                 :            :      * the GNU General Public License as published by the Free
      15                 :            :        Software Foundation; either version 2 of the License, or (at
      16                 :            :        your option) any later version
      17                 :            : 
      18                 :            :    or both in parallel, as here.
      19                 :            : 
      20                 :            :    elfutils is distributed in the hope that it will be useful, but
      21                 :            :    WITHOUT ANY WARRANTY; without even the implied warranty of
      22                 :            :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      23                 :            :    General Public License for more details.
      24                 :            : 
      25                 :            :    You should have received copies of the GNU General Public License and
      26                 :            :    the GNU Lesser General Public License along with this program.  If
      27                 :            :    not, see <http://www.gnu.org/licenses/>.  */
      28                 :            : 
      29                 :            : #ifdef HAVE_CONFIG_H
      30                 :            : # include <config.h>
      31                 :            : #endif
      32                 :            : 
      33                 :            : #include <stdio.h>
      34                 :            : #include <inttypes.h>
      35                 :            : 
      36                 :            : #include <assert.h>
      37                 :            : #include <dwarf.h>
      38                 :            : 
      39                 :            : #define BACKEND aarch64_
      40                 :            : #include "libebl_CPU.h"
      41                 :            : 
      42                 :            : static int
      43                 :        412 : skip_until (Dwarf_Die *child, int tag)
      44                 :            : {
      45                 :        412 :   int i;
      46   [ +  -  -  + ]:        412 :   while (DWARF_TAG_OR_RETURN (child) != tag)
      47         [ #  # ]:          0 :     if ((i = dwarf_siblingof (child, child)) != 0)
      48                 :            :       /* If there are no members, then this is not a HFA.  Errors
      49                 :            :          are propagated.  */
      50                 :          0 :       return i;
      51                 :            :   return 0;
      52                 :            : }
      53                 :            : 
      54                 :            : static int
      55                 :        172 : dwarf_bytesize_aux (Dwarf_Die *die, Dwarf_Word *sizep)
      56                 :            : {
      57                 :        172 :   int bits;
      58         [ -  + ]:        172 :   if (((bits = 8 * dwarf_bytesize (die)) < 0
      59         [ #  # ]:          0 :        && (bits = dwarf_bitsize (die)) < 0)
      60         [ -  + ]:        172 :       || bits % 8 != 0)
      61                 :          0 :     return -1;
      62                 :            : 
      63                 :        172 :   *sizep = bits / 8;
      64                 :        172 :   return 0;
      65                 :            : }
      66                 :            : 
      67                 :            : /* HFA (Homogeneous Floating-point Aggregate) is an aggregate type
      68                 :            :    whose members are all of the same floating-point type, which is
      69                 :            :    then base type of this HFA.  Instead of being floating-point types
      70                 :            :    directly, members can instead themselves be HFA.  Such HFA fields
      71                 :            :    are handled as if their type were HFA base type.
      72                 :            : 
      73                 :            :    This function returns 0 if TYPEDIE is HFA, 1 if it is not, or -1 if
      74                 :            :    there were errors.  In the former case, *SIZEP contains byte size
      75                 :            :    of the base type (e.g. 8 for IEEE double).  *COUNT is set to the
      76                 :            :    number of leaf members of the HFA.  */
      77                 :            : static int hfa_type (Dwarf_Die *ftypedie, int tag,
      78                 :            :                      Dwarf_Word *sizep, Dwarf_Word *countp);
      79                 :            : 
      80                 :            : /* Return 0 if MEMBDIE refers to a member with a floating-point or HFA
      81                 :            :    type, or 1 if it's not.  Return -1 for errors.  The meaning of the
      82                 :            :    remaining arguments is as documented at hfa_type.  */
      83                 :            : static int
      84                 :        444 : member_is_fp (Dwarf_Die *membdie, Dwarf_Word *sizep, Dwarf_Word *countp)
      85                 :            : {
      86                 :        444 :   Dwarf_Die typedie;
      87                 :        444 :   int tag = dwarf_peeled_die_type (membdie, &typedie);
      88      [ +  +  - ]:        444 :   switch (tag)
      89                 :            :     {
      90                 :        148 :     case DW_TAG_base_type:;
      91                 :        148 :       Dwarf_Word encoding;
      92                 :        148 :       Dwarf_Attribute attr_mem;
      93         [ +  - ]:        148 :       if (dwarf_attr_integrate (&typedie, DW_AT_encoding, &attr_mem) == NULL
      94         [ -  + ]:        148 :           || dwarf_formudata (&attr_mem, &encoding) != 0)
      95                 :          0 :         return -1;
      96                 :            : 
      97      [ +  +  + ]:        148 :       switch (encoding)
      98                 :            :         {
      99                 :         12 :         case DW_ATE_complex_float:
     100                 :         12 :           *countp = 2;
     101                 :         12 :           break;
     102                 :            : 
     103                 :        132 :         case DW_ATE_float:
     104                 :        132 :           *countp = 1;
     105                 :        132 :           break;
     106                 :            : 
     107                 :            :         default:
     108                 :            :           return 1;
     109                 :            :         }
     110                 :            : 
     111         [ -  + ]:        144 :       if (dwarf_bytesize_aux (&typedie, sizep) < 0)
     112                 :            :         return -1;
     113                 :            : 
     114                 :        144 :       *sizep /= *countp;
     115                 :        144 :       return 0;
     116                 :            : 
     117                 :        296 :     case DW_TAG_structure_type:
     118                 :            :     case DW_TAG_union_type:
     119                 :            :     case DW_TAG_array_type:
     120                 :        296 :       return hfa_type (&typedie, tag, sizep, countp);
     121                 :            :     }
     122                 :            : 
     123                 :            :   return 1;
     124                 :            : }
     125                 :            : 
     126                 :            : static int
     127                 :        502 : hfa_type (Dwarf_Die *ftypedie, int tag, Dwarf_Word *sizep, Dwarf_Word *countp)
     128                 :            : {
     129   [ +  +  -  + ]:        502 :   assert (tag == DW_TAG_structure_type || tag == DW_TAG_class_type
     130                 :            :           || tag == DW_TAG_union_type || tag == DW_TAG_array_type);
     131                 :            : 
     132                 :        320 :   int i;
     133         [ +  - ]:        320 :   if (tag == DW_TAG_array_type)
     134                 :            :     {
     135                 :        320 :       Dwarf_Word tot_size;
     136         [ +  - ]:        320 :       if (dwarf_aggregate_size (ftypedie, &tot_size) < 0)
     137                 :            :         return -1;
     138                 :            : 
     139                 :            :       /* For vector types, we don't care about the underlying
     140                 :            :          type, but only about the vector type itself.  */
     141                 :        320 :       bool vec;
     142                 :        320 :       Dwarf_Attribute attr_mem;
     143         [ +  + ]:        320 :       if (dwarf_formflag (dwarf_attr_integrate (ftypedie, DW_AT_GNU_vector,
     144                 :            :                                                 &attr_mem), &vec) == 0
     145         [ +  - ]:        288 :           && vec)
     146                 :            :         {
     147                 :        288 :           *sizep = tot_size;
     148                 :        288 :           *countp = 1;
     149                 :            : 
     150                 :        288 :           return 0;
     151                 :            :         }
     152                 :            : 
     153         [ +  + ]:         32 :       if ((i = member_is_fp (ftypedie, sizep, countp)) == 0)
     154                 :            :         {
     155                 :         30 :           *countp = tot_size / *sizep;
     156                 :         30 :           return 0;
     157                 :            :         }
     158                 :            : 
     159                 :            :       return i;
     160                 :            :     }
     161                 :            : 
     162                 :            :   /* Find first DW_TAG_member and determine its type.  */
     163                 :        182 :   Dwarf_Die member;
     164         [ +  - ]:        182 :   if ((i = dwarf_child (ftypedie, &member) != 0))
     165                 :            :     return i;
     166                 :            : 
     167         [ +  - ]:        182 :   if ((i = skip_until (&member, DW_TAG_member)) != 0)
     168                 :            :     return i;
     169                 :            : 
     170                 :        182 :   *countp = 0;
     171         [ +  + ]:        182 :   if ((i = member_is_fp (&member, sizep, countp)) != 0)
     172                 :            :     return i;
     173                 :            : 
     174                 :        816 :   while ((i = dwarf_siblingof (&member, &member)) == 0
     175   [ +  +  +  - ]:        408 :          && (i = skip_until (&member, DW_TAG_member)) == 0)
     176                 :            :     {
     177                 :        230 :       Dwarf_Word size, count;
     178         [ -  + ]:        230 :       if ((i = member_is_fp (&member, &size, &count)) != 0)
     179                 :          0 :         return i;
     180                 :            : 
     181         [ +  - ]:        230 :       if (*sizep != size)
     182                 :            :         return 1;
     183                 :            : 
     184                 :        230 :       *countp += count;
     185                 :            :     }
     186                 :            : 
     187                 :            :   /* At this point we already have at least one FP member, which means
     188                 :            :      FTYPEDIE is an HFA.  So either return 0, or propagate error.  */
     189                 :        178 :   return i < 0 ? i : 0;
     190                 :            : }
     191                 :            : 
     192                 :            : static int
     193                 :         16 : pass_in_gpr (const Dwarf_Op **locp, Dwarf_Word size)
     194                 :            : {
     195                 :         16 :   static const Dwarf_Op loc[] =
     196                 :            :     {
     197                 :            :       { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 8 },
     198                 :            :       { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 8 }
     199                 :            :     };
     200                 :            : 
     201                 :         16 :   *locp = loc;
     202                 :         16 :   return size <= 8 ? 1 : 4;
     203                 :            : }
     204                 :            : 
     205                 :            : static int
     206                 :         16 : pass_by_ref (const Dwarf_Op **locp)
     207                 :            : {
     208                 :         16 :   static const Dwarf_Op loc[] = { { .atom = DW_OP_breg0 } };
     209                 :            : 
     210                 :         16 :   *locp = loc;
     211                 :         16 :   return 1;
     212                 :            : }
     213                 :            : 
     214                 :            : static int
     215                 :        202 : pass_hfa (const Dwarf_Op **locp, Dwarf_Word size, Dwarf_Word count)
     216                 :            : {
     217         [ -  + ]:        196 :   assert (count >= 1 && count <= 4);
     218         [ -  + ]:        196 :   assert (size == 2 || size == 4 || size == 8 || size == 16);
     219                 :            : 
     220                 :            : #define DEFINE_FPREG(NAME, SIZE)                \
     221                 :            :   static const Dwarf_Op NAME[] = {              \
     222                 :            :     { .atom = DW_OP_regx, .number = 64 },       \
     223                 :            :     { .atom = DW_OP_piece, .number = SIZE },    \
     224                 :            :     { .atom = DW_OP_regx, .number = 65 },       \
     225                 :            :     { .atom = DW_OP_piece, .number = SIZE },    \
     226                 :            :     { .atom = DW_OP_regx, .number = 66 },       \
     227                 :            :     { .atom = DW_OP_piece, .number = SIZE },    \
     228                 :            :     { .atom = DW_OP_regx, .number = 67 },       \
     229                 :            :     { .atom = DW_OP_piece, .number = SIZE }     \
     230                 :            :   }
     231                 :            : 
     232   [ -  +  +  +  :        196 :   switch (size)
                      - ]
     233                 :            :     {
     234                 :          0 :     case 2:;
     235                 :          0 :       DEFINE_FPREG (loc_hfa_2, 2);
     236                 :          0 :       *locp = loc_hfa_2;
     237                 :          0 :       break;
     238                 :            : 
     239                 :         22 :     case 4:;
     240                 :         22 :       DEFINE_FPREG (loc_hfa_4, 4);
     241                 :         22 :       *locp = loc_hfa_4;
     242                 :         22 :       break;
     243                 :            : 
     244                 :         88 :     case 8:;
     245                 :         88 :       DEFINE_FPREG (loc_hfa_8, 8);
     246                 :         88 :       *locp = loc_hfa_8;
     247                 :         82 :       break;
     248                 :            : 
     249                 :         92 :     case 16:;
     250                 :         92 :       DEFINE_FPREG (loc_hfa_16, 16);
     251                 :         92 :       *locp = loc_hfa_16;
     252                 :         92 :       break;
     253                 :            :     }
     254                 :            : #undef DEFINE_FPREG
     255                 :            : 
     256         [ +  + ]:        196 :   return count == 1 ? 1 : 2 * count;
     257                 :            : }
     258                 :            : 
     259                 :            : static int
     260                 :          6 : pass_in_simd (const Dwarf_Op **locp)
     261                 :            : {
     262                 :            :   /* This is like passing single-element HFA.  Size doesn't matter, so
     263                 :            :      pretend it's for example double.  */
     264                 :          6 :   return pass_hfa (locp, 8, 1);
     265                 :            : }
     266                 :            : 
     267                 :            : int
     268                 :        234 : aarch64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
     269                 :            : {
     270                 :            :   /* Start with the function's type, and get the DW_AT_type attribute,
     271                 :            :      which is the type of the return value.  */
     272                 :        234 :   Dwarf_Die typedie;
     273                 :        234 :   int tag = dwarf_peeled_die_type (functypedie, &typedie);
     274         [ +  - ]:        234 :   if (tag <= 0)
     275                 :            :     return tag;
     276                 :            : 
     277                 :        234 :   Dwarf_Word size = (Dwarf_Word)-1;
     278                 :            : 
     279                 :            :   /* If the argument type is a Composite Type that is larger than 16
     280                 :            :      bytes, then the argument is copied to memory allocated by the
     281                 :            :      caller and the argument is replaced by a pointer to the copy.  */
     282         [ +  + ]:        234 :   if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type
     283         [ +  + ]:         52 :       || tag == DW_TAG_class_type || tag == DW_TAG_array_type)
     284                 :            :     {
     285                 :        206 :       Dwarf_Word base_size, count;
     286      [ +  +  - ]:        206 :       switch (hfa_type (&typedie, tag, &base_size, &count))
     287                 :            :         {
     288                 :            :         default:
     289                 :        206 :           return -1;
     290                 :            : 
     291                 :        202 :         case 0:
     292         [ -  + ]:        202 :           assert (count > 0);
     293         [ +  + ]:        202 :           if (count <= 4)
     294                 :        190 :             return pass_hfa (locp, base_size, count);
     295                 :         16 :           FALLTHROUGH;
     296                 :            : 
     297                 :            :         case 1:
     298                 :            :           /* Not a HFA.  */
     299         [ +  - ]:         16 :           if (dwarf_aggregate_size (&typedie, &size) < 0)
     300                 :            :             return -1;
     301         [ +  - ]:         16 :           if (size > 16)
     302                 :         16 :             return pass_by_ref (locp);
     303                 :            :         }
     304                 :            :     }
     305                 :            : 
     306   [ +  +  +  - ]:         28 :   if (tag == DW_TAG_base_type || dwarf_is_pointer (tag))
     307                 :            :     {
     308         [ -  + ]:         28 :       if (dwarf_bytesize_aux (&typedie, &size) < 0)
     309                 :            :         {
     310         [ #  # ]:          0 :           if (dwarf_is_pointer (tag))
     311                 :          0 :             size = 8;
     312                 :            :           else
     313                 :            :             return -1;
     314                 :            :         }
     315                 :            : 
     316                 :         28 :       Dwarf_Attribute attr_mem;
     317         [ +  + ]:         28 :       if (tag == DW_TAG_base_type)
     318                 :            :         {
     319                 :         26 :           Dwarf_Word encoding;
     320         [ +  - ]:         26 :           if (dwarf_formudata (dwarf_attr_integrate (&typedie, DW_AT_encoding,
     321                 :            :                                                      &attr_mem),
     322                 :            :                                &encoding) != 0)
     323                 :            :             return -1;
     324                 :            : 
     325   [ +  +  +  - ]:         26 :           switch (encoding)
     326                 :            :             {
     327                 :            :               /* If the argument is a Half-, Single-, Double- or Quad-
     328                 :            :                  precision Floating-point [...] the argument is allocated
     329                 :            :                  to the least significant bits of register v[NSRN].  */
     330                 :          6 :             case DW_ATE_float:
     331         [ +  - ]:          6 :               switch (size)
     332                 :            :                 {
     333                 :            :                 case 2: /* half */
     334                 :            :                 case 4: /* single */
     335                 :            :                 case 8: /* double */
     336                 :            :                 case 16: /* quad */
     337                 :          6 :                   return pass_in_simd (locp);
     338                 :            : 
     339                 :            :                 default:
     340                 :            :                   return -2;
     341                 :            :                 }
     342                 :            : 
     343                 :          6 :             case DW_ATE_complex_float:
     344         [ +  - ]:          6 :               switch (size)
     345                 :            :                 {
     346                 :          6 :                 case 8: /* float _Complex */
     347                 :            :                 case 16: /* double _Complex */
     348                 :            :                 case 32: /* long double _Complex */
     349                 :          6 :                   return pass_hfa (locp, size / 2, 2);
     350                 :            : 
     351                 :            :                 default:
     352                 :            :                   return -2;
     353                 :            :                 }
     354                 :            : 
     355                 :            :               /* If the argument is an Integral or Pointer Type, the
     356                 :            :                  size of the argument is less than or equal to 8 bytes
     357                 :            :                  [...] the argument is copied to the least significant
     358                 :            :                  bits in x[NGRN].  */
     359                 :         14 :             case DW_ATE_boolean:
     360                 :            :             case DW_ATE_signed:
     361                 :            :             case DW_ATE_unsigned:
     362                 :            :             case DW_ATE_unsigned_char:
     363                 :            :             case DW_ATE_signed_char:
     364         [ +  + ]:         16 :               return pass_in_gpr (locp, size);
     365                 :            :             }
     366                 :            : 
     367                 :            :           return -2;
     368                 :            :         }
     369                 :            :       else
     370         [ -  + ]:          2 :         return pass_in_gpr (locp, size);
     371                 :            :     }
     372                 :            : 
     373                 :          0 :   *locp = NULL;
     374                 :          0 :   return 0;
     375                 :            : }

Generated by: LCOV version 1.16