1 /* Function return value location for IA64 ABI. 2 Copyright (C) 2006, 2007 Red Hat, Inc. 3 This file is part of Red Hat elfutils. 4 5 Red Hat elfutils is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by the 7 Free Software Foundation; version 2 of the License. 8 9 Red Hat elfutils is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 General Public License for more details. 13 14 You should have received a copy of the GNU General Public License along 15 with Red Hat elfutils; if not, write to the Free Software Foundation, 16 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. 17 18 Red Hat elfutils is an included package of the Open Invention Network. 19 An included package of the Open Invention Network is a package for which 20 Open Invention Network licensees cross-license their patents. No patent 21 license is granted, either expressly or impliedly, by designation as an 22 included package. Should you wish to participate in the Open Invention 23 Network licensing program, please visit www.openinventionnetwork.com 24 <http://www.openinventionnetwork.com>. */ 25 26 #ifdef HAVE_CONFIG_H 27 # include <config.h> 28 #endif 29 30 #include <assert.h> 31 #include <dwarf.h> 32 33 #define BACKEND ia64_ 34 #include "libebl_CPU.h" 35 36 37 /* r8, or pair r8, r9, or aggregate up to r8-r11. */ 38 static const Dwarf_Op loc_intreg[] = 39 { 40 { .atom = DW_OP_reg8 }, { .atom = DW_OP_piece, .number = 8 }, 41 { .atom = DW_OP_reg9 }, { .atom = DW_OP_piece, .number = 8 }, 42 { .atom = DW_OP_reg10 }, { .atom = DW_OP_piece, .number = 8 }, 43 { .atom = DW_OP_reg11 }, { .atom = DW_OP_piece, .number = 8 }, 44 }; 45 #define nloc_intreg 1 46 #define nloc_intregs(n) (2 * (n)) 47 48 /* f8, or aggregate up to f8-f15. */ 49 #define DEFINE_FPREG(size) \ 50 static const Dwarf_Op loc_fpreg_##size[] = \ 51 { \ 52 { .atom = DW_OP_regx, .number = 128 + 8 }, \ 53 { .atom = DW_OP_piece, .number = size }, \ 54 { .atom = DW_OP_regx, .number = 128 + 9 }, \ 55 { .atom = DW_OP_piece, .number = size }, \ 56 { .atom = DW_OP_regx, .number = 128 + 10 }, \ 57 { .atom = DW_OP_piece, .number = size }, \ 58 { .atom = DW_OP_regx, .number = 128 + 11 }, \ 59 { .atom = DW_OP_piece, .number = size }, \ 60 { .atom = DW_OP_regx, .number = 128 + 12 }, \ 61 { .atom = DW_OP_piece, .number = size }, \ 62 { .atom = DW_OP_regx, .number = 128 + 13 }, \ 63 { .atom = DW_OP_piece, .number = size }, \ 64 { .atom = DW_OP_regx, .number = 128 + 14 }, \ 65 { .atom = DW_OP_piece, .number = size }, \ 66 { .atom = DW_OP_regx, .number = 128 + 15 }, \ 67 { .atom = DW_OP_piece, .number = size }, \ 68 } 69 #define nloc_fpreg 1 70 #define nloc_fpregs(n) (2 * (n)) 71 72 DEFINE_FPREG (4); 73 DEFINE_FPREG (8); 74 DEFINE_FPREG (10); 75 76 #undef DEFINE_FPREG 77 78 79 /* The return value is a structure and is actually stored in stack space 80 passed in a hidden argument by the caller. But, the compiler 81 helpfully returns the address of that space in r8. */ 82 static const Dwarf_Op loc_aggregate[] = 83 { 84 { .atom = DW_OP_breg8, .number = 0 } 85 }; 86 #define nloc_aggregate 1 87 88 89 /* If this type is an HFA small enough to be returned in FP registers, 90 return the number of registers to use. Otherwise 9, or -1 for errors. */ 91 static int 92 hfa_type (Dwarf_Die *typedie, const Dwarf_Op **locp, int fpregs_used) 93 { 94 /* Descend the type structure, counting elements and finding their types. 95 If we find a datum that's not an FP type (and not quad FP), punt. 96 If we find a datum that's not the same FP type as the first datum, punt. 97 If we count more than eight total homogeneous FP data, punt. */ 98 99 inline int hfa (const Dwarf_Op *loc, int nregs) 100 { 101 if (fpregs_used == 0) 102 *locp = loc; 103 else if (*locp != loc) 104 return 9; 105 return fpregs_used + nregs; 106 } 107 108 int tag = dwarf_tag (typedie); 109 switch (tag) 110 { 111 Dwarf_Attribute attr_mem; 112 113 case -1: 114 return -1; 115 116 case DW_TAG_base_type:; 117 int size = dwarf_bytesize (typedie); 118 if (size < 0) 119 return -1; 120 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 if (tag == DW_TAG_union_type) 182 { 183 int used = hfa_type (child_typedie, locp, fpregs_used); 184 if (used < 0 || used > 8) 185 return used; 186 if (used > max_used) 187 max_used = used; 188 } 189 else 190 { 191 fpregs_used = hfa_type (child_typedie, locp, fpregs_used); 192 if (fpregs_used < 0 || fpregs_used > 8) 193 return fpregs_used; 194 } 195 } 196 while (dwarf_siblingof (&child_mem, &child_mem) == 0); 197 if (tag == DW_TAG_union_type) 198 fpregs_used = max_used; 199 break; 200 } 201 break; 202 203 case DW_TAG_array_type:; 204 size = dwarf_bytesize (typedie); 205 if (size < 0) 206 return 9; 207 if (size == 0) 208 break; 209 210 Dwarf_Die base_type_mem; 211 Dwarf_Die *base_typedie 212 = dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type, 213 &attr_mem), 214 &base_type_mem); 215 216 int used = hfa_type (base_typedie, locp, 0); 217 if (used < 0 || used > 8) 218 return used; 219 if (size % (*locp)[1].number != 0) 220 return 0; 221 size /= (*locp)[1].number; 222 fpregs_used += used * size; 223 break; 224 225 default: 226 return 9; 227 } 228 229 return fpregs_used; 230 } 231 232 int 233 ia64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) 234 { 235 /* Start with the function's type, and get the DW_AT_type attribute, 236 which is the type of the return value. */ 237 238 Dwarf_Attribute attr_mem; 239 Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type, 240 &attr_mem); 241 if (attr == NULL) 242 /* The function has no return value, like a `void' function in C. */ 243 return 0; 244 245 Dwarf_Die die_mem; 246 Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem); 247 int tag = dwarf_tag (typedie); 248 249 /* Follow typedefs and qualifiers to get to the actual type. */ 250 while (tag == DW_TAG_typedef 251 || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type 252 || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type) 253 { 254 attr = dwarf_attr (typedie, DW_AT_type, &attr_mem); 255 typedie = dwarf_formref_die (attr, &die_mem); 256 tag = dwarf_tag (typedie); 257 } 258 259 Dwarf_Word size; 260 switch (tag) 261 { 262 case -1: 263 return -1; 264 265 case DW_TAG_subrange_type: 266 if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) 267 { 268 attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); 269 typedie = dwarf_formref_die (attr, &die_mem); 270 tag = dwarf_tag (typedie); 271 } 272 /* Fall through. */ 273 274 case DW_TAG_base_type: 275 case DW_TAG_enumeration_type: 276 case DW_TAG_pointer_type: 277 case DW_TAG_ptr_to_member_type: 278 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, 279 &attr_mem), &size) != 0) 280 { 281 if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) 282 size = 8; 283 else 284 return -1; 285 } 286 if (tag == DW_TAG_base_type) 287 { 288 Dwarf_Word encoding; 289 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, 290 &attr_mem), 291 &encoding) != 0) 292 return -1; 293 294 switch (encoding) 295 { 296 case DW_ATE_float: 297 switch (size) 298 { 299 case 4: /* float */ 300 *locp = loc_fpreg_4; 301 return nloc_fpreg; 302 case 8: /* double */ 303 *locp = loc_fpreg_8; 304 return nloc_fpreg; 305 case 10: /* x86-style long double, not really used */ 306 *locp = loc_fpreg_10; 307 return nloc_fpreg; 308 case 16: /* long double, IEEE quad format */ 309 *locp = loc_intreg; 310 return nloc_intregs (2); 311 } 312 return -2; 313 314 case DW_ATE_complex_float: 315 switch (size) 316 { 317 case 4 * 2: /* complex float */ 318 *locp = loc_fpreg_4; 319 return nloc_fpregs (2); 320 case 8 * 2: /* complex double */ 321 *locp = loc_fpreg_8; 322 return nloc_fpregs (2); 323 case 10 * 2: /* complex long double (x86-style) */ 324 *locp = loc_fpreg_10; 325 return nloc_fpregs (2); 326 case 16 * 2: /* complex long double (IEEE quad) */ 327 *locp = loc_intreg; 328 return nloc_intregs (4); 329 } 330 return -2; 331 } 332 } 333 334 intreg: 335 *locp = loc_intreg; 336 if (size <= 8) 337 return nloc_intreg; 338 if (size <= 32) 339 return nloc_intregs ((size + 7) / 8); 340 341 large: 342 *locp = loc_aggregate; 343 return nloc_aggregate; 344 345 case DW_TAG_structure_type: 346 case DW_TAG_class_type: 347 case DW_TAG_union_type: 348 case DW_TAG_array_type: 349 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, 350 &attr_mem), &size) != 0) 351 return -1; 352 353 /* If this qualifies as an homogeneous floating-point aggregate 354 (HFA), then it should be returned in FP regs. */ 355 int nfpreg = hfa_type (typedie, locp, 0); 356 if (nfpreg < 0) 357 return nfpreg; 358 else if (nfpreg > 0 && nfpreg <= 8) 359 return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg); 360 361 if (size > 32) 362 goto large; 363 364 goto intreg; 365 } 366 367 /* XXX We don't have a good way to return specific errors from ebl calls. 368 This value means we do not understand the type, but it is well-formed 369 DWARF and might be valid. */ 370 return -2; 371 } 372