1 /* Function return value location for IA64 ABI. 2 Copyright (C) 2006-2010, 2014 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 <assert.h> 34 #include <dwarf.h> 35 36 #define BACKEND ia64_ 37 #include "libebl_CPU.h" 38 39 40 /* r8, or pair r8, r9, or aggregate up to r8-r11. */ 41 static const Dwarf_Op loc_intreg[] = 42 { 43 { .atom = DW_OP_reg8 }, { .atom = DW_OP_piece, .number = 8 }, 44 { .atom = DW_OP_reg9 }, { .atom = DW_OP_piece, .number = 8 }, 45 { .atom = DW_OP_reg10 }, { .atom = DW_OP_piece, .number = 8 }, 46 { .atom = DW_OP_reg11 }, { .atom = DW_OP_piece, .number = 8 }, 47 }; 48 #define nloc_intreg 1 49 #define nloc_intregs(n) (2 * (n)) 50 51 /* f8, or aggregate up to f8-f15. */ 52 #define DEFINE_FPREG(size) \ 53 static const Dwarf_Op loc_fpreg_##size[] = \ 54 { \ 55 { .atom = DW_OP_regx, .number = 128 + 8 }, \ 56 { .atom = DW_OP_piece, .number = size }, \ 57 { .atom = DW_OP_regx, .number = 128 + 9 }, \ 58 { .atom = DW_OP_piece, .number = size }, \ 59 { .atom = DW_OP_regx, .number = 128 + 10 }, \ 60 { .atom = DW_OP_piece, .number = size }, \ 61 { .atom = DW_OP_regx, .number = 128 + 11 }, \ 62 { .atom = DW_OP_piece, .number = size }, \ 63 { .atom = DW_OP_regx, .number = 128 + 12 }, \ 64 { .atom = DW_OP_piece, .number = size }, \ 65 { .atom = DW_OP_regx, .number = 128 + 13 }, \ 66 { .atom = DW_OP_piece, .number = size }, \ 67 { .atom = DW_OP_regx, .number = 128 + 14 }, \ 68 { .atom = DW_OP_piece, .number = size }, \ 69 { .atom = DW_OP_regx, .number = 128 + 15 }, \ 70 { .atom = DW_OP_piece, .number = size }, \ 71 } 72 #define nloc_fpreg 1 73 #define nloc_fpregs(n) (2 * (n)) 74 75 DEFINE_FPREG (4); 76 DEFINE_FPREG (8); 77 DEFINE_FPREG (10); 78 79 #undef DEFINE_FPREG 80 81 82 /* The return value is a structure and is actually stored in stack space 83 passed in a hidden argument by the caller. But, the compiler 84 helpfully returns the address of that space in r8. */ 85 static const Dwarf_Op loc_aggregate[] = 86 { 87 { .atom = DW_OP_breg8, .number = 0 } 88 }; 89 #define nloc_aggregate 1 90 91 92 /* If this type is an HFA small enough to be returned in FP registers, 93 return the number of registers to use. Otherwise 9, or -1 for errors. */ 94 static int 95 hfa_type (Dwarf_Die *typedie, Dwarf_Word size, 96 const Dwarf_Op **locp, int fpregs_used) 97 { 98 /* Descend the type structure, counting elements and finding their types. 99 If we find a datum that's not an FP type (and not quad FP), punt. 100 If we find a datum that's not the same FP type as the first datum, punt. 101 If we count more than eight total homogeneous FP data, punt. */ 102 103 inline int hfa (const Dwarf_Op *loc, int nregs) 104 { 105 if (fpregs_used == 0) 106 *locp = loc; 107 else if (*locp != loc) 108 return 9; 109 return fpregs_used + nregs; 110 } 111 112 int tag = DWARF_TAG_OR_RETURN (typedie); 113 switch (tag) 114 { 115 Dwarf_Attribute attr_mem; 116 117 case -1: 118 return -1; 119 120 case DW_TAG_base_type:; 121 Dwarf_Word encoding; 122 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, 123 &attr_mem), &encoding) != 0) 124 return -1; 125 126 switch (encoding) 127 { 128 case DW_ATE_float: 129 switch (size) 130 { 131 case 4: /* float */ 132 return hfa (loc_fpreg_4, 1); 133 case 8: /* double */ 134 return hfa (loc_fpreg_8, 1); 135 case 10: /* x86-style long double, not really used */ 136 return hfa (loc_fpreg_10, 1); 137 } 138 break; 139 140 case DW_ATE_complex_float: 141 switch (size) 142 { 143 case 4 * 2: /* complex float */ 144 return hfa (loc_fpreg_4, 2); 145 case 8 * 2: /* complex double */ 146 return hfa (loc_fpreg_8, 2); 147 case 10 * 2: /* complex long double (x86-style) */ 148 return hfa (loc_fpreg_10, 2); 149 } 150 break; 151 } 152 break; 153 154 case DW_TAG_structure_type: 155 case DW_TAG_class_type: 156 case DW_TAG_union_type:; 157 Dwarf_Die child_mem; 158 switch (dwarf_child (typedie, &child_mem)) 159 { 160 default: 161 return -1; 162 163 case 1: /* No children: empty struct. */ 164 break; 165 166 case 0:; /* Look at each element. */ 167 int max_used = fpregs_used; 168 do 169 switch (dwarf_tag (&child_mem)) 170 { 171 case -1: 172 return -1; 173 174 case DW_TAG_member:; 175 Dwarf_Die child_type_mem; 176 Dwarf_Die *child_typedie 177 = dwarf_formref_die (dwarf_attr_integrate (&child_mem, 178 DW_AT_type, 179 &attr_mem), 180 &child_type_mem); 181 Dwarf_Word child_size; 182 if (dwarf_aggregate_size (child_typedie, &child_size) != 0) 183 return -1; 184 if (tag == DW_TAG_union_type) 185 { 186 int used = hfa_type (child_typedie, child_size, 187 locp, fpregs_used); 188 if (used < 0 || used > 8) 189 return used; 190 if (used > max_used) 191 max_used = used; 192 } 193 else 194 { 195 fpregs_used = hfa_type (child_typedie, child_size, 196 locp, fpregs_used); 197 if (fpregs_used < 0 || fpregs_used > 8) 198 return fpregs_used; 199 } 200 } 201 while (dwarf_siblingof (&child_mem, &child_mem) == 0); 202 if (tag == DW_TAG_union_type) 203 fpregs_used = max_used; 204 break; 205 } 206 break; 207 208 case DW_TAG_array_type: 209 if (size == 0) 210 break; 211 212 Dwarf_Die base_type_mem; 213 Dwarf_Die *base_typedie 214 = dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type, 215 &attr_mem), 216 &base_type_mem); 217 Dwarf_Word base_size; 218 if (dwarf_aggregate_size (base_typedie, &base_size) != 0) 219 return -1; 220 221 int used = hfa_type (base_typedie, base_size, locp, 0); 222 if (used < 0 || used > 8) 223 return used; 224 if (size % (*locp)[1].number != 0) 225 return 0; 226 fpregs_used += used * (size / (*locp)[1].number); 227 break; 228 229 default: 230 return 9; 231 } 232 233 return fpregs_used; 234 } 235 236 int 237 ia64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) 238 { 239 /* Start with the function's type, and get the DW_AT_type attribute, 240 which is the type of the return value. */ 241 Dwarf_Die die_mem, *typedie = &die_mem; 242 int tag = dwarf_peeled_die_type (functypedie, typedie); 243 if (tag <= 0) 244 return tag; 245 246 Dwarf_Word size; 247 switch (tag) 248 { 249 case -1: 250 return -1; 251 252 case DW_TAG_subrange_type: 253 if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) 254 { 255 Dwarf_Attribute attr_mem, *attr; 256 attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); 257 typedie = dwarf_formref_die (attr, &die_mem); 258 tag = DWARF_TAG_OR_RETURN (typedie); 259 } 260 /* Fall through. */ 261 262 case DW_TAG_base_type: 263 case DW_TAG_enumeration_type: 264 case DW_TAG_pointer_type: 265 case DW_TAG_ptr_to_member_type: 266 { 267 Dwarf_Attribute attr_mem; 268 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, 269 &attr_mem), &size) != 0) 270 { 271 if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) 272 size = 8; 273 else 274 return -1; 275 } 276 } 277 278 if (tag == DW_TAG_base_type) 279 { 280 Dwarf_Attribute attr_mem; 281 Dwarf_Word encoding; 282 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, 283 &attr_mem), 284 &encoding) != 0) 285 return -1; 286 287 switch (encoding) 288 { 289 case DW_ATE_float: 290 switch (size) 291 { 292 case 4: /* float */ 293 *locp = loc_fpreg_4; 294 return nloc_fpreg; 295 case 8: /* double */ 296 *locp = loc_fpreg_8; 297 return nloc_fpreg; 298 case 10: /* x86-style long double, not really used */ 299 *locp = loc_fpreg_10; 300 return nloc_fpreg; 301 case 16: /* long double, IEEE quad format */ 302 *locp = loc_intreg; 303 return nloc_intregs (2); 304 } 305 return -2; 306 307 case DW_ATE_complex_float: 308 switch (size) 309 { 310 case 4 * 2: /* complex float */ 311 *locp = loc_fpreg_4; 312 return nloc_fpregs (2); 313 case 8 * 2: /* complex double */ 314 *locp = loc_fpreg_8; 315 return nloc_fpregs (2); 316 case 10 * 2: /* complex long double (x86-style) */ 317 *locp = loc_fpreg_10; 318 return nloc_fpregs (2); 319 case 16 * 2: /* complex long double (IEEE quad) */ 320 *locp = loc_intreg; 321 return nloc_intregs (4); 322 } 323 return -2; 324 } 325 } 326 327 intreg: 328 *locp = loc_intreg; 329 if (size <= 8) 330 return nloc_intreg; 331 if (size <= 32) 332 return nloc_intregs ((size + 7) / 8); 333 334 large: 335 *locp = loc_aggregate; 336 return nloc_aggregate; 337 338 case DW_TAG_structure_type: 339 case DW_TAG_class_type: 340 case DW_TAG_union_type: 341 case DW_TAG_array_type: 342 if (dwarf_aggregate_size (typedie, &size) != 0) 343 return -1; 344 345 /* If this qualifies as an homogeneous floating-point aggregate 346 (HFA), then it should be returned in FP regs. */ 347 int nfpreg = hfa_type (typedie, size, locp, 0); 348 if (nfpreg < 0) 349 return nfpreg; 350 else if (nfpreg > 0 && nfpreg <= 8) 351 return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg); 352 353 if (size > 32) 354 goto large; 355 356 goto intreg; 357 } 358 359 /* XXX We don't have a good way to return specific errors from ebl calls. 360 This value means we do not understand the type, but it is well-formed 361 DWARF and might be valid. */ 362 return -2; 363 } 364