|
|
1.1 ! root 1: /* Output variables, constants and external declarations, for GNU compiler. ! 2: Copyright (C) 1987, 1988 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU CC. ! 5: ! 6: GNU CC is distributed in the hope that it will be useful, ! 7: but WITHOUT ANY WARRANTY. No author or distributor ! 8: accepts responsibility to anyone for the consequences of using it ! 9: or for whether it serves any particular purpose or works at all, ! 10: unless he says so in writing. Refer to the GNU CC General Public ! 11: License for full details. ! 12: ! 13: Everyone is granted permission to copy, modify and redistribute ! 14: GNU CC, but only under the conditions described in the ! 15: GNU CC General Public License. A copy of this license is ! 16: supposed to have been given to you along with GNU CC so you ! 17: can know your rights and responsibilities. It should be in a ! 18: file named COPYING. Among other things, the copyright notice ! 19: and this notice must be preserved on all copies. */ ! 20: ! 21: ! 22: /* This file handles generation of all the assembler code ! 23: *except* the instructions of a function. ! 24: This includes declarations of variables and their initial values. ! 25: ! 26: We also output the assembler code for constants stored in memory ! 27: and are responsible for combining constants with the same value. */ ! 28: ! 29: #include <stdio.h> ! 30: /* #include <stab.h> */ ! 31: #include "config.h" ! 32: #include "rtl.h" ! 33: #include "tree.h" ! 34: #include "flags.h" ! 35: #include "expr.h" ! 36: ! 37: #include "obstack.h" ! 38: ! 39: #define MIN(a, b) ((a) < (b) ? (a) : (b)) ! 40: ! 41: /* File in which assembler code is being written. */ ! 42: ! 43: extern FILE *asm_out_file; ! 44: ! 45: extern struct obstack *current_obstack; ! 46: extern struct obstack *saveable_obstack; ! 47: extern struct obstack permanent_obstack; ! 48: #define obstack_chunk_alloc xmalloc ! 49: extern int xmalloc (); ! 50: ! 51: /* Number for making the label on the next ! 52: constant that is stored in memory. */ ! 53: ! 54: int const_labelno; ! 55: ! 56: /* Number for making the label on the next ! 57: static variable internal to a function. */ ! 58: ! 59: int var_labelno; ! 60: ! 61: extern FILE *asm_out_file; ! 62: ! 63: static char *compare_constant_1 (); ! 64: static void record_constant_1 (); ! 65: void assemble_name (); ! 66: void output_addressed_constants (); ! 67: void output_constant (); ! 68: void output_constructor (); ! 69: ! 70: /* Output a string of literal assembler code ! 71: for an `asm' keyword used between functions. */ ! 72: ! 73: void ! 74: assemble_asm (string) ! 75: tree string; ! 76: { ! 77: app_enable (); ! 78: ! 79: fprintf (asm_out_file, "\t%s\n", TREE_STRING_POINTER (string)); ! 80: } ! 81: ! 82: /* Output assembler code associated with defining the name of a function ! 83: as described by DECL. */ ! 84: ! 85: void ! 86: assemble_function (decl) ! 87: tree decl; ! 88: { ! 89: rtx x, n; ! 90: char *fnname; ! 91: ! 92: /* Get the function's name, as described by its RTL. ! 93: This may be different from the DECL_NAME name used in the source file. */ ! 94: ! 95: x = DECL_RTL (decl); ! 96: if (GET_CODE (x) != MEM) ! 97: abort (); ! 98: n = XEXP (x, 0); ! 99: if (GET_CODE (n) != SYMBOL_REF) ! 100: abort (); ! 101: fnname = XSTR (n, 0); ! 102: ! 103: /* The following code does not need preprocessing in the assembler. */ ! 104: ! 105: app_disable (); ! 106: ! 107: /* Tell assembler to switch to text segment. */ ! 108: ! 109: fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP); ! 110: ! 111: /* Tell assembler to move to target machine's alignment for functions. */ ! 112: ! 113: ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT)); ! 114: ! 115: /* Make function name accessible from other files, if appropriate. */ ! 116: ! 117: if (TREE_PUBLIC (decl)) ! 118: ASM_GLOBALIZE_LABEL (asm_out_file, fnname); ! 119: ! 120: /* Do any machine/system dependent processing of the function name */ ! 121: #ifdef ASM_DECLARE_FUNCTION_NAME ! 122: ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname); ! 123: #else ! 124: /* Standard thing is just output label for the function. */ ! 125: ASM_OUTPUT_LABEL (asm_out_file, fnname); ! 126: #endif /* ASM_DECLARE_FUNCTION_NAME */ ! 127: } ! 128: ! 129: /* Assemble " .int 0\n" or whatever this assembler wants. */ ! 130: ! 131: void ! 132: assemble_integer_zero () ! 133: { ! 134: ASM_OUTPUT_INT (asm_out_file, const0_rtx); ! 135: } ! 136: ! 137: /* Create the rtx to represent a function in calls to it. ! 138: DECL is a FUNCTION_DECL node which describes which function. ! 139: The rtl is stored in DECL. */ ! 140: ! 141: void ! 142: make_function_rtl (decl) ! 143: tree decl; ! 144: { ! 145: if (DECL_RTL (decl) == 0) ! 146: DECL_RTL (decl) ! 147: = gen_rtx (MEM, DECL_MODE (decl), ! 148: gen_rtx (SYMBOL_REF, Pmode, ! 149: IDENTIFIER_POINTER (DECL_NAME (decl)))); ! 150: } ! 151: ! 152: /* Assemble everything that is needed for a variable or function declaration. ! 153: Not used for automatic variables, and not used for function definitions. ! 154: Should not be called for variables of incomplete structure type. ! 155: ! 156: ASMSPEC is the user's specification of assembler symbol name to use. ! 157: TOP_LEVEL is nonzero if this variable has file scope. ! 158: WRITE_SYMBOLS is 2 if writing dbx symbol output. ! 159: The dbx data for a file-scope variable is written here. ! 160: AT_END is nonzero if this is the special handling, at end of compilation, ! 161: to define things that have had only tentative definitions. */ ! 162: ! 163: void ! 164: assemble_variable (decl, asmspec, top_level, write_symbols, at_end) ! 165: tree decl; ! 166: tree asmspec; ! 167: int top_level; ! 168: int write_symbols; ! 169: int at_end; ! 170: { ! 171: register char *name = IDENTIFIER_POINTER (DECL_NAME (decl)); ! 172: register int i; ! 173: ! 174: if (asmspec != 0) ! 175: { ! 176: if (TREE_CODE (asmspec) != STRING_CST) ! 177: abort (); ! 178: name = (char *) oballoc (strlen (TREE_STRING_POINTER (asmspec)) + 2); ! 179: name[0] = '*'; ! 180: strcpy (&name[1], TREE_STRING_POINTER (asmspec)); ! 181: } ! 182: ! 183: /* For a duplicate declaration, we can be called twice on the ! 184: same DECL node. Don't alter the RTL already made ! 185: unless the old mode is wrong (which can happen when ! 186: the previous rtl was made when the type was incomplete). */ ! 187: if (DECL_RTL (decl) == 0 ! 188: || GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl)) ! 189: { ! 190: if (DECL_RTL (decl) && asmspec == 0) ! 191: name = XSTR (XEXP (DECL_RTL (decl), 0), 0); ! 192: ! 193: /* Can't use just the variable's own name for a variable ! 194: whose scope is less than the whole file. ! 195: Concatenate a distinguishing number. */ ! 196: else if (!top_level && !TREE_EXTERNAL (decl) && asmspec == 0) ! 197: { ! 198: char *label; ! 199: ! 200: ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno); ! 201: name = obstack_copy0 (current_obstack, label, strlen (label)); ! 202: var_labelno++; ! 203: } ! 204: ! 205: DECL_RTL (decl) = gen_rtx (MEM, DECL_MODE (decl), ! 206: gen_rtx (SYMBOL_REF, Pmode, name)); ! 207: if (TREE_VOLATILE (decl)) ! 208: DECL_RTL (decl)->volatil = 1; ! 209: if (TREE_READONLY (decl)) ! 210: DECL_RTL (decl)->unchanging = 1; ! 211: DECL_RTL (decl)->in_struct ! 212: = (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE ! 213: || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE ! 214: || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE); ! 215: } ! 216: ! 217: /* Output no assembler code for a function declaration. ! 218: Only definitions of functions output anything. */ ! 219: ! 220: if (TREE_CODE (decl) == FUNCTION_DECL) ! 221: return; ! 222: ! 223: /* Normally no need to say anything for external references, ! 224: since assembler considers all undefined symbols external. */ ! 225: ! 226: if (TREE_EXTERNAL (decl)) ! 227: { ! 228: #ifdef ASM_OUTPUT_EXTERNAL ! 229: /* Some systems do require some output. */ ! 230: ASM_OUTPUT_EXTERNAL (asm_out_file, decl, name); ! 231: #endif ! 232: return; ! 233: } ! 234: /* Don't output anything when a tentative file-scope definition is seen. ! 235: But at end of compilation, do output code for them. */ ! 236: if (! at_end && top_level ! 237: && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node)) ! 238: return; ! 239: ! 240: /* If type was incomplete when the variable was declared, ! 241: see if it is complete now. */ ! 242: ! 243: if (DECL_SIZE (decl) == 0) ! 244: layout_decl (decl); ! 245: ! 246: /* Still incomplete => don't allocate it; treat the tentative defn ! 247: (which is what it must have been) as an `extern' reference. */ ! 248: ! 249: if (DECL_SIZE (decl) == 0) ! 250: { ! 251: error_with_file_and_line (DECL_SOURCE_FILE (decl), ! 252: DECL_SOURCE_LINE (decl), ! 253: "storage size of static var `%s' isn't known", ! 254: IDENTIFIER_POINTER (DECL_NAME (decl))); ! 255: return; ! 256: } ! 257: ! 258: /* The first declaration of a variable that comes through this function ! 259: decides whether it is global (in C, has external linkage) ! 260: or local (in C, has internal linkage). So do nothing more ! 261: if this function has already run. */ ! 262: ! 263: if (TREE_ASM_WRITTEN (decl)) ! 264: return; ! 265: ! 266: TREE_ASM_WRITTEN (decl) = 1; ! 267: ! 268: if (write_symbols == 2) ! 269: dbxout_symbol (decl, 0); ! 270: else if (write_symbols != 0) ! 271: /* Make sure the file is known to GDB even if it has no functions. */ ! 272: set_current_gdbfile (DECL_SOURCE_FILE (decl)); ! 273: ! 274: /* If storage size is erroneously variable, just continue. ! 275: Error message was already made. */ ! 276: ! 277: if (! TREE_LITERAL (DECL_SIZE (decl))) ! 278: return; ! 279: ! 280: app_disable (); ! 281: ! 282: /* Handle uninitialized definitions. */ ! 283: ! 284: if (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node) ! 285: { ! 286: int size = (TREE_INT_CST_LOW (DECL_SIZE (decl)) ! 287: * DECL_SIZE_UNIT (decl) ! 288: / BITS_PER_UNIT); ! 289: /* Round size up to multiple of BIGGEST_ALIGNMENT bits ! 290: so that each uninitialized object starts on such a boundary. */ ! 291: size = ((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1) ! 292: / (BIGGEST_ALIGNMENT / BITS_PER_UNIT) ! 293: * (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); ! 294: if (TREE_PUBLIC (decl)) ! 295: ASM_OUTPUT_COMMON (asm_out_file, name, size); ! 296: else ! 297: ASM_OUTPUT_LOCAL (asm_out_file, name, size); ! 298: return; ! 299: } ! 300: ! 301: /* Handle initialized definitions. */ ! 302: ! 303: if (TREE_PUBLIC (decl)) ! 304: ASM_GLOBALIZE_LABEL (asm_out_file, name); ! 305: ! 306: output_addressed_constants (DECL_INITIAL (decl)); ! 307: ! 308: if (TREE_READONLY (decl) && ! TREE_VOLATILE (decl)) ! 309: fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP); ! 310: else ! 311: fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP); ! 312: ! 313: for (i = 0; DECL_ALIGN (decl) >= BITS_PER_UNIT << (i + 1); i++); ! 314: ! 315: ASM_OUTPUT_ALIGN (asm_out_file, i); ! 316: ! 317: ASM_OUTPUT_LABEL (asm_out_file, name); ! 318: output_constant (DECL_INITIAL (decl), int_size_in_bytes (TREE_TYPE (decl))); ! 319: } ! 320: ! 321: /* Output to FILE a reference to the assembler name of a C-level name NAME. ! 322: If NAME starts with a *, the rest of NAME is output verbatim. ! 323: Otherwise NAME is transformed in an implementation-defined way ! 324: (usually by the addition of an underscore). ! 325: Many macros in the tm file are defined to call this function. */ ! 326: ! 327: void ! 328: assemble_name (file, name) ! 329: FILE *file; ! 330: char *name; ! 331: { ! 332: if (name[0] == '*') ! 333: fputs (&name[1], file); ! 334: else ! 335: ASM_OUTPUT_LABELREF (file, name); ! 336: } ! 337: ! 338: /* Here we combine duplicate floating constants to make ! 339: CONST_DOUBLE rtx's, and force those out to memory when necessary. */ ! 340: ! 341: /* Chain of all CONST_DOUBLE rtx's constructed for the current function. ! 342: They are chained through the third operand slot. */ ! 343: ! 344: extern rtx real_constant_chain; ! 345: ! 346: /* Return a CONST_DOUBLE for a specified `double' value ! 347: and machine mode. */ ! 348: ! 349: rtx ! 350: immed_real_const_1 (d, mode) ! 351: double d; ! 352: enum machine_mode mode; ! 353: ! 354: { ! 355: register rtx r; ! 356: union {double d; int i[2];} u; ! 357: register int i0, i1; ! 358: ! 359: /* Get the desired `double' value as two ints ! 360: since that is how they are stored in a CONST_DOUBLE. */ ! 361: ! 362: u.d = d; ! 363: i0 = u.i[0]; ! 364: i1 = u.i[1]; ! 365: ! 366: /* Search the chain for an existing CONST_DOUBLE with the right value. ! 367: If one is found, return it. */ ! 368: ! 369: for (r = real_constant_chain; r; r = XEXP (r, 3)) ! 370: if (XINT (r, 0) == i0 && XINT (r, 1) == i1 ! 371: && GET_MODE (r) == mode) ! 372: return r; ! 373: ! 374: /* No; make a new one and add it to the chain. */ ! 375: ! 376: r = gen_rtx (CONST_DOUBLE, mode, i0, i1, 0); ! 377: XEXP (r, 3) = real_constant_chain; ! 378: real_constant_chain = r; ! 379: ! 380: /* Store const0_rtx in slot 2 just so most things won't barf. ! 381: Actual use of slot 2 is only through force_const_double_mem. */ ! 382: ! 383: XEXP (r, 2) = const0_rtx; ! 384: ! 385: return r; ! 386: } ! 387: ! 388: /* Return a CONST_DOUBLE rtx for a value specified by EXP, ! 389: which must be a REAL_CST tree node. Make only one CONST_DOUBLE ! 390: for each distinct value. */ ! 391: ! 392: rtx ! 393: immed_real_const (exp) ! 394: tree exp; ! 395: { ! 396: register rtx r; ! 397: r = immed_real_const_1 (TREE_REAL_CST (exp), TYPE_MODE (TREE_TYPE (exp))); ! 398: ! 399: /* Associate exp and with this rtl value. */ ! 400: TREE_CST_RTL (exp) = r; ! 401: ! 402: return r; ! 403: } ! 404: ! 405: /* Given a CONST_DOUBLE, cause a constant in memory to be created ! 406: (unless we already have one for the same value) ! 407: and return a MEM rtx to refer to it. */ ! 408: ! 409: rtx ! 410: force_const_double_mem (r) ! 411: rtx r; ! 412: { ! 413: if (XEXP (r, 2) == const0_rtx) ! 414: { ! 415: XEXP (r, 2) = force_const_mem (GET_MODE (r), r); ! 416: } ! 417: /* XEXP (r, 2) is now a MEM with a constant address. ! 418: If that is legitimate, return it. ! 419: Othewise it will need reloading, so return a copy of it. */ ! 420: if (memory_address_p (GET_MODE (r), XEXP (XEXP (r, 2), 0))) ! 421: return XEXP (r, 2); ! 422: return gen_rtx (MEM, GET_MODE (r), XEXP (XEXP (r, 2), 0)); ! 423: } ! 424: ! 425: /* At the start of a function, forget the memory-constants ! 426: previously made for CONST_DOUBLEs. */ ! 427: ! 428: static void ! 429: clear_const_double_mem () ! 430: { ! 431: register rtx r; ! 432: ! 433: for (r = real_constant_chain; r; r = XEXP (r, 3)) ! 434: XEXP (r, 2) = 0; ! 435: } ! 436: ! 437: /* Given an expression EXP with a constant value, ! 438: reduce it to the sum of an assembler symbol and an integer. ! 439: Store them both in the structure *VALUE. ! 440: Abort if EXP does not reduce. */ ! 441: ! 442: struct addr_const ! 443: { ! 444: rtx base; ! 445: int offset; ! 446: }; ! 447: ! 448: static void ! 449: decode_addr_const (exp, value) ! 450: tree exp; ! 451: struct addr_const *value; ! 452: { ! 453: register tree target = TREE_OPERAND (exp, 0); ! 454: register int offset = 0; ! 455: register rtx x; ! 456: ! 457: while (1) ! 458: { ! 459: if (TREE_CODE (target) == COMPONENT_REF) ! 460: { ! 461: offset += DECL_OFFSET (TREE_OPERAND (target, 1)) / BITS_PER_UNIT; ! 462: target = TREE_OPERAND (target, 0); ! 463: } ! 464: else if (TREE_CODE (target) == ARRAY_REF) ! 465: { ! 466: if (TREE_CODE (TREE_OPERAND (target, 1)) != INTEGER_CST ! 467: || TREE_CODE (TYPE_SIZE (TREE_TYPE (target))) != INTEGER_CST) ! 468: abort (); ! 469: offset += ((TYPE_SIZE_UNIT (TREE_TYPE (target)) ! 470: * TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (target))) ! 471: * TREE_INT_CST_LOW (TREE_OPERAND (target, 1))) ! 472: / BITS_PER_UNIT); ! 473: target = TREE_OPERAND (target, 0); ! 474: } ! 475: else break; ! 476: } ! 477: ! 478: if (TREE_CODE (target) == VAR_DECL ! 479: || TREE_CODE (target) == FUNCTION_DECL) ! 480: x = DECL_RTL (target); ! 481: else if (TREE_LITERAL (target)) ! 482: x = TREE_CST_RTL (target); ! 483: else ! 484: abort (); ! 485: ! 486: if (GET_CODE (x) != MEM) ! 487: abort (); ! 488: x = XEXP (x, 0); ! 489: ! 490: value->base = x; ! 491: value->offset = offset; ! 492: } ! 493: ! 494: /* Uniquize all constants that appear in memory. ! 495: Each constant in memory thus far output is recorded ! 496: in `const_hash_table' with a `struct constant_descriptor' ! 497: that contains a polish representation of the value of ! 498: the constant. ! 499: ! 500: We cannot store the trees in the hash table ! 501: because the trees may be temporary. */ ! 502: ! 503: struct constant_descriptor ! 504: { ! 505: struct constant_descriptor *next; ! 506: char *label; ! 507: char contents[1]; ! 508: }; ! 509: ! 510: #define HASHBITS 30 ! 511: #define MAX_HASH_TABLE 1007 ! 512: static struct constant_descriptor *const_hash_table[MAX_HASH_TABLE]; ! 513: ! 514: /* Compute a hash code for a constant expression. */ ! 515: ! 516: int ! 517: const_hash (exp) ! 518: tree exp; ! 519: { ! 520: register char *p; ! 521: register int len, hi, i; ! 522: register enum tree_code code = TREE_CODE (exp); ! 523: ! 524: if (code == INTEGER_CST) ! 525: { ! 526: p = (char *) &TREE_INT_CST_LOW (exp); ! 527: len = 2 * sizeof TREE_INT_CST_LOW (exp); ! 528: } ! 529: else if (code == REAL_CST) ! 530: { ! 531: p = (char *) &TREE_REAL_CST (exp); ! 532: len = sizeof TREE_REAL_CST (exp); ! 533: } ! 534: else if (code == STRING_CST) ! 535: p = TREE_STRING_POINTER (exp), len = TREE_STRING_LENGTH (exp); ! 536: else if (code == COMPLEX_CST) ! 537: return const_hash (TREE_REALPART (exp)) * 5 ! 538: + const_hash (TREE_IMAGPART (exp)); ! 539: else if (code == CONSTRUCTOR) ! 540: { ! 541: register tree link; ! 542: hi = 5; ! 543: for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link)) ! 544: hi = (hi * 603 + const_hash (TREE_VALUE (link))) % MAX_HASH_TABLE; ! 545: return hi; ! 546: } ! 547: else if (code == ADDR_EXPR) ! 548: { ! 549: struct addr_const value; ! 550: decode_addr_const (exp, &value); ! 551: p = (char *) &value; ! 552: len = sizeof value; ! 553: } ! 554: else if (code == PLUS_EXPR || code == MINUS_EXPR) ! 555: return const_hash (TREE_OPERAND (exp, 0)) * 9 ! 556: + const_hash (TREE_OPERAND (exp, 1)); ! 557: else if (code == NOP_EXPR || code == CONVERT_EXPR) ! 558: return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2; ! 559: ! 560: /* Compute hashing function */ ! 561: hi = len; ! 562: for (i = 0; i < len; i++) ! 563: hi = ((hi * 613) + (unsigned)(p[i])); ! 564: ! 565: hi &= (1 << HASHBITS) - 1; ! 566: hi %= MAX_HASH_TABLE; ! 567: return hi; ! 568: } ! 569: ! 570: /* Compare a constant expression EXP with a constant-descriptor DESC. ! 571: Return 1 if DESC describes a constant with the same value as EXP. */ ! 572: ! 573: static int ! 574: compare_constant (exp, desc) ! 575: tree exp; ! 576: struct constant_descriptor *desc; ! 577: { ! 578: return 0 != compare_constant_1 (exp, desc->contents); ! 579: } ! 580: ! 581: /* Compare constant expression EXP with a substring P of a constant descriptor. ! 582: If they match, return a pointer to the end of the substring matched. ! 583: If they do not match, return 0. ! 584: ! 585: Since descriptors are written in polish prefix notation, ! 586: this function can be used recursively to test one operand of EXP ! 587: against a subdescriptor, and if it succeeds it returns the ! 588: address of the subdescriptor for the next operand. */ ! 589: ! 590: static char * ! 591: compare_constant_1 (exp, p) ! 592: tree exp; ! 593: char *p; ! 594: { ! 595: register char *strp; ! 596: register int len; ! 597: register enum tree_code code = TREE_CODE (exp); ! 598: ! 599: if (code != (enum tree_code) *p++) ! 600: return 0; ! 601: ! 602: if (code == INTEGER_CST) ! 603: { ! 604: strp = (char *) &TREE_INT_CST_LOW (exp); ! 605: len = 2 * sizeof TREE_INT_CST_LOW (exp); ! 606: } ! 607: else if (code == REAL_CST) ! 608: { ! 609: /* Real constants are the same only if the same width of type. */ ! 610: if (*p++ != TYPE_PRECISION (TREE_TYPE (exp))) ! 611: return 0; ! 612: strp = (char *) &TREE_REAL_CST (exp); ! 613: len = sizeof TREE_REAL_CST (exp); ! 614: } ! 615: else if (code == STRING_CST) ! 616: { ! 617: if (flag_writable_strings) ! 618: return 0; ! 619: strp = TREE_STRING_POINTER (exp); ! 620: len = TREE_STRING_LENGTH (exp); ! 621: if (bcmp (&TREE_STRING_LENGTH (exp), p, ! 622: sizeof TREE_STRING_LENGTH (exp))) ! 623: return 0; ! 624: p += sizeof TREE_STRING_LENGTH (exp); ! 625: } ! 626: else if (code == COMPLEX_CST) ! 627: { ! 628: p = compare_constant_1 (TREE_REALPART (exp), p); ! 629: if (p == 0) return 0; ! 630: p = compare_constant_1 (TREE_IMAGPART (exp), p); ! 631: return p; ! 632: } ! 633: else if (code == CONSTRUCTOR) ! 634: { ! 635: register tree link; ! 636: int length = list_length (CONSTRUCTOR_ELTS (exp)); ! 637: if (bcmp (&length, p, sizeof length)) ! 638: return 0; ! 639: p += sizeof length; ! 640: for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link)) ! 641: if ((p = compare_constant_1 (TREE_VALUE (link), p)) == 0) ! 642: return 0; ! 643: return p; ! 644: } ! 645: else if (code == ADDR_EXPR) ! 646: { ! 647: struct addr_const value; ! 648: decode_addr_const (exp, &value); ! 649: strp = (char *) &value; ! 650: len = sizeof value; ! 651: } ! 652: else if (code == PLUS_EXPR || code == MINUS_EXPR) ! 653: { ! 654: if (*p++ != (char) code) ! 655: return 0; ! 656: p = compare_constant_1 (TREE_OPERAND (exp, 0), p); ! 657: if (p == 0) return 0; ! 658: p = compare_constant_1 (TREE_OPERAND (exp, 1), p); ! 659: return p; ! 660: } ! 661: else if (code == NOP_EXPR || code == CONVERT_EXPR) ! 662: { ! 663: if (*p++ != (char) code) ! 664: return 0; ! 665: p = compare_constant_1 (TREE_OPERAND (exp, 0), p); ! 666: return p; ! 667: } ! 668: ! 669: /* Compare constant contents. */ ! 670: while (--len >= 0) ! 671: if (*p++ != *strp++) ! 672: return 0; ! 673: ! 674: return p; ! 675: } ! 676: ! 677: /* Construct a constant descriptor for the expression EXP. ! 678: It is up to the caller to enter the descriptor in the hash table. */ ! 679: ! 680: static struct constant_descriptor * ! 681: record_constant (exp) ! 682: tree exp; ! 683: { ! 684: struct constant_descriptor *ptr = 0; ! 685: int buf; ! 686: ! 687: obstack_grow (&permanent_obstack, &ptr, sizeof ptr); ! 688: obstack_grow (&permanent_obstack, &buf, sizeof buf); ! 689: record_constant_1 (exp); ! 690: return (struct constant_descriptor *) obstack_finish (&permanent_obstack); ! 691: } ! 692: ! 693: /* Add a description of constant expression EXP ! 694: to the object growing in `permanent_obstack'. ! 695: No need to return its address; the caller will get that ! 696: from the obstack when the object is complete. */ ! 697: ! 698: static void ! 699: record_constant_1 (exp) ! 700: tree exp; ! 701: { ! 702: register char *strp; ! 703: register int len; ! 704: register enum tree_code code = TREE_CODE (exp); ! 705: ! 706: obstack_1grow (&permanent_obstack, (unsigned char) code); ! 707: ! 708: if (code == INTEGER_CST) ! 709: { ! 710: strp = (char *) &TREE_INT_CST_LOW (exp); ! 711: len = 2 * sizeof TREE_INT_CST_LOW (exp); ! 712: } ! 713: else if (code == REAL_CST) ! 714: { ! 715: obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp))); ! 716: strp = (char *) &TREE_REAL_CST (exp); ! 717: len = sizeof TREE_REAL_CST (exp); ! 718: } ! 719: else if (code == STRING_CST) ! 720: { ! 721: if (flag_writable_strings) ! 722: return; ! 723: strp = TREE_STRING_POINTER (exp); ! 724: len = TREE_STRING_LENGTH (exp); ! 725: obstack_grow (&permanent_obstack, (char *) &TREE_STRING_LENGTH (exp), ! 726: sizeof TREE_STRING_LENGTH (exp)); ! 727: } ! 728: else if (code == COMPLEX_CST) ! 729: { ! 730: record_constant_1 (TREE_REALPART (exp)); ! 731: record_constant_1 (TREE_IMAGPART (exp)); ! 732: return; ! 733: } ! 734: else if (code == CONSTRUCTOR) ! 735: { ! 736: register tree link; ! 737: int length = list_length (CONSTRUCTOR_ELTS (exp)); ! 738: obstack_grow (&permanent_obstack, (char *) &length, sizeof length); ! 739: ! 740: for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link)) ! 741: record_constant_1 (TREE_VALUE (link)); ! 742: return; ! 743: } ! 744: else if (code == ADDR_EXPR) ! 745: { ! 746: struct addr_const value; ! 747: decode_addr_const (exp, &value); ! 748: strp = (char *) &value; ! 749: len = sizeof value; ! 750: } ! 751: else if (code == PLUS_EXPR || code == MINUS_EXPR) ! 752: { ! 753: obstack_1grow (&permanent_obstack, (char) code); ! 754: record_constant_1 (TREE_OPERAND (exp, 0)); ! 755: record_constant_1 (TREE_OPERAND (exp, 1)); ! 756: return; ! 757: } ! 758: else if (code == NOP_EXPR || code == CONVERT_EXPR) ! 759: { ! 760: obstack_1grow (&permanent_obstack, (char) code); ! 761: record_constant_1 (TREE_OPERAND (exp, 0)); ! 762: return; ! 763: } ! 764: ! 765: /* Record constant contents. */ ! 766: obstack_grow (&permanent_obstack, strp, len); ! 767: } ! 768: ! 769: /* Return the constant-label-string for constant value EXP. ! 770: If no constant equal to EXP has yet been output, ! 771: define a new label and output assembler code for it. ! 772: The const_hash_table records which constants already have label strings. */ ! 773: ! 774: static char * ! 775: get_or_assign_label (exp) ! 776: tree exp; ! 777: { ! 778: register int hash, i; ! 779: register struct constant_descriptor *desc; ! 780: char label[10]; ! 781: ! 782: /* Make sure any other constants whose addresses appear in EXP ! 783: are assigned label numbers. */ ! 784: ! 785: output_addressed_constants (exp); ! 786: ! 787: /* Compute hash code of EXP. Search the descriptors for that hash code ! 788: to see if any of them describes EXP. If yes, the descriptor records ! 789: the label number already assigned. */ ! 790: ! 791: hash = const_hash (exp) % MAX_HASH_TABLE; ! 792: ! 793: for (desc = const_hash_table[hash]; desc; desc = desc->next) ! 794: if (compare_constant (exp, desc)) ! 795: return desc->label; ! 796: ! 797: /* No constant equal to EXP is known to have been output. ! 798: Make a constant descriptor to enter EXP in the hash table. ! 799: Assign the label number and record it in the descriptor for ! 800: future calls to this function to find. */ ! 801: ! 802: desc = record_constant (exp); ! 803: desc->next = const_hash_table[hash]; ! 804: const_hash_table[hash] = desc; ! 805: ! 806: /* Now output assembler code to define that label ! 807: and follow it with the data of EXP. */ ! 808: ! 809: /* First switch to text segment, except for writable strings. */ ! 810: if ((TREE_CODE (exp) == STRING_CST) && flag_writable_strings) ! 811: fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP); ! 812: else ! 813: fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP); ! 814: ! 815: /* Align the location counter as required by EXP's data type. */ ! 816: for (i = 0; TYPE_ALIGN (TREE_TYPE (exp)) >= BITS_PER_UNIT << (i + 1); i++); ! 817: ASM_OUTPUT_ALIGN (asm_out_file, i); ! 818: ! 819: /* Output the label itself. */ ! 820: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", const_labelno); ! 821: ! 822: /* Output the value of EXP. */ ! 823: output_constant (exp, ! 824: (TREE_CODE (exp) == STRING_CST ! 825: ? TREE_STRING_LENGTH (exp) ! 826: : int_size_in_bytes (TREE_TYPE (exp)))); ! 827: ! 828: /* Create a string containing the label name, in LABEL. */ ! 829: ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno); ! 830: ! 831: ++const_labelno; ! 832: ! 833: desc->label ! 834: = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label)); ! 835: ! 836: return desc->label; ! 837: } ! 838: ! 839: /* Return an rtx representing a reference to constant data in memory ! 840: for the constant expression EXP. ! 841: If assembler code for such a constant has already been output, ! 842: return an rtx to refer to it. ! 843: Otherwise, output such a constant in memory and generate ! 844: an rtx for it. The TREE_CST_RTL of EXP is set up to point to that rtx. */ ! 845: ! 846: rtx ! 847: output_constant_def (exp) ! 848: tree exp; ! 849: { ! 850: register rtx def; ! 851: char label[10]; ! 852: ! 853: if (TREE_CST_RTL (exp)) ! 854: return TREE_CST_RTL (exp); ! 855: ! 856: def = gen_rtx (SYMBOL_REF, Pmode, get_or_assign_label (exp)); ! 857: ! 858: TREE_CST_RTL (exp) ! 859: = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), def); ! 860: TREE_CST_RTL (exp)->unchanging = 1; ! 861: ! 862: return TREE_CST_RTL (exp); ! 863: } ! 864: ! 865: /* Similar hash facility for making memory-constants ! 866: from constant rtl-expressions. It is used on RISC machines ! 867: where immediate integer arguments and constant addresses are restricted ! 868: so that such constants must be stored in memory. ! 869: ! 870: This pool of constants is reinitialized for each function ! 871: so each function gets its own constants-pool that comes right before it. */ ! 872: ! 873: #define MAX_RTX_HASH_TABLE 61 ! 874: static struct constant_descriptor *const_rtx_hash_table[MAX_RTX_HASH_TABLE]; ! 875: ! 876: void ! 877: init_const_rtx_hash_table () ! 878: { ! 879: bzero (const_rtx_hash_table, sizeof const_rtx_hash_table); ! 880: clear_const_double_mem (); ! 881: } ! 882: ! 883: struct rtx_const ! 884: { ! 885: enum kind { RTX_DOUBLE, RTX_INT } kind : 16; ! 886: enum machine_mode mode : 16; ! 887: union { ! 888: int d[2]; ! 889: struct addr_const addr; ! 890: } un; ! 891: }; ! 892: ! 893: /* Express an rtx for a constant integer (perhaps symbolic) ! 894: as the sum of a symbol or label plus an explicit integer. ! 895: They are stored into VALUE. */ ! 896: ! 897: static void ! 898: decode_rtx_const (x, value) ! 899: rtx x; ! 900: struct rtx_const *value; ! 901: { ! 902: value->kind = RTX_INT; /* Most usual kind. */ ! 903: value->mode = GET_MODE (x); ! 904: value->un.addr.base = 0; ! 905: value->un.addr.offset = 0; ! 906: ! 907: switch (GET_CODE (x)) ! 908: { ! 909: case CONST_DOUBLE: ! 910: value->kind = RTX_DOUBLE; ! 911: value->mode = GET_MODE (x); ! 912: value->un.d[0] = XINT (x, 0); ! 913: value->un.d[1] = XINT (x, 1); ! 914: break; ! 915: ! 916: case CONST_INT: ! 917: value->un.addr.offset = INTVAL (x); ! 918: break; ! 919: ! 920: case SYMBOL_REF: ! 921: /* Use the string's address, not the SYMBOL_REF's address, ! 922: for the sake of addresses of library routines. */ ! 923: value->un.addr.base = XEXP (x, 0); ! 924: break; ! 925: ! 926: case LABEL_REF: ! 927: /* Return the CODE_LABEL, not the LABEL_REF. */ ! 928: value->un.addr.base = XEXP (x, 0); ! 929: break; ! 930: ! 931: case CONST: ! 932: x = XEXP (x, 0); ! 933: if (GET_CODE (x) == PLUS) ! 934: { ! 935: value->un.addr.base = XEXP (x, 0); ! 936: if (GET_CODE (XEXP (x, 1)) != CONST_INT) ! 937: abort (); ! 938: value->un.addr.offset = INTVAL (XEXP (x, 1)); ! 939: } ! 940: else if (GET_CODE (x) == MINUS) ! 941: { ! 942: value->un.addr.base = XEXP (x, 0); ! 943: if (GET_CODE (XEXP (x, 1)) != CONST_INT) ! 944: abort (); ! 945: value->un.addr.offset = - INTVAL (XEXP (x, 1)); ! 946: } ! 947: else ! 948: abort (); ! 949: break; ! 950: ! 951: default: ! 952: abort (); ! 953: } ! 954: } ! 955: ! 956: /* Compute a hash code for a constant RTL expression. */ ! 957: ! 958: int ! 959: const_hash_rtx (x) ! 960: rtx x; ! 961: { ! 962: register int hi, i, len; ! 963: register char *p; ! 964: ! 965: struct rtx_const value; ! 966: decode_rtx_const (x, &value); ! 967: ! 968: /* Compute hashing function */ ! 969: hi = 0; ! 970: for (i = 0; i < sizeof value / sizeof (int); i++) ! 971: hi += ((int *) &value)[i]; ! 972: ! 973: hi &= (1 << HASHBITS) - 1; ! 974: hi %= MAX_RTX_HASH_TABLE; ! 975: return hi; ! 976: } ! 977: ! 978: /* Compare a constant rtl object X with a constant-descriptor DESC. ! 979: Return 1 if DESC describes a constant with the same value as X. */ ! 980: ! 981: static int ! 982: compare_constant_rtx (x, desc) ! 983: rtx x; ! 984: struct constant_descriptor *desc; ! 985: { ! 986: register int *p = (int *) desc->contents; ! 987: register int *strp; ! 988: register int len; ! 989: struct rtx_const value; ! 990: ! 991: decode_rtx_const (x, &value); ! 992: strp = (int *) &value; ! 993: len = sizeof value / sizeof (int); ! 994: ! 995: /* Compare constant contents. */ ! 996: while (--len >= 0) ! 997: if (*p++ != *strp++) ! 998: return 0; ! 999: ! 1000: return 1; ! 1001: } ! 1002: ! 1003: /* Construct a constant descriptor for the rtl-expression X. ! 1004: It is up to the caller to enter the descriptor in the hash table. */ ! 1005: ! 1006: static struct constant_descriptor * ! 1007: record_constant_rtx (x) ! 1008: rtx x; ! 1009: { ! 1010: struct constant_descriptor *ptr = 0; ! 1011: int buf; ! 1012: struct rtx_const value; ! 1013: ! 1014: decode_rtx_const (x, &value); ! 1015: ! 1016: obstack_grow (saveable_obstack, &ptr, sizeof ptr); ! 1017: obstack_grow (saveable_obstack, &buf, sizeof buf); ! 1018: ! 1019: /* Record constant contents. */ ! 1020: obstack_grow (saveable_obstack, &value, sizeof value); ! 1021: ! 1022: return (struct constant_descriptor *) obstack_finish (saveable_obstack); ! 1023: } ! 1024: ! 1025: /* Given a constant rtx X, make (or find) a memory constant for its value ! 1026: and return a MEM rtx to refer to it in memory. */ ! 1027: ! 1028: rtx ! 1029: force_const_mem (mode, x) ! 1030: enum machine_mode mode; ! 1031: rtx x; ! 1032: { ! 1033: register int hash, i; ! 1034: register struct constant_descriptor *desc; ! 1035: char label[10]; ! 1036: char *found = 0; ! 1037: rtx def; ! 1038: ! 1039: /* Compute hash code of X. Search the descriptors for that hash code ! 1040: to see if any of them describes X. If yes, the descriptor records ! 1041: the label number already assigned. */ ! 1042: ! 1043: hash = const_hash_rtx (x); ! 1044: ! 1045: for (desc = const_rtx_hash_table[hash]; desc; desc = desc->next) ! 1046: if (compare_constant_rtx (x, desc)) ! 1047: { ! 1048: found = desc->label; ! 1049: break; ! 1050: } ! 1051: ! 1052: if (found == 0) ! 1053: { ! 1054: /* No constant equal to X is known to have been output. ! 1055: Make a constant descriptor to enter X in the hash table. ! 1056: Assign the label number and record it in the descriptor for ! 1057: future calls to this function to find. */ ! 1058: ! 1059: desc = record_constant_rtx (x); ! 1060: desc->next = const_rtx_hash_table[hash]; ! 1061: const_rtx_hash_table[hash] = desc; ! 1062: ! 1063: /* Now output assembler code to define that label ! 1064: and follow it with the data of EXP. */ ! 1065: ! 1066: /* First switch to text segment. */ ! 1067: fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP); ! 1068: ! 1069: /* Align the location counter as required by EXP's data type. */ ! 1070: ASM_OUTPUT_ALIGN (asm_out_file, exact_log2 (UNITS_PER_WORD)); ! 1071: ! 1072: /* Output the label itself. */ ! 1073: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", const_labelno); ! 1074: ! 1075: /* Output the value of EXP. */ ! 1076: if (GET_CODE (x) == CONST_DOUBLE) ! 1077: { ! 1078: union {double d; int i[2];} u; ! 1079: ! 1080: u.i[0] = XINT (x, 0); ! 1081: u.i[1] = XINT (x, 1); ! 1082: if (GET_MODE_SIZE (GET_MODE (x)) == GET_MODE_SIZE (DFmode)) ! 1083: ASM_OUTPUT_DOUBLE (asm_out_file, u.d); ! 1084: else ! 1085: ASM_OUTPUT_FLOAT (asm_out_file, u.d); ! 1086: } ! 1087: else ! 1088: ASM_OUTPUT_INT (asm_out_file, x); ! 1089: ! 1090: /* Create a string containing the label name, in LABEL. */ ! 1091: ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno); ! 1092: ! 1093: ++const_labelno; ! 1094: ! 1095: desc->label = found ! 1096: = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label)); ! 1097: } ! 1098: ! 1099: /* We have a symbol name; construct the SYMBOL_REF and the MEM. */ ! 1100: ! 1101: def = gen_rtx (MEM, mode, gen_rtx (SYMBOL_REF, Pmode, desc->label)); ! 1102: ! 1103: def->unchanging = 1; ! 1104: /* Mark the symbol_ref as belonging to this constants pool. */ ! 1105: XEXP (def, 0)->unchanging = 1; ! 1106: ! 1107: return def; ! 1108: } ! 1109: ! 1110: /* Find all the constants whose addresses are referenced inside of EXP, ! 1111: and make sure assembler code with a label has been output for each one. */ ! 1112: ! 1113: void ! 1114: output_addressed_constants (exp) ! 1115: tree exp; ! 1116: { ! 1117: switch (TREE_CODE (exp)) ! 1118: { ! 1119: case ADDR_EXPR: ! 1120: { ! 1121: register tree constant = TREE_OPERAND (exp, 0); ! 1122: ! 1123: while (TREE_CODE (constant) == COMPONENT_REF) ! 1124: { ! 1125: constant = TREE_OPERAND (constant, 0); ! 1126: } ! 1127: ! 1128: if (TREE_LITERAL (constant)) ! 1129: /* No need to do anything here ! 1130: for addresses of variables or functions. */ ! 1131: output_constant_def (constant); ! 1132: } ! 1133: break; ! 1134: ! 1135: case PLUS_EXPR: ! 1136: case MINUS_EXPR: ! 1137: output_addressed_constants (TREE_OPERAND (exp, 0)); ! 1138: output_addressed_constants (TREE_OPERAND (exp, 1)); ! 1139: break; ! 1140: ! 1141: case NOP_EXPR: ! 1142: case CONVERT_EXPR: ! 1143: output_addressed_constants (TREE_OPERAND (exp, 0)); ! 1144: break; ! 1145: ! 1146: case CONSTRUCTOR: ! 1147: { ! 1148: register tree link; ! 1149: for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link)) ! 1150: output_addressed_constants (TREE_VALUE (link)); ! 1151: } ! 1152: break; ! 1153: ! 1154: case ERROR_MARK: ! 1155: break; ! 1156: ! 1157: default: ! 1158: if (! TREE_LITERAL (exp)) ! 1159: abort (); ! 1160: } ! 1161: } ! 1162: ! 1163: /* Output assembler code for constant EXP to FILE, with no label. ! 1164: This includes the pseudo-op such as ".int" or ".byte", and a newline. ! 1165: Assumes output_addressed_constants has been done on EXP already. ! 1166: ! 1167: Generate exactly SIZE bytes of assembler data, padding at the end ! 1168: with zeros if necessary. SIZE must always be specified. ! 1169: ! 1170: SIZE is important for structure constructors, ! 1171: since trailing members may have been omitted from the constructor. ! 1172: It is also important for initialization of arrays from string constants ! 1173: since the full length of the string constant might not be wanted. ! 1174: It is also needed for initialization of unions, where the initializer's ! 1175: type is just one member, and that may not be as long as the union. ! 1176: ! 1177: There a case in which we would fail to output exactly SIZE bytes: ! 1178: for a structure constructor that wants to produce more than SIZE bytes. ! 1179: But such constructors will never be generated for any possible input. */ ! 1180: ! 1181: void ! 1182: output_constant (exp, size) ! 1183: register tree exp; ! 1184: register int size; ! 1185: { ! 1186: register enum tree_code code = TREE_CODE (TREE_TYPE (exp)); ! 1187: rtx x; ! 1188: ! 1189: if (size == 0) ! 1190: return; ! 1191: ! 1192: switch (code) ! 1193: { ! 1194: case INTEGER_TYPE: ! 1195: case ENUMERAL_TYPE: ! 1196: case POINTER_TYPE: ! 1197: x = expand_expr (exp, 0, VOIDmode, EXPAND_SUM); ! 1198: ! 1199: if (size == 1) ! 1200: { ! 1201: ASM_OUTPUT_CHAR (asm_out_file, x); ! 1202: size -= 1; ! 1203: } ! 1204: else if (size == 2) ! 1205: { ! 1206: ASM_OUTPUT_SHORT (asm_out_file, x); ! 1207: size -= 2; ! 1208: } ! 1209: else if (size == 4) ! 1210: { ! 1211: ASM_OUTPUT_INT (asm_out_file, x); ! 1212: size -= 4; ! 1213: } ! 1214: else ! 1215: abort (); ! 1216: ! 1217: break; ! 1218: ! 1219: case REAL_TYPE: ! 1220: if (TREE_CODE (exp) != REAL_CST) ! 1221: error ("initializer for floating value is not a floating constant"); ! 1222: ! 1223: if (size < 4) ! 1224: break; ! 1225: else if (size < 8) ! 1226: { ! 1227: ASM_OUTPUT_FLOAT (asm_out_file, TREE_REAL_CST (exp)); ! 1228: size -= 4; ! 1229: } ! 1230: else ! 1231: { ! 1232: ASM_OUTPUT_DOUBLE (asm_out_file, TREE_REAL_CST (exp)); ! 1233: size -= 8; ! 1234: } ! 1235: break; ! 1236: ! 1237: case COMPLEX_TYPE: ! 1238: output_constant (TREE_REALPART (exp), size / 2); ! 1239: output_constant (TREE_IMAGPART (exp), size / 2); ! 1240: size -= (size / 2) * 2; ! 1241: break; ! 1242: ! 1243: case ARRAY_TYPE: ! 1244: if (TREE_CODE (exp) == CONSTRUCTOR) ! 1245: { ! 1246: output_constructor (exp, size); ! 1247: return; ! 1248: } ! 1249: else if (TREE_CODE (exp) == STRING_CST) ! 1250: { ! 1251: register int i; ! 1252: register unsigned char *p ! 1253: = (unsigned char *) TREE_STRING_POINTER (exp); ! 1254: int excess = 0; ! 1255: ! 1256: if (size > TREE_STRING_LENGTH (exp)) ! 1257: { ! 1258: excess = size - TREE_STRING_LENGTH (exp); ! 1259: size = TREE_STRING_LENGTH (exp); ! 1260: } ! 1261: ! 1262: #ifdef ASM_OUTPUT_ASCII ! 1263: ASM_OUTPUT_ASCII (asm_out_file, p, size); ! 1264: #else ! 1265: fprintf (asm_out_file, "\t.ascii \""); ! 1266: ! 1267: for (i = 0; i < size; i++) ! 1268: { ! 1269: register int c = p[i]; ! 1270: if (c == '\"' || c == '\\') ! 1271: putc ('\\', asm_out_file); ! 1272: if (c >= ' ' && c < 0177) ! 1273: putc (c, asm_out_file); ! 1274: else ! 1275: { ! 1276: fprintf (asm_out_file, "\\%o", c); ! 1277: /* After an octal-escape, if a digit follows, ! 1278: terminate one string constant and start another. ! 1279: The Vax assembler fails to stop reading the escape ! 1280: after three digits, so this is the only way we ! 1281: can get it to parse the data properly. */ ! 1282: if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9') ! 1283: fprintf (asm_out_file, "\"\n\t.ascii \""); ! 1284: } ! 1285: } ! 1286: fprintf (asm_out_file, "\"\n"); ! 1287: #endif /* no ASM_OUTPUT_ASCII */ ! 1288: ! 1289: size = excess; ! 1290: } ! 1291: else ! 1292: abort (); ! 1293: break; ! 1294: ! 1295: case RECORD_TYPE: ! 1296: case UNION_TYPE: ! 1297: if (TREE_CODE (exp) == CONSTRUCTOR) ! 1298: output_constructor (exp, size); ! 1299: else ! 1300: abort (); ! 1301: return; ! 1302: } ! 1303: ! 1304: if (size > 0) ! 1305: ASM_OUTPUT_SKIP (asm_out_file, size); ! 1306: } ! 1307: ! 1308: /* Subroutine of output_constant, used for CONSTRUCTORs ! 1309: (aggregate constants). ! 1310: Generate at least SIZE bytes, padding if necessary. */ ! 1311: ! 1312: void ! 1313: output_constructor (exp, size) ! 1314: tree exp; ! 1315: int size; ! 1316: { ! 1317: register tree link, field = 0; ! 1318: register int byte; ! 1319: int total_bytes = 0; ! 1320: int byte_offset = -1; ! 1321: ! 1322: if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE ! 1323: || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE) ! 1324: field = TYPE_FIELDS (TREE_TYPE (exp)); ! 1325: ! 1326: /* As LINK goes through the elements of the constant, ! 1327: FIELD goes through the structure fields, if the constant is a structure. ! 1328: But the constant could also be an array. Then FIELD is zero. */ ! 1329: for (link = CONSTRUCTOR_ELTS (exp); ! 1330: link; ! 1331: link = TREE_CHAIN (link), ! 1332: field = field ? TREE_CHAIN (field) : 0) ! 1333: { ! 1334: if (field == 0 ! 1335: || (DECL_MODE (field) != BImode)) ! 1336: { ! 1337: register int fieldsize; ! 1338: ! 1339: /* An element that is not a bit-field. ! 1340: Output any buffered-up bit-fields preceding it. */ ! 1341: if (byte_offset >= 0) ! 1342: { ! 1343: ASM_OUTPUT_BYTE (asm_out_file, byte); ! 1344: total_bytes++; ! 1345: byte_offset = -1; ! 1346: } ! 1347: ! 1348: /* Align to this element's alignment, ! 1349: if it isn't aligned properly by its predecessors. */ ! 1350: if (field && (total_bytes * BITS_PER_UNIT) % DECL_ALIGN (field) != 0) ! 1351: { ! 1352: int byte_align = DECL_ALIGN (field) / BITS_PER_UNIT; ! 1353: int to_byte = (((total_bytes + byte_align - 1) / byte_align) ! 1354: * byte_align); ! 1355: ASM_OUTPUT_SKIP (asm_out_file, to_byte - total_bytes); ! 1356: total_bytes = to_byte; ! 1357: } ! 1358: ! 1359: /* Output the element's initial value. */ ! 1360: if (field) ! 1361: { ! 1362: if (! TREE_LITERAL (DECL_SIZE (field))) ! 1363: abort (); ! 1364: fieldsize = TREE_INT_CST_LOW (DECL_SIZE (field)) ! 1365: * DECL_SIZE_UNIT (field); ! 1366: fieldsize = (fieldsize + BITS_PER_UNIT - 1) / BITS_PER_UNIT; ! 1367: } ! 1368: else ! 1369: fieldsize = int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp))); ! 1370: ! 1371: output_constant (TREE_VALUE (link), fieldsize); ! 1372: ! 1373: /* Count its size. */ ! 1374: total_bytes += fieldsize; ! 1375: } ! 1376: else if (TREE_CODE (TREE_VALUE (link)) != INTEGER_CST) ! 1377: error ("invalid initial value for member `%s'", ! 1378: IDENTIFIER_POINTER (DECL_NAME (field))); ! 1379: else ! 1380: { ! 1381: /* Element that is a bit-field. */ ! 1382: ! 1383: int next_offset = DECL_OFFSET (field); ! 1384: int end_offset ! 1385: = (next_offset ! 1386: + (TREE_INT_CST_LOW (DECL_SIZE (field)) ! 1387: * DECL_SIZE_UNIT (field))); ! 1388: ! 1389: /* We must split the element into pieces that fall within ! 1390: separate bytes, and combine each byte with previous or ! 1391: following bit-fields. */ ! 1392: ! 1393: /* next_offset is the offset n fbits from the begining of ! 1394: the structure to the next bit of this element to be processed. ! 1395: end_offset is the offset of the first bit past the end of ! 1396: this element. */ ! 1397: while (next_offset < end_offset) ! 1398: { ! 1399: int this_time; ! 1400: int next_byte = next_offset / BITS_PER_UNIT; ! 1401: int next_bit = next_offset % BITS_PER_UNIT; ! 1402: if (byte_offset < 0) ! 1403: { ! 1404: byte_offset = next_byte; ! 1405: byte = 0; ! 1406: } ! 1407: else ! 1408: while (next_byte != byte_offset) ! 1409: { ! 1410: ASM_OUTPUT_BYTE (asm_out_file, byte); ! 1411: byte_offset++; ! 1412: total_bytes++; ! 1413: byte = 0; ! 1414: } ! 1415: /* Number of bits we can process at once ! 1416: (all part of the same byte). */ ! 1417: this_time = MIN (end_offset - next_offset, ! 1418: BITS_PER_UNIT - next_bit); ! 1419: #ifdef BYTES_BIG_ENDIAN ! 1420: /* On big-endian machine, take the most significant bits ! 1421: first (of the bits that are significant) ! 1422: and put them into bytes from the most significant end. */ ! 1423: byte |= (((TREE_INT_CST_LOW (TREE_VALUE (link)) ! 1424: >> (end_offset - next_offset - this_time)) ! 1425: & ((1 << this_time) - 1)) ! 1426: << (BITS_PER_UNIT - this_time - next_bit)); ! 1427: #else ! 1428: /* On little-endian machines, ! 1429: take first the least significant bits of the value ! 1430: and pack them starting at the least significant ! 1431: bits of the bytes. */ ! 1432: byte |= ((TREE_INT_CST_LOW (TREE_VALUE (link)) ! 1433: >> (next_offset - DECL_OFFSET (field))) ! 1434: & ((1 << this_time) - 1)) << next_bit; ! 1435: #endif ! 1436: next_offset += this_time; ! 1437: } ! 1438: } ! 1439: } ! 1440: if (byte_offset >= 0) ! 1441: { ! 1442: ASM_OUTPUT_BYTE (asm_out_file, byte); ! 1443: byte_offset = -1; ! 1444: total_bytes++; ! 1445: } ! 1446: if (total_bytes < size) ! 1447: ASM_OUTPUT_SKIP (asm_out_file, size - total_bytes); ! 1448: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.