Branch data Line data Source code
1 : : /* Function return value location for Linux/LoongArch ABI.
2 : : Copyright (C) 2013 Red Hat, Inc.
3 : : Copyright (C) 2023 OpenAnolis community LoongArch SIG.
4 : : Copyright (C) 2023 Loongson Technology Corporation Limited.
5 : :
6 : : This file is part of elfutils.
7 : :
8 : : This file is free software; you can redistribute it and/or modify
9 : : it under the terms of either
10 : :
11 : : * the GNU Lesser General Public License as published by the Free
12 : : Software Foundation; either version 3 of the License, or (at
13 : : your option) any later version
14 : :
15 : : or
16 : :
17 : : * the GNU General Public License as published by the Free
18 : : Software Foundation; either version 2 of the License, or (at
19 : : your option) any later version
20 : :
21 : : or both in parallel, as here.
22 : :
23 : : elfutils is distributed in the hope that it will be useful, but
24 : : WITHOUT ANY WARRANTY; without even the implied warranty of
25 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 : : General Public License for more details.
27 : :
28 : : You should have received copies of the GNU General Public License and
29 : : the GNU Lesser General Public License along with this program. If
30 : : not, see <http://www.gnu.org/licenses/>. */
31 : :
32 : : #ifdef HAVE_CONFIG_H
33 : : # include <config.h>
34 : : #endif
35 : :
36 : : #include <stdio.h>
37 : : #include <inttypes.h>
38 : :
39 : : #include <assert.h>
40 : : #include <dwarf.h>
41 : :
42 : : #define BACKEND loongarch_
43 : : #include "libebl_CPU.h"
44 : :
45 : : static int
46 : 0 : dwarf_bytesize_aux (Dwarf_Die *die, Dwarf_Word *sizep)
47 : : {
48 : 0 : int bits;
49 [ # # ]: 0 : if (((bits = 8 * dwarf_bytesize (die)) < 0
50 [ # # ]: 0 : && (bits = dwarf_bitsize (die)) < 0)
51 [ # # ]: 0 : || bits % 8 != 0)
52 : 0 : return -1;
53 : :
54 : 0 : *sizep = bits / 8;
55 : 0 : return 0;
56 : : }
57 : :
58 : : static int
59 : 0 : pass_in_gpr (const Dwarf_Op **locp, Dwarf_Word size)
60 : : {
61 : 0 : static const Dwarf_Op loc[] =
62 : : {
63 : : { .atom = DW_OP_reg4 }, { .atom = DW_OP_piece, .number = 8 },
64 : : { .atom = DW_OP_reg5 }, { .atom = DW_OP_piece, .number = 8 }
65 : : };
66 : :
67 : 0 : *locp = loc;
68 : 0 : return size <= 8 ? 1 : 4;
69 : : }
70 : :
71 : : static int
72 : 0 : pass_by_ref (const Dwarf_Op **locp)
73 : : {
74 : 0 : static const Dwarf_Op loc[] = { { .atom = DW_OP_breg4 } };
75 : :
76 : 0 : *locp = loc;
77 : 0 : return 1;
78 : : }
79 : :
80 : : static int
81 : 0 : pass_in_fpr (const Dwarf_Op **locp, Dwarf_Word size)
82 : : {
83 : 0 : static const Dwarf_Op loc[] =
84 : : {
85 : : { .atom = DW_OP_regx, .number = 32 },
86 : : { .atom = DW_OP_piece, .number = 8 },
87 : : { .atom = DW_OP_regx, .number = 33 },
88 : : { .atom = DW_OP_piece, .number = 8 }
89 : : };
90 : :
91 : 0 : *locp = loc;
92 : 0 : return size <= 8 ? 1 : 4;
93 : : }
94 : :
95 : : int
96 : 0 : loongarch_return_value_location(Dwarf_Die *functypedie,
97 : : const Dwarf_Op **locp)
98 : : {
99 : : /* Start with the function's type, and get the DW_AT_type attribute,
100 : : which is the type of the return value. */
101 : 0 : Dwarf_Die typedie;
102 : 0 : int tag = dwarf_peeled_die_type (functypedie, &typedie);
103 [ # # ]: 0 : if (tag <= 0)
104 : : return tag;
105 : :
106 : 0 : Dwarf_Word size = (Dwarf_Word)-1;
107 : :
108 : : /* If the argument type is a Composite Type that is larger than 16
109 : : bytes, then the argument is copied to memory allocated by the
110 : : caller and the argument is replaced by a pointer to the copy. */
111 [ # # ]: 0 : if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type
112 [ # # ]: 0 : || tag == DW_TAG_class_type || tag == DW_TAG_array_type)
113 : : {
114 [ # # ]: 0 : if (dwarf_aggregate_size (&typedie, &size) < 0)
115 : : return -1;
116 : :
117 : : /* Aggregates larger than 2*GRLEN bits are passed by reference. */
118 [ # # ]: 0 : if (size > 16)
119 : 0 : return pass_by_ref (locp);
120 : : /* Aggregates whose total size is no more than GRLEN bits are passed in
121 : : a register. Aggregates whose total size is no more than 2*GRLEN bits
122 : : are passed in a pair of registers. */
123 : : else
124 [ # # ]: 0 : return pass_in_gpr (locp, size);
125 : : }
126 : :
127 [ # # # # ]: 0 : if (tag == DW_TAG_base_type || dwarf_is_pointer (tag))
128 : : {
129 [ # # ]: 0 : if (dwarf_bytesize_aux (&typedie, &size) < 0)
130 : : {
131 [ # # ]: 0 : if (dwarf_is_pointer (tag))
132 : 0 : size = 8;
133 : : else
134 : : return -1;
135 : : }
136 : :
137 : 0 : Dwarf_Attribute attr_mem;
138 [ # # ]: 0 : if (tag == DW_TAG_base_type)
139 : : {
140 : 0 : Dwarf_Word encoding;
141 [ # # ]: 0 : if (dwarf_formudata (dwarf_attr_integrate (&typedie, DW_AT_encoding,
142 : : &attr_mem),
143 : : &encoding) != 0)
144 : : return -1;
145 : :
146 [ # # # # ]: 0 : switch (encoding)
147 : : {
148 : 0 : case DW_ATE_boolean:
149 : : case DW_ATE_signed:
150 : : case DW_ATE_unsigned:
151 : : case DW_ATE_unsigned_char:
152 : : case DW_ATE_signed_char:
153 : : /* Scalars that are at most GRLEN bits wide are passed in a single
154 : : argument register. Scalars that are 2*GRLEN bits wide are
155 : : passed in a pair of argument registers. Scalars wider than
156 : : 2*GRLEN are passed by reference. */
157 [ # # ]: 0 : return pass_in_gpr (locp, size);
158 : :
159 : 0 : case DW_ATE_float:
160 : : /* A real floating-point argument is passed in a floating-point
161 : : argument register if it is no more than FLEN bits wide,
162 : : otherwise it is passed according to the integer calling
163 : : convention. */
164 [ # # # ]: 0 : switch (size)
165 : : {
166 : 0 : case 4: /* single */
167 : : case 8: /* double */
168 : 0 : return pass_in_fpr (locp, size);
169 : :
170 : 0 : case 16: /* quad */
171 : 0 : return pass_in_gpr (locp, size);
172 : :
173 : : default:
174 : : return -2;
175 : : }
176 : :
177 : 0 : case DW_ATE_complex_float:
178 : : /* A complex floating-point number is passed as though it were a
179 : : struct containing two floating-point reals. */
180 [ # # # ]: 0 : switch (size)
181 : : {
182 : 0 : case 8: /* float _Complex */
183 : : case 16: /* double _Complex */
184 [ # # ]: 0 : return pass_in_fpr (locp, size);
185 : :
186 : : case 32: /* long double _Complex */
187 : 0 : return pass_by_ref (locp);
188 : :
189 : : default:
190 : : return -2;
191 : : }
192 : : }
193 : :
194 : : return -2;
195 : : }
196 : : else
197 [ # # ]: 0 : return pass_in_gpr (locp, size);
198 : : }
199 : :
200 : 0 : *locp = NULL;
201 : 0 : return 0;
202 : : }
|