Annotation of researchv10dc/cmd/gcc/varasm.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.