Annotation of GNUtools/cc/config/arm/arm.c, revision 1.1.1.1

1.1       root        1: /* Output routines for GCC for ARM/RISCiX.
                      2:    Copyright (C) 1991, 1993 Free Software Foundation, Inc.
                      3:    Contributed by Pieter `Tiggr' Schoenmakers ([email protected])
                      4:              and Martin Simmons (@harleqn.co.uk).
                      5:    More major hacks by Richard Earnshaw ([email protected])
                      6: 
                      7: This file is part of GNU CC.
                      8: 
                      9: GNU CC is free software; you can redistribute it and/or modify
                     10: it under the terms of the GNU General Public License as published by
                     11: the Free Software Foundation; either version 2, or (at your option)
                     12: any later version.
                     13: 
                     14: GNU CC is distributed in the hope that it will be useful,
                     15: but WITHOUT ANY WARRANTY; without even the implied warranty of
                     16: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     17: GNU General Public License for more details.
                     18: 
                     19: You should have received a copy of the GNU General Public License
                     20: along with GNU CC; see the file COPYING.  If not, write to
                     21: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
                     22:     
                     23: #include <stdio.h>
                     24: #include "assert.h"
                     25: #include "config.h"
                     26: #include "rtl.h"
                     27: #include "regs.h"
                     28: #include "hard-reg-set.h"
                     29: #include "real.h"
                     30: #include "insn-config.h"
                     31: #include "conditions.h"
                     32: #include "insn-flags.h"
                     33: #include "output.h"
                     34: #include "insn-attr.h"
                     35: #include "flags.h"
                     36: #include "reload.h"
                     37: 
                     38: /* The maximum number of insns skipped which will be conditionalised if
                     39:    possible.  */
                     40: #define MAX_INSNS_SKIPPED  5
                     41: 
                     42: /* Some function declarations.  */
                     43: extern FILE *asm_out_file;
                     44: extern char *output_multi_immediate ();
                     45: extern char *arm_output_asm_insn ();
                     46: extern void arm_increase_location ();
                     47: 
                     48: /*  Define the information needed to generate branch insns.  This is
                     49:    stored from the compare operation. */
                     50: 
                     51: rtx arm_compare_op0, arm_compare_op1;
                     52: int arm_compare_fp;
                     53: 
                     54: /* What type of cpu are we compiling for? */
                     55: 
                     56: enum processor_type arm_cpu;
                     57: 
                     58: /* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we
                     59:    must report the mode of the memory reference from PRINT_OPERAND to
                     60:    PRINT_OPERAND_ADDRESS.  */
                     61: int output_memory_reference_mode;
                     62: 
                     63: /* Nonzero if the prologue must setup `fp'.  */
                     64: int current_function_anonymous_args;
                     65: 
                     66: /* Location counter of .text segment.  */
                     67: int arm_text_location = 0;
                     68: 
                     69: /* Set to one if we think that lr is only saved because of subroutine calls,
                     70:    but all of these can be `put after' return insns */
                     71: int lr_save_eliminated;
                     72: 
                     73: /* A hash table is used to store text segment labels and their associated
                     74:    offset from the start of the text segment.  */
                     75: struct label_offset
                     76: {
                     77:   char *name;
                     78:   int offset;
                     79:   struct label_offset *cdr;
                     80: };
                     81: 
                     82: #define LABEL_HASH_SIZE  257
                     83: 
                     84: static struct label_offset *offset_table[LABEL_HASH_SIZE];
                     85: 
                     86: /* Set to 1 when a return insn is output, this means that the epilogue
                     87:    is not needed. */
                     88: 
                     89: static int return_used_this_function;
                     90: 
                     91: /* For an explanation of these variables, see final_prescan_insn below.  */
                     92: int arm_ccfsm_state;
                     93: int arm_current_cc;
                     94: rtx arm_target_insn;
                     95: int arm_target_label;
                     96: 
                     97: /* Return 1 if it is possible to return using a single instruction */
                     98: 
                     99: int
                    100: use_return_insn ()
                    101: {
                    102:   int regno;
                    103: 
                    104:   if (!reload_completed ||current_function_pretend_args_size
                    105:       || current_function_anonymous_args
                    106:       || (get_frame_size () && !(TARGET_APCS || frame_pointer_needed)))
                    107:     return 0;
                    108: 
                    109:   /* Can't be done if any of the FPU regs are pushed, since this also
                    110:      requires an insn */
                    111:   for (regno = 20; regno < 24; regno++)
                    112:     if (regs_ever_live[regno])
                    113:       return 0;
                    114: 
                    115:   return 1;
                    116: }
                    117: 
                    118: /* Return the number of mov instructions needed to get the constant VALUE into
                    119:    a register.  */
                    120: 
                    121: int
                    122: arm_const_nmoves (value)
                    123:      register int value;
                    124: {
                    125:   register int i;
                    126: 
                    127:   if (value == 0)
                    128:     return (1);
                    129:   for (i = 0; value; i++, value &= ~0xff)
                    130:     while ((value & 3) == 0)
                    131:       value = (value >> 2) | ((value & 3) << 30);
                    132:   return (i);
                    133: } /* arm_const_nmoves */
                    134: 
                    135: 
                    136: /* Return TRUE if int I is a valid immediate ARM constant.  */
                    137: 
                    138: int
                    139: const_ok_for_arm (i)
                    140:      HOST_WIDE_INT i;
                    141: {
                    142:   unsigned HOST_WIDE_INT mask = ~0xFF;
                    143: 
                    144:   do
                    145:     {
                    146:       if ((i & mask & (unsigned HOST_WIDE_INT) 0xffffffff) == 0)
                    147:         return(TRUE);
                    148:       mask =
                    149:          (mask << 2) | ((mask & (unsigned HOST_WIDE_INT) 0xffffffff)
                    150:                         >> (32 - 2)) | ~((unsigned HOST_WIDE_INT) 0xffffffff);
                    151:     } while (mask != ~0xFF);
                    152: 
                    153:   return (FALSE);
                    154: } /* const_ok_for_arm */
                    155: 
                    156: /* This code has been fixed for cross compilation. */
                    157: 
                    158: static int fpa_consts_inited = 0;
                    159: 
                    160: char *strings_fpa[8] = {
                    161:   "0.0",
                    162:   "1.0",
                    163:   "2.0",
                    164:   "3.0",
                    165:   "4.0",
                    166:   "5.0",
                    167:   "0.5",
                    168:   "10.0"
                    169:   };
                    170: 
                    171: static REAL_VALUE_TYPE values_fpa[8];
                    172: 
                    173: static void
                    174: init_fpa_table ()
                    175: {
                    176:   int i;
                    177:   REAL_VALUE_TYPE r;
                    178: 
                    179:   for (i = 0; i < 8; i++)
                    180:     {
                    181:       r = REAL_VALUE_ATOF (strings_fpa[i], DFmode);
                    182:       values_fpa[i] = r;
                    183:     }
                    184:   fpa_consts_inited = 1;
                    185: }
                    186: 
                    187: /* Return TRUE if rtx X is a valid immediate FPU constant. */
                    188: 
                    189: int
                    190: const_double_rtx_ok_for_fpu (x)
                    191:      rtx x;
                    192: {
                    193:   REAL_VALUE_TYPE r;
                    194:   int i;
                    195:   
                    196:   if (!fpa_consts_inited)
                    197:     init_fpa_table ();
                    198:   
                    199:   REAL_VALUE_FROM_CONST_DOUBLE (r, x);
                    200:   if (REAL_VALUE_MINUS_ZERO (r))
                    201:     return 0;
                    202:   for (i = 0; i < 8; i++)
                    203:     if (REAL_VALUES_EQUAL (r, values_fpa[i]))
                    204:       return 1;
                    205:   return 0;
                    206: } /* const_double_rtx_ok_for_fpu */
                    207: 
                    208: /* Return TRUE if rtx X is a valid immediate FPU constant. */
                    209: 
                    210: int
                    211: neg_const_double_rtx_ok_for_fpu (x)
                    212:      rtx x;
                    213: {
                    214:   REAL_VALUE_TYPE r;
                    215:   int i;
                    216:   
                    217:   if (!fpa_consts_inited)
                    218:     init_fpa_table ();
                    219:   
                    220:   REAL_VALUE_FROM_CONST_DOUBLE (r, x);
                    221:   r = REAL_VALUE_NEGATE (r);
                    222:   if (REAL_VALUE_MINUS_ZERO (r))
                    223:     return 0;
                    224:   for (i = 0; i < 8; i++)
                    225:     if (REAL_VALUES_EQUAL (r, values_fpa[i]))
                    226:       return 1;
                    227:   return 0;
                    228: } /* neg_const_double_rtx_ok_for_fpu */
                    229: 
                    230: /* Predicates for `match_operand' and `match_operator'.  */
                    231: 
                    232: /* s_register_operand is the same as register_operand, but it doesn't accept
                    233:    (SUBREG (MEM)...). */
                    234: 
                    235: int
                    236: s_register_operand (op, mode)
                    237:      register rtx op;
                    238:      enum machine_mode mode;
                    239: {
                    240:   if (GET_MODE (op) != mode && mode != VOIDmode)
                    241:     return 0;
                    242: 
                    243:   if (GET_CODE (op) == SUBREG)
                    244:     {
                    245:       op = SUBREG_REG (op);
                    246:     }
                    247: 
                    248:   /* We don't consider registers whose class is NO_REGS
                    249:      to be a register operand.  */
                    250:   return (GET_CODE (op) == REG
                    251:          && (REGNO (op) >= FIRST_PSEUDO_REGISTER
                    252:              || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
                    253: }
                    254: 
                    255: /* Return 1 if OP is an item in memory, given that we are in reload.  */
                    256: 
                    257: int
                    258: reload_memory_operand (op, mode)
                    259:      rtx op;
                    260:      enum machine_mode mode;
                    261: {
                    262:   int regno = true_regnum (op);
                    263: 
                    264:   return (! CONSTANT_P (op)
                    265:          && (regno == -1
                    266:              || (GET_CODE (op) == REG
                    267:                  && REGNO (op) >= FIRST_PSEUDO_REGISTER)));
                    268: }
                    269: 
                    270: /* Return TRUE for valid operands for the rhs of an ARM instruction.  */
                    271: 
                    272: int
                    273: arm_rhs_operand (op, mode)
                    274:      rtx op;
                    275:      enum machine_mode mode;
                    276: {
                    277:   return (s_register_operand (op, mode)
                    278:          || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))));
                    279: } /* arm_rhs_operand */
                    280: 
                    281: /* Return TRUE for valid operands for the rhs of an ARM instruction, or a load.
                    282:  */
                    283: 
                    284: int
                    285: arm_rhsm_operand (op, mode)
                    286:      rtx op;
                    287:      enum machine_mode mode;
                    288: {
                    289:   return (s_register_operand (op, mode)
                    290:          || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op)))
                    291:          || memory_operand (op, mode));
                    292: } /* arm_rhs_operand */
                    293: 
                    294: /* Return TRUE for valid operands for the rhs of an ARM instruction, or if a
                    295:    constant that is valid when negated.  */
                    296: 
                    297: int
                    298: arm_add_operand (op, mode)
                    299:      rtx op;
                    300:      enum machine_mode mode;
                    301: {
                    302:   return (s_register_operand (op, mode)
                    303:          || (GET_CODE (op) == CONST_INT
                    304:              && (const_ok_for_arm (INTVAL (op))
                    305:                  || const_ok_for_arm (-INTVAL (op)))));
                    306: } /* arm_rhs_operand */
                    307: 
                    308: int
                    309: arm_not_operand (op, mode)
                    310:      rtx op;
                    311:      enum machine_mode mode;
                    312: {
                    313:   return (s_register_operand (op, mode)
                    314:          || (GET_CODE (op) == CONST_INT
                    315:              && (const_ok_for_arm (INTVAL (op))
                    316:                  || const_ok_for_arm (~INTVAL (op)))));
                    317: } /* arm_rhs_operand */
                    318: 
                    319: /* Return TRUE for valid operands for the rhs of an FPU instruction.  */
                    320: 
                    321: int
                    322: fpu_rhs_operand (op, mode)
                    323:      rtx op;
                    324:      enum machine_mode mode;
                    325: {
                    326:   if (s_register_operand (op, mode))
                    327:     return(TRUE);
                    328:   else if (GET_CODE (op) == CONST_DOUBLE)
                    329:     return (const_double_rtx_ok_for_fpu (op));
                    330:   else return (FALSE);
                    331: } /* fpu_rhs_operand */
                    332: 
                    333: int
                    334: fpu_add_operand (op, mode)
                    335:      rtx op;
                    336:      enum machine_mode mode;
                    337: {
                    338:   if (s_register_operand (op, mode))
                    339:     return(TRUE);
                    340:   else if (GET_CODE (op) == CONST_DOUBLE)
                    341:     return const_double_rtx_ok_for_fpu (op) 
                    342:        || neg_const_double_rtx_ok_for_fpu (op);
                    343:   return (FALSE);
                    344: }
                    345: 
                    346: /* Return nonzero if OP is a constant power of two.  */
                    347: 
                    348: int
                    349: power_of_two_operand (op, mode)
                    350:      rtx op;
                    351:      enum machine_mode mode;
                    352: {
                    353:   if (GET_CODE (op) == CONST_INT)
                    354:     {
                    355:       int value = INTVAL(op);
                    356:       return (value != 0  &&  (value & (value-1)) == 0);
                    357:     }
                    358:   return (FALSE);
                    359: } /* power_of_two_operand */
                    360: 
                    361: /* Return TRUE for a valid operand of a DImode operation.
                    362:    Either: REG, CONST_DOUBLE or MEM(DImode_address).
                    363:    Note that this disallows MEM(REG+REG), but allows
                    364:    MEM(PRE/POST_INC/DEC(REG)).  */
                    365: 
                    366: int
                    367: di_operand (op, mode)
                    368:      rtx op;
                    369:      enum machine_mode mode;
                    370: {
                    371:   if (s_register_operand (op, mode))
                    372:     return (TRUE);
                    373: 
                    374:   switch (GET_CODE (op))
                    375:     {
                    376:     case CONST_DOUBLE:
                    377:     case CONST_INT:
                    378:       return (TRUE);
                    379:     case MEM:
                    380:       return (memory_address_p (DImode, XEXP (op, 0)));
                    381:     default:
                    382:       return (FALSE);
                    383:     }
                    384: } /* di_operand */
                    385: 
                    386: /* Return TRUE for valid index operands. */
                    387: 
                    388: int
                    389: index_operand (op, mode)
                    390:      rtx op;
                    391:      enum machine_mode mode;
                    392: {
                    393:   return (s_register_operand(op, mode)
                    394:          || (immediate_operand (op, mode)
                    395:              && INTVAL (op) < 4096 && INTVAL (op) > -4096));
                    396: } /* index_operand */
                    397: 
                    398: /* Return TRUE for valid shifts by a constant. This also accepts any
                    399:    power of two on the (somewhat overly relaxed) assumption that the
                    400:    shift operator in this case was a mult. */
                    401: 
                    402: int
                    403: const_shift_operand (op, mode)
                    404:      rtx op;
                    405:      enum machine_mode mode;
                    406: {
                    407:   return (power_of_two_operand (op, mode)
                    408:          || (immediate_operand (op, mode)
                    409:              && (INTVAL (op) < 32 && INTVAL (op) > 0)));
                    410: } /* const_shift_operand */
                    411: 
                    412: /* Return TRUE for arithmetic operators which can be combined with a multiply
                    413:    (shift).  */
                    414: 
                    415: int
                    416: shiftable_operator (x, mode)
                    417:      rtx x;
                    418:      enum machine_mode mode;
                    419: {
                    420:   if (GET_MODE (x) != mode)
                    421:     return FALSE;
                    422:   else
                    423:     {
                    424:       enum rtx_code code = GET_CODE (x);
                    425: 
                    426:       return (code == PLUS || code == MINUS
                    427:              || code == IOR || code == XOR || code == AND);
                    428:     }
                    429: } /* shiftable_operator */
                    430: 
                    431: /* Return TRUE for shift operators. */
                    432: 
                    433: int
                    434: shift_operator (x, mode)
                    435:      rtx x;
                    436:      enum machine_mode mode;
                    437: {
                    438:   if (GET_MODE (x) != mode)
                    439:     return FALSE;
                    440:   else
                    441:     {
                    442:       enum rtx_code code = GET_CODE (x);
                    443: 
                    444:       if (code == MULT)
                    445:        return power_of_two_operand (XEXP (x, 1));
                    446:       return (code == ASHIFT || code == LSHIFT
                    447:              || code == ASHIFTRT || code == LSHIFTRT);
                    448:     }
                    449: } /* shift_operator */
                    450: 
                    451: int equality_operator (x, mode)
                    452: rtx x;
                    453: enum machine_mode mode;
                    454: {
                    455:   return (GET_CODE (x) == EQ || GET_CODE (x) == NE);
                    456: }
                    457: 
                    458: /* Return TRUE for SMIN SMAX UMIN UMAX operators. */
                    459: 
                    460: int
                    461: minmax_operator (x, mode)
                    462:      rtx x;
                    463:      enum machine_mode mode;
                    464: {
                    465:   enum rtx_code code = GET_CODE (x);
                    466: 
                    467:   if (GET_MODE (x) != mode)
                    468:     return FALSE;
                    469:   return code == SMIN || code == SMAX || code == UMIN || code == UMAX;
                    470: } /* minmax_operator */
                    471: 
                    472: /* return TRUE if x is EQ or NE */
                    473: 
                    474: /* Return TRUE if this is the condition code register, if we aren't given
                    475:    a mode, accept any class CCmode register */
                    476: 
                    477: int
                    478: cc_register (x, mode)
                    479: rtx x;
                    480: enum machine_mode mode;
                    481: {
                    482:   if (mode == VOIDmode)
                    483:     {
                    484:       mode = GET_MODE (x);
                    485:       if (GET_MODE_CLASS (mode) != MODE_CC)
                    486:        return FALSE;
                    487:     }
                    488:   if (mode == GET_MODE (x) && GET_CODE (x) == REG && REGNO (x) == 24)
                    489:     return TRUE;
                    490:   return FALSE;
                    491: }
                    492:        
                    493: enum rtx_code
                    494: minmax_code (x)
                    495: rtx x;
                    496: {
                    497:   enum rtx_code code = GET_CODE (x);
                    498: 
                    499:   if (code == SMAX)
                    500:     return GE;
                    501:   if (code == SMIN)
                    502:     return LE;
                    503:   if (code == UMIN)
                    504:     return LEU;
                    505:   if (code == UMAX)
                    506:     return GEU;
                    507:   abort ();
                    508: }
                    509: 
                    510: /* Return 1 if memory locations are adjacent */
                    511: 
                    512: adjacent_mem_locations (a, b)
                    513:      rtx a, b;
                    514: {
                    515:   int val0 = 0, val1 = 0;
                    516:   int reg0, reg1;
                    517:   
                    518:   if ((GET_CODE (XEXP (a, 0)) == REG
                    519:        || (GET_CODE (XEXP (a, 0)) == PLUS
                    520:           && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT))
                    521:       && (GET_CODE (XEXP (b, 0)) == REG
                    522:          || (GET_CODE (XEXP (b, 0)) == PLUS
                    523:              && GET_CODE (XEXP (XEXP (b, 0), 1)) == CONST_INT)))
                    524:     {
                    525:       if (GET_CODE (XEXP (a, 0)) == PLUS)
                    526:         {
                    527:          reg0 = REGNO (XEXP (XEXP (a, 0), 0));
                    528:          val0 = INTVAL (XEXP (XEXP (a, 0), 1));
                    529:         }
                    530:       else
                    531:        reg0 = REGNO (XEXP (a, 0));
                    532:       if (GET_CODE (XEXP (b, 0)) == PLUS)
                    533:         {
                    534:          reg1 = REGNO (XEXP (XEXP (b, 0), 0));
                    535:          val1 = INTVAL (XEXP (XEXP (b, 0), 1));
                    536:         }
                    537:       else
                    538:        reg1 = REGNO (XEXP (b, 0));
                    539:       return (reg0 == reg1) && ((val1 - val0) == 4 || (val0 - val1) == 4);
                    540:     }
                    541:   return 0;
                    542: }
                    543: 
                    544: /* Return 1 if OP is a load multiple operation.  It is known to be
                    545:    parallel and the first section will be tested. */
                    546: 
                    547: load_multiple_operation (op, mode)
                    548:      rtx op;
                    549:      enum machine_mode mode;
                    550: {
                    551:   int count = XVECLEN (op, 0);
                    552:   int dest_regno;
                    553:   rtx src_addr;
                    554:   int i = 1, base = 0;
                    555:   rtx elt;
                    556: 
                    557:   if (count <= 1
                    558:       || GET_CODE (XVECEXP (op, 0, 0)) != SET)
                    559:     return 0;
                    560: 
                    561:   /* Check to see if this might be a write-back */
                    562:   if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
                    563:     {
                    564:       i++;
                    565:       base = 1;
                    566: 
                    567:       /* Now check it more carefully */
                    568:       if (GET_CODE (SET_DEST (elt)) != REG
                    569:           || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
                    570:           || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt))
                    571:           || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
                    572:           || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 2) * 4
                    573:           || GET_CODE (XVECEXP (op, 0, count - 1)) != CLOBBER
                    574:           || GET_CODE (XEXP (XVECEXP (op, 0, count - 1), 0)) != REG
                    575:           || REGNO (XEXP (XVECEXP (op, 0, count - 1), 0))
                    576:               != REGNO (SET_DEST (elt)))
                    577:         return 0;
                    578:       count--;
                    579:     }
                    580: 
                    581:   /* Perform a quick check so we don't blow up below.  */
                    582:   if (count <= i
                    583:       || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
                    584:       || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != REG
                    585:       || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != MEM)
                    586:     return 0;
                    587: 
                    588:   dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1)));
                    589:   src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0);
                    590: 
                    591:   for (; i < count; i++)
                    592:     {
                    593:       rtx elt = XVECEXP (op, 0, i);
                    594: 
                    595:       if (GET_CODE (elt) != SET
                    596:           || GET_CODE (SET_DEST (elt)) != REG
                    597:           || GET_MODE (SET_DEST (elt)) != SImode
                    598:           || REGNO (SET_DEST (elt)) != dest_regno + i - base
                    599:           || GET_CODE (SET_SRC (elt)) != MEM
                    600:           || GET_MODE (SET_SRC (elt)) != SImode
                    601:           || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
                    602:           || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
                    603:           || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
                    604:           || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != (i - base) * 4)
                    605:         return 0;
                    606:     }
                    607: 
                    608:   return 1;
                    609: }
                    610: 
                    611: /* Return 1 if OP is a store multiple operation.  It is known to be
                    612:    parallel and the first section will be tested. */
                    613: 
                    614: store_multiple_operation (op, mode)
                    615:      rtx op;
                    616:      enum machine_mode mode;
                    617: {
                    618:   int count = XVECLEN (op, 0);
                    619:   int src_regno;
                    620:   rtx dest_addr;
                    621:   int i = 1, base = 0;
                    622:   rtx elt;
                    623: 
                    624:   if (count <= 1
                    625:       || GET_CODE (XVECEXP (op, 0, 0)) != SET)
                    626:     return 0;
                    627: 
                    628:   /* Check to see if this might be a write-back */
                    629:   if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
                    630:     {
                    631:       i++;
                    632:       base = 1;
                    633: 
                    634:       /* Now check it more carefully */
                    635:       if (GET_CODE (SET_DEST (elt)) != REG
                    636:           || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
                    637:           || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt))
                    638:           || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
                    639:           || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 2) * 4
                    640:           || GET_CODE (XVECEXP (op, 0, count - 1)) != CLOBBER
                    641:           || GET_CODE (XEXP (XVECEXP (op, 0, count - 1), 0)) != REG
                    642:           || REGNO (XEXP (XVECEXP (op, 0, count - 1), 0))
                    643:               != REGNO (SET_DEST (elt)))
                    644:         return 0;
                    645:       count--;
                    646:     }
                    647: 
                    648:   /* Perform a quick check so we don't blow up below.  */
                    649:   if (count <= i
                    650:       || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
                    651:       || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != MEM
                    652:       || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != REG)
                    653:     return 0;
                    654: 
                    655:   src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1)));
                    656:   dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0);
                    657: 
                    658:   for (; i < count; i++)
                    659:     {
                    660:       elt = XVECEXP (op, 0, i);
                    661: 
                    662:       if (GET_CODE (elt) != SET
                    663:           || GET_CODE (SET_SRC (elt)) != REG
                    664:           || GET_MODE (SET_SRC (elt)) != SImode
                    665:           || REGNO (SET_SRC (elt)) != src_regno + i - base
                    666:           || GET_CODE (SET_DEST (elt)) != MEM
                    667:           || GET_MODE (SET_DEST (elt)) != SImode
                    668:           || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
                    669:           || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
                    670:           || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
                    671:           || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != (i - base) * 4)
                    672:         return 0;
                    673:     }
                    674: 
                    675:   return 1;
                    676: }
                    677: 
                    678: /* Routines for use in generating RTL */
                    679: 
                    680: rtx arm_gen_load_multiple (base_regno, count, from, up, write_back)
                    681:      int base_regno;
                    682:      int count;
                    683:      rtx from;
                    684:      int up;
                    685:      int write_back;
                    686: {
                    687:   int i = 0, j;
                    688:   rtx result;
                    689:   int sign = up ? 1 : -1;
                    690: 
                    691:   result = gen_rtx (PARALLEL, VOIDmode,
                    692:                     rtvec_alloc (count + (write_back ? 2 : 0)));
                    693:   if (write_back)
                    694:   {
                    695:       XVECEXP (result, 0, 0)
                    696:           = gen_rtx (SET, GET_MODE (from), from,
                    697:                      plus_constant (from, count * 4 * sign));
                    698:       i = 1;
                    699:       count++;
                    700:   }
                    701:   for (j = 0; i < count; i++, j++)
                    702:   {
                    703:       XVECEXP (result, 0, i)
                    704:           = gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, base_regno + j),
                    705:                      gen_rtx (MEM, SImode,
                    706:                               plus_constant (from, j * 4 * sign)));
                    707:   }
                    708:   if (write_back)
                    709:     XVECEXP (result, 0, i) = gen_rtx (CLOBBER, SImode, from);
                    710: 
                    711:   return result;
                    712: }
                    713: 
                    714: rtx arm_gen_store_multiple (base_regno, count, to, up, write_back)
                    715:      int base_regno;
                    716:      int count;
                    717:      rtx to;
                    718:      int up;
                    719:      int write_back;
                    720: {
                    721:   int i = 0, j;
                    722:   rtx result;
                    723:   int sign = up ? 1 : -1;
                    724: 
                    725:   result = gen_rtx (PARALLEL, VOIDmode,
                    726:                     rtvec_alloc (count + (write_back ? 2 : 0)));
                    727:   if (write_back)
                    728:   {
                    729:       XVECEXP (result, 0, 0)
                    730:           = gen_rtx (SET, GET_MODE (to), to,
                    731:                      plus_constant (to, count * 4 * sign));
                    732:       i = 1;
                    733:       count++;
                    734:   }
                    735:   for (j = 0; i < count; i++, j++)
                    736:   {
                    737:       XVECEXP (result, 0, i)
                    738:           = gen_rtx (SET, VOIDmode,
                    739:                      gen_rtx (MEM, SImode, plus_constant (to, j * 4 * sign)),
                    740:                      gen_rtx (REG, SImode, base_regno + j));
                    741:   }
                    742:   if (write_back)
                    743:     XVECEXP (result, 0, i) = gen_rtx (CLOBBER, SImode, to);
                    744: 
                    745:   return result;
                    746: }
                    747: 
                    748: /* X and Y are two things to compare using CODE.  Emit the compare insn and
                    749:    return the rtx for register 0 in the proper mode.  FP means this is a
                    750:    floating point compare: I don't think that it is needed on the arm.  */
                    751: 
                    752: rtx
                    753: gen_compare_reg (code, x, y, fp)
                    754:      enum rtx_code code;
                    755:      rtx x, y;
                    756: {
                    757:   enum machine_mode mode = SELECT_CC_MODE (code, x, y);
                    758:   rtx cc_reg = gen_rtx (REG, mode, 24);
                    759: 
                    760:   emit_insn (gen_rtx (SET, VOIDmode, cc_reg,
                    761:                       gen_rtx (COMPARE, mode, x, y)));
                    762: 
                    763:   return cc_reg;
                    764: }
                    765: 
                    766: arm_reload_out_hi (operands)
                    767: rtx operands[];
                    768: {
                    769:   rtx base = find_replacement (&XEXP (operands[0], 0));
                    770: 
                    771:   emit_insn (gen_rtx (SET, VOIDmode,
                    772:                       gen_rtx (MEM, QImode, base),
                    773:                       gen_rtx (SUBREG, QImode, operands[1], 0)));
                    774:   emit_insn (gen_rtx (SET, VOIDmode, operands[2],
                    775:                       gen_rtx (LSHIFTRT, SImode, 
                    776:                                gen_rtx (SUBREG, SImode, operands[1], 0),
                    777:                                GEN_INT (8))));
                    778:   emit_insn (gen_rtx (SET, VOIDmode,
                    779:                       gen_rtx (MEM, QImode,
                    780:                                plus_constant (base, 1)),
                    781:                       gen_rtx (SUBREG, QImode, operands[2], 0)));
                    782: }
                    783: 
                    784: /* Check to see if a branch is forwards or backwards.  Return TRUE if it
                    785:    is backwards.  */
                    786: 
                    787: int
                    788: arm_backwards_branch (from, to)
                    789: int from, to;
                    790: {
                    791:   return (insn_addresses[to] <= insn_addresses[from]);
                    792: }
                    793: 
                    794: /* Check to see if a branch is within the distance that can be done using
                    795:    an arithmetic expression. */
                    796: int
                    797: short_branch (from, to)
                    798: int from, to;
                    799: {
                    800:   int delta = insn_addresses[from] + 2 - insn_addresses[to];
                    801: 
                    802:   return abs (delta) < 245;    /* A small margin for safety */
                    803: }
                    804: 
                    805: /* Check to see that the insn isn't the target of the conditionalizing
                    806:    code */
                    807: int
                    808: arm_insn_not_targeted (insn)
                    809: rtx insn;
                    810: {
                    811:   return insn != arm_target_insn;
                    812: }
                    813: 
                    814: 
                    815: /* Routines to output assembly language.  */
                    816: 
                    817: /* fp_immediate_constant 
                    818:    if the rtx is the correct value then return the string of the number.
                    819:    In this way we can ensure that valid double constants are generated even
                    820:    when cross compiling. */
                    821: char *
                    822: fp_immediate_constant (x)
                    823: rtx (x);
                    824: {
                    825:   REAL_VALUE_TYPE r;
                    826:   int i;
                    827:   
                    828:   if (!fpa_consts_inited)
                    829:     init_fpa_table ();
                    830:   
                    831:   REAL_VALUE_FROM_CONST_DOUBLE (r, x);
                    832:   for (i = 0; i < 8; i++)
                    833:     if (REAL_VALUES_EQUAL (r, values_fpa[i]))
                    834:       return strings_fpa[i];
                    835:   abort ();
                    836: }
                    837: 
                    838: 
                    839: /* Output the operands of a LDM/STM instruction to STREAM.
                    840:    MASK is the ARM register set mask of which only bits 0-15 are important.
                    841:    INSTR is the possibly suffixed base register.  HAT unequals zero if a hat
                    842:    must follow the register list.  */
                    843: 
                    844: void
                    845: print_multi_reg (stream, instr, mask, hat)
                    846:      FILE *stream;
                    847:      char *instr;
                    848:      int mask, hat;
                    849: {
                    850:   int i;
                    851:   int not_first = FALSE;
                    852: 
                    853:   fprintf (stream, "\t%s, {", instr);
                    854:   for (i = 0; i < 16; i++)
                    855:     if (mask & (1 << i))
                    856:       {
                    857:        if (not_first)
                    858:          fprintf (stream, ", ");
                    859:        fprintf (stream, "%s", reg_names[i]);
                    860:        not_first = TRUE;
                    861:       }
                    862:   fprintf (stream, "}%s\n", hat ? "^" : "");
                    863: } /* print_multi_reg */
                    864: 
                    865: /* Output a 'call' insn. */
                    866: 
                    867: char *
                    868: output_call (operands)
                    869:        rtx operands[];
                    870: {
                    871:   /* Handle calls to lr using ip (which may be clobbered in subr anyway). */
                    872: 
                    873:   if (REGNO (operands[0]) == 14)
                    874:     {
                    875:       operands[0] = gen_rtx (REG, SImode, 12);
                    876:       arm_output_asm_insn ("mov\t%0, lr", operands);
                    877:     }
                    878:   arm_output_asm_insn ("mov\tlr, pc", operands);
                    879:   arm_output_asm_insn ("mov\tpc, %0", operands);
                    880:   return ("");
                    881: } /* output_call */
                    882: 
                    883: static int
                    884: eliminate_lr2ip (x)
                    885: rtx *x;
                    886: {
                    887:   int something_changed = 0;
                    888:   rtx x0 = *x;
                    889:   int code = GET_CODE (x0);
                    890:   register int i, j;
                    891:   register char *fmt;
                    892:   
                    893:   switch (code)
                    894:     {
                    895:     case REG:
                    896:       if (REGNO (x0) == 14)
                    897:         {
                    898:          *x = gen_rtx (REG, SImode, 12);
                    899:          return 1;
                    900:         }
                    901:       return 0;
                    902:     default:
                    903:       /* Scan through the sub-elements and change any references there */
                    904:       fmt = GET_RTX_FORMAT (code);
                    905:       for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
                    906:        if (fmt[i] == 'e')
                    907:          something_changed |= eliminate_lr2ip (&XEXP (x0, i));
                    908:        else if (fmt[i] == 'E')
                    909:          for (j = 0; j < XVECLEN (x0, i); j++)
                    910:            something_changed |= eliminate_lr2ip (&XVECEXP (x0, i, j));
                    911:       return something_changed;
                    912:     }
                    913: }
                    914:   
                    915: /* Output a 'call' insn that is a reference in memory. */
                    916: 
                    917: char *
                    918: output_call_mem (operands)
                    919:        rtx operands[];
                    920: {
                    921:   operands[0] = copy_rtx (operands[0]); /* Be ultra careful */
                    922:   /* Handle calls using lr by using ip (which may be clobbered in subr anyway).
                    923:    */
                    924:   if (eliminate_lr2ip (&operands[0]))
                    925:     arm_output_asm_insn ("mov\tip, lr", operands);
                    926:   arm_output_asm_insn ("mov\tlr, pc", operands);
                    927:   arm_output_asm_insn ("ldr\tpc, %0", operands);
                    928:   return ("");
                    929: } /* output_call */
                    930: 
                    931: 
                    932: /* Output a move from arm registers to an fpu registers.
                    933:    OPERANDS[0] is an fpu register.
                    934:    OPERANDS[1] is the first registers of an arm register pair.  */
                    935: 
                    936: char *
                    937: output_mov_long_double_fpu_from_arm (operands)
                    938:      rtx operands[];
                    939: {
                    940:   int arm_reg0 = REGNO (operands[1]);
                    941:   rtx ops[3];
                    942: 
                    943:   if (arm_reg0 == 12)
                    944:     abort();
                    945:   ops[0] = gen_rtx (REG, SImode, arm_reg0);
                    946:   ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
                    947:   ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0);
                    948:   
                    949:   arm_output_asm_insn ("stmfd\tsp!, {%0, %1, %2}", ops);
                    950:   arm_output_asm_insn ("ldfe\t%0, [sp], #12", operands);
                    951:   return ("");
                    952: } /* output_mov_long_double_fpu_from_arm */
                    953: 
                    954: /* Output a move from an fpu register to arm registers.
                    955:    OPERANDS[0] is the first registers of an arm register pair.
                    956:    OPERANDS[1] is an fpu register.  */
                    957: 
                    958: char *
                    959: output_mov_long_double_arm_from_fpu (operands)
                    960:      rtx operands[];
                    961: {
                    962:   int arm_reg0 = REGNO (operands[0]);
                    963:   rtx ops[3];
                    964: 
                    965:   if (arm_reg0 == 12)
                    966:     abort();
                    967:   ops[0] = gen_rtx (REG, SImode, arm_reg0);
                    968:   ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
                    969:   ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0);
                    970: 
                    971:   arm_output_asm_insn ("stfe\t%1, [sp, #-12]!", operands);
                    972:   arm_output_asm_insn ("ldmfd\tsp!, {%0, %1, %2}", ops);
                    973:   return("");
                    974: } /* output_mov_long_double_arm_from_fpu */
                    975: 
                    976: /* Output a move from arm registers to arm registers of a long double
                    977:    OPERANDS[0] is the destination.
                    978:    OPERANDS[1] is the source.  */
                    979: char *
                    980: output_mov_long_double_arm_from_arm (operands)
                    981: rtx operands[];
                    982: {
                    983:   /* We have to be careful here because the two might overlap */
                    984:   int dest_start = REGNO (operands[0]);
                    985:   int src_start = REGNO (operands[1]);
                    986:   rtx ops[2];
                    987:   int i;
                    988: 
                    989:   if (dest_start < src_start)
                    990:     {
                    991:       for (i = 0; i < 3; i++)
                    992:        {
                    993:          ops[0] = gen_rtx (REG, SImode, dest_start + i);
                    994:          ops[1] = gen_rtx (REG, SImode, src_start + i);
                    995:          arm_output_asm_insn ("mov\t%0, %1", ops);
                    996:        }
                    997:     }
                    998:   else
                    999:     {
                   1000:       for (i = 2; i >= 0; i--)
                   1001:        {
                   1002:          ops[0] = gen_rtx (REG, SImode, dest_start + i);
                   1003:          ops[1] = gen_rtx (REG, SImode, src_start + i);
                   1004:          arm_output_asm_insn ("mov\t%0, %1", ops);
                   1005:        }
                   1006:     }
                   1007:   return "";
                   1008: }
                   1009: 
                   1010: 
                   1011: /* Output a move from arm registers to an fpu registers.
                   1012:    OPERANDS[0] is an fpu register.
                   1013:    OPERANDS[1] is the first registers of an arm register pair.  */
                   1014: 
                   1015: char *
                   1016: output_mov_double_fpu_from_arm (operands)
                   1017:      rtx operands[];
                   1018: {
                   1019:   int arm_reg0 = REGNO (operands[1]);
                   1020:   rtx ops[2];
                   1021: 
                   1022:   if (arm_reg0 == 12)
                   1023:     abort();
                   1024:   ops[0] = gen_rtx (REG, SImode, arm_reg0);
                   1025:   ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
                   1026:   arm_output_asm_insn ("stmfd\tsp!, {%0, %1}", ops);
                   1027:   arm_output_asm_insn ("ldfd\t%0, [sp], #8", operands);
                   1028:   return ("");
                   1029: } /* output_mov_double_fpu_from_arm */
                   1030: 
                   1031: /* Output a move from an fpu register to arm registers.
                   1032:    OPERANDS[0] is the first registers of an arm register pair.
                   1033:    OPERANDS[1] is an fpu register.  */
                   1034: 
                   1035: char *
                   1036: output_mov_double_arm_from_fpu (operands)
                   1037:      rtx operands[];
                   1038: {
                   1039:   int arm_reg0 = REGNO (operands[0]);
                   1040:   rtx ops[2];
                   1041: 
                   1042:   if (arm_reg0 == 12)
                   1043:     abort();
                   1044:   ops[0] = gen_rtx (REG, SImode, arm_reg0);
                   1045:   ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
                   1046:   arm_output_asm_insn ("stfd\t%1, [sp, #-8]!", operands);
                   1047:   arm_output_asm_insn ("ldmfd\tsp!, {%0, %1}", ops);
                   1048:   return("");
                   1049: } /* output_mov_double_arm_from_fpu */
                   1050: 
                   1051: /* Output a move between double words.
                   1052:    It must be REG<-REG, REG<-CONST_DOUBLE, REG<-CONST_INT, REG<-MEM
                   1053:    or MEM<-REG and all MEMs must be offsettable addresses.  */
                   1054: 
                   1055: char *
                   1056: output_move_double (operands)
                   1057:      rtx operands[];
                   1058: {
                   1059:   enum rtx_code code0 = GET_CODE (operands[0]);
                   1060:   enum rtx_code code1 = GET_CODE (operands[1]);
                   1061:   rtx otherops[2];
                   1062: 
                   1063:   if (code0 == REG)
                   1064:     {
                   1065:       int reg0 = REGNO (operands[0]);
                   1066: 
                   1067:       otherops[0] = gen_rtx (REG, SImode, 1 + reg0);
                   1068:       if (code1 == REG)
                   1069:        {
                   1070:          int reg1 = REGNO (operands[1]);
                   1071:          if (reg1 == 12)
                   1072:            abort();
                   1073:          otherops[1] = gen_rtx (REG, SImode, 1 + reg1);
                   1074: 
                   1075:          /* Ensure the second source is not overwritten */
                   1076:          if (reg0 == 1 + reg1)
                   1077:            {
                   1078:              arm_output_asm_insn("mov\t%0, %1", otherops);
                   1079:              arm_output_asm_insn("mov\t%0, %1", operands);
                   1080:            }
                   1081:          else
                   1082:            {
                   1083:              arm_output_asm_insn("mov\t%0, %1", operands);
                   1084:              arm_output_asm_insn("mov\t%0, %1", otherops);
                   1085:            }
                   1086:        }
                   1087:       else if (code1 == CONST_DOUBLE)
                   1088:        {
                   1089:          otherops[1] = gen_rtx (CONST_INT, VOIDmode,
                   1090:                                 CONST_DOUBLE_HIGH (operands[1]));
                   1091:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
                   1092:                                 CONST_DOUBLE_LOW (operands[1]));
                   1093:          output_mov_immediate (operands, FALSE, "");
                   1094:          output_mov_immediate (otherops, FALSE, "");
                   1095:        }
                   1096:       else if (code1 == CONST_INT)
                   1097:        {
                   1098:          otherops[1] = const0_rtx;
                   1099:          /* sign extend the intval into the high-order word */
                   1100:          /* Note: output_mov_immediate may clobber operands[1], so we
                   1101:             put this out first */
                   1102:          if (INTVAL (operands[1]) < 0)
                   1103:            arm_output_asm_insn ("mvn\t%0, %1", otherops);
                   1104:          else
                   1105:            arm_output_asm_insn ("mov\t%0, %1", otherops);
                   1106:          output_mov_immediate (operands, FALSE, "");
                   1107:        }
                   1108:       else if (code1 == MEM)
                   1109:        {
                   1110:          switch (GET_CODE (XEXP (operands[1], 0)))
                   1111:            {
                   1112:            case REG:
                   1113:              /* Handle the simple case where address is [r, #0] more
                   1114:                 efficient.  */
                   1115:              operands[1] = XEXP (operands[1], 0);
                   1116:              arm_output_asm_insn ("ldmia\t%1, %M0", operands);
                   1117:              break;
                   1118:            case PRE_INC:
                   1119:              operands[1] = XEXP (XEXP (operands[1], 0), 0);
                   1120:              arm_output_asm_insn ("add\t%1, %1, #8", operands);
                   1121:              arm_output_asm_insn ("ldmia\t%1, %M0", operands);
                   1122:              break;
                   1123:            case PRE_DEC:
                   1124:              operands[1] = XEXP (XEXP (operands[1], 0), 0);
                   1125:              arm_output_asm_insn ("sub\t%1, %1, #8", operands);
                   1126:              arm_output_asm_insn ("ldmia\t%1, %M0", operands);
                   1127:              break;
                   1128:            case POST_INC:
                   1129:              operands[1] = XEXP (XEXP (operands[1], 0), 0);
                   1130:              arm_output_asm_insn ("ldmia\t%1!, %M0", operands);
                   1131:              break;
                   1132:            case POST_DEC:
                   1133:              operands[1] = XEXP (XEXP (operands[1], 0), 0);
                   1134:              arm_output_asm_insn ("ldmia\t%1, %M0", operands);
                   1135:              arm_output_asm_insn ("sub\t%1, %1, #8", operands);
                   1136:              break;
                   1137:            default:
                   1138:              otherops[1] = adj_offsettable_operand (operands[1], 4);
                   1139:              /* Take care of overlapping base/data reg.  */
                   1140:              if (reg_mentioned_p (operands[0], operands[1]))
                   1141:                {
                   1142:                  arm_output_asm_insn ("ldr\t%0, %1", otherops);
                   1143:                  arm_output_asm_insn ("ldr\t%0, %1", operands);
                   1144:                }
                   1145:              else
                   1146:                {
                   1147:                  arm_output_asm_insn ("ldr\t%0, %1", operands);
                   1148:                  arm_output_asm_insn ("ldr\t%0, %1", otherops);
                   1149:                }
                   1150:            }
                   1151:        }
                   1152:       else abort();  /* Constraints should prevent this */
                   1153:     }
                   1154:   else if (code0 == MEM && code1 == REG)
                   1155:     {
                   1156:       if (REGNO (operands[1]) == 12)
                   1157:        abort();
                   1158:       switch (GET_CODE (XEXP (operands[0], 0)))
                   1159:         {
                   1160:        case REG:
                   1161:          operands[0] = XEXP (operands[0], 0);
                   1162:          arm_output_asm_insn ("stmia\t%0, %M1", operands);
                   1163:          break;
                   1164:         case PRE_INC:
                   1165:          operands[0] = XEXP (XEXP (operands[0], 0), 0);
                   1166:          arm_output_asm_insn ("add\t%0, %0, #8", operands);
                   1167:          arm_output_asm_insn ("stmia\t%0, %M1", operands);
                   1168:          break;
                   1169:         case PRE_DEC:
                   1170:          operands[0] = XEXP (XEXP (operands[0], 0), 0);
                   1171:          arm_output_asm_insn ("sub\t%0, %0, #8", operands);
                   1172:          arm_output_asm_insn ("stmia\t%0, %M1", operands);
                   1173:          break;
                   1174:         case POST_INC:
                   1175:          operands[0] = XEXP (XEXP (operands[0], 0), 0);
                   1176:          arm_output_asm_insn ("stmia\t%0!, %M1", operands);
                   1177:          break;
                   1178:         case POST_DEC:
                   1179:          operands[0] = XEXP (XEXP (operands[0], 0), 0);
                   1180:          arm_output_asm_insn ("stmia\t%0, %M1", operands);
                   1181:          arm_output_asm_insn ("sub\t%0, %0, #8", operands);
                   1182:          break;
                   1183:         default:
                   1184:          otherops[0] = adj_offsettable_operand (operands[0], 4);
                   1185:          otherops[1] = gen_rtx (REG, SImode, 1 + REGNO (operands[1]));
                   1186:          arm_output_asm_insn ("str\t%1, %0", operands);
                   1187:          arm_output_asm_insn ("str\t%1, %0", otherops);
                   1188:        }
                   1189:     }
                   1190:   else abort();  /* Constraints should prevent this */
                   1191: 
                   1192:   return("");
                   1193: } /* output_move_double */
                   1194: 
                   1195: 
                   1196: /* Output an arbitrary MOV reg, #n.
                   1197:    OPERANDS[0] is a register.  OPERANDS[1] is a const_int.  */
                   1198: 
                   1199: char *
                   1200: output_mov_immediate (operands)
                   1201:      rtx operands[2];
                   1202: {
                   1203:   int n = INTVAL (operands[1]);
                   1204:   int n_ones = 0;
                   1205:   int i;
                   1206: 
                   1207:   /* Try to use one MOV */
                   1208: 
                   1209:   if (const_ok_for_arm (n))
                   1210:     return (arm_output_asm_insn ("mov\t%0, %1", operands));
                   1211: 
                   1212:   /* Try to use one MVN */
                   1213: 
                   1214:   if (const_ok_for_arm(~n))
                   1215:     {
                   1216:       operands[1] = gen_rtx (CONST_INT, VOIDmode, ~n);
                   1217:       return (arm_output_asm_insn ("mvn\t%0, %1", operands));
                   1218:     }
                   1219: 
                   1220:   /* If all else fails, make it out of ORRs or BICs as appropriate. */
                   1221: 
                   1222:   for (i=0; i < 32; i++)
                   1223:     if (n & 1 << i)
                   1224:       n_ones++;
                   1225: 
                   1226:   if (n_ones > 16)  /* Shorter to use MVN with BIC in this case. */
                   1227:     output_multi_immediate(operands, "mvn\t%0, %1", "bic\t%0, %0, %1", 1, ~n);
                   1228:   else
                   1229:     output_multi_immediate(operands, "mov\t%0, %1", "orr\t%0, %0, %1", 1, n);
                   1230:   return("");
                   1231: } /* output_mov_immediate */
                   1232: 
                   1233: 
                   1234: /* Output an ADD r, s, #n where n may be too big for one instruction.  If
                   1235:    adding zero to one register, output nothing.  */
                   1236: 
                   1237: char *
                   1238: output_add_immediate (operands)
                   1239:      rtx operands[3];
                   1240: {
                   1241:   int n = INTVAL (operands[2]);
                   1242: 
                   1243:   if (n != 0 || REGNO (operands[0]) != REGNO (operands[1]))
                   1244:     {
                   1245:       if (n < 0)
                   1246:        output_multi_immediate (operands,
                   1247:                                "sub\t%0, %1, %2", "sub\t%0, %0, %2", 2, -n);
                   1248:       else
                   1249:        output_multi_immediate (operands,
                   1250:                                "add\t%0, %1, %2", "add\t%0, %0, %2", 2, n);
                   1251:     }
                   1252:   return("");
                   1253: } /* output_add_immediate */
                   1254: 
                   1255: 
                   1256: /* Output a multiple immediate operation.
                   1257:    OPERANDS is the vector of operands referred to in the output patterns.
                   1258:    INSTR1 is the output pattern to use for the first constant.
                   1259:    INSTR2 is the output pattern to use for subsequent constants.
                   1260:    IMMED_OP is the index of the constant slot in OPERANDS.
                   1261:    N is the constant value.  */
                   1262: 
                   1263: char *
                   1264: output_multi_immediate (operands, instr1, instr2, immed_op, n)
                   1265:      rtx operands[];
                   1266:      char *instr1, *instr2;
                   1267:      int immed_op, n;
                   1268: {
                   1269:   if (n == 0)
                   1270:     {
                   1271:       operands[immed_op] = const0_rtx;
                   1272:       arm_output_asm_insn (instr1, operands); /* Quick and easy output */
                   1273:     }
                   1274:   else
                   1275:     {
                   1276:       int i;
                   1277:       char *instr = instr1;
                   1278: 
                   1279:       /* Note that n is never zero here (which would give no output) */
                   1280: 
                   1281:       for (i = 0; i < 32; i += 2)
                   1282:        {
                   1283:          if (n & (3 << i))
                   1284:            {
                   1285:              operands[immed_op] = gen_rtx (CONST_INT, VOIDmode,
                   1286:                                            n & (255 << i));
                   1287:              arm_output_asm_insn (instr, operands);
                   1288:              instr = instr2;
                   1289:              i += 6;
                   1290:            }
                   1291:        }
                   1292:     }
                   1293:   return ("");
                   1294: } /* output_multi_immediate */
                   1295: 
                   1296: 
                   1297: /* Return the appropriate ARM instruction for the operation code.
                   1298:    The returned result should not be overwritten.  OP is the rtx of the
                   1299:    operation.  SHIFT_FIRST_ARG is TRUE if the first argument of the operator
                   1300:    was shifted.  */
                   1301: 
                   1302: char *
                   1303: arithmetic_instr (op, shift_first_arg)
                   1304:      rtx op;
                   1305: {
                   1306:   switch (GET_CODE(op))
                   1307:     {
                   1308:     case PLUS:
                   1309:       return ("add");
                   1310:     case MINUS:
                   1311:       if (shift_first_arg)
                   1312:        return ("rsb");
                   1313:       else
                   1314:        return ("sub");
                   1315:     case IOR:
                   1316:       return ("orr");
                   1317:     case XOR:
                   1318:       return ("eor");
                   1319:     case AND:
                   1320:       return ("and");
                   1321:     default:
                   1322:       abort();
                   1323:     }
                   1324:   return ("");                 /* stupid cc */
                   1325: } /* arithmetic_instr */
                   1326: 
                   1327: 
                   1328: /* Ensure valid constant shifts and return the appropriate shift mnemonic
                   1329:    for the operation code.  The returned result should not be overwritten.
                   1330:    OP is the rtx code of the shift.
                   1331:    SHIFT_PTR points to the shift size operand.  */
                   1332: 
                   1333: char *
                   1334: shift_instr (op, shift_ptr)
                   1335:      enum rtx_code op;
                   1336:      rtx *shift_ptr;
                   1337: {
                   1338:   int min_shift = 0;
                   1339:   int max_shift = 31;
                   1340:   char *mnem;
                   1341: 
                   1342:   switch (op)
                   1343:     {
                   1344:     case ASHIFT:
                   1345:       mnem = "asl";
                   1346:       break;
                   1347:     case LSHIFT:
                   1348:       mnem = "lsl";
                   1349:       break;
                   1350:     case ASHIFTRT:
                   1351:       mnem = "asr";
                   1352:       max_shift = 32;
                   1353:       break;
                   1354:     case LSHIFTRT:
                   1355:       mnem = "lsr";
                   1356:       max_shift = 32;
                   1357:       break;
                   1358:     case MULT:
                   1359:       *shift_ptr = gen_rtx (CONST_INT, VOIDmode,
                   1360:                            int_log2 (INTVAL (*shift_ptr)));
                   1361:       return ("asl");
                   1362:     default:
                   1363:       abort();
                   1364:     }
                   1365: 
                   1366:   if (GET_CODE (*shift_ptr) == CONST_INT)
                   1367:     {
                   1368:       int shift = INTVAL (*shift_ptr);
                   1369: 
                   1370:       if (shift < min_shift)
                   1371:        *shift_ptr = gen_rtx (CONST_INT, VOIDmode, 0);
                   1372:       else if (shift > max_shift)
                   1373:        *shift_ptr = gen_rtx (CONST_INT, VOIDmode, max_shift);
                   1374:     }
                   1375:   return (mnem);
                   1376: } /* shift_instr */
                   1377: 
                   1378: 
                   1379: /* Obtain the shift from the POWER of two. */
                   1380: 
                   1381: int
                   1382: int_log2 (power)
                   1383:      unsigned int power;
                   1384: {
                   1385:   int shift = 0;
                   1386: 
                   1387:   while (((1 << shift) & power) == 0)
                   1388:     {
                   1389:       if (shift > 31)
                   1390:        abort();
                   1391:       shift++;
                   1392:     }
                   1393:   return (shift);
                   1394: } /* int_log2 */
                   1395: 
                   1396: 
                   1397: /* Output an arithmetic instruction which may set the condition code.
                   1398:    OPERANDS[0] is the destination register.
                   1399:    OPERANDS[1] is the arithmetic operator expression.
                   1400:    OPERANDS[2] is the left hand argument.
                   1401:    OPERANDS[3] is the right hand argument.
                   1402:    CONST_FIRST_ARG is TRUE if the first argument of the operator was constant.
                   1403:    SET_COND is TRUE when the condition code should be set.  */
                   1404: 
                   1405: char *
                   1406: output_arithmetic (operands, const_first_arg, set_cond)
                   1407:      rtx operands[4];
                   1408:      int const_first_arg;
                   1409:      int set_cond;
                   1410: {
                   1411:   char mnemonic[80];
                   1412:   char *instr = arithmetic_instr (operands[1], const_first_arg);
                   1413: 
                   1414:   sprintf (mnemonic, "%s%s\t%%0, %%2, %%3", instr, set_cond ? "s" : "");
                   1415:   return (arm_output_asm_insn (mnemonic, operands));
                   1416: } /* output_arithmetic */
                   1417: 
                   1418: 
                   1419: /* Output an arithmetic instruction with a shift.
                   1420:    OPERANDS[0] is the destination register.
                   1421:    OPERANDS[1] is the arithmetic operator expression.
                   1422:    OPERANDS[2] is the unshifted register.
                   1423:    OPERANDS[3] is the shift operator expression.
                   1424:    OPERANDS[4] is the shifted register.
                   1425:    OPERANDS[5] is the shift constant or register.
                   1426:    SHIFT_FIRST_ARG is TRUE if the first argument of the operator was shifted.
                   1427:    SET_COND is TRUE when the condition code should be set.  */
                   1428: 
                   1429: char *
                   1430: output_arithmetic_with_shift (operands, shift_first_arg, set_cond)
                   1431:      rtx operands[6];
                   1432:      int shift_first_arg;
                   1433:      int set_cond;
                   1434: {
                   1435:   char mnemonic[80];
                   1436:   char *instr = arithmetic_instr (operands[1], shift_first_arg);
                   1437:   char *condbit = set_cond ? "s" : "";
                   1438:   char *shift = shift_instr (GET_CODE (operands[3]), &operands[5]);
                   1439: 
                   1440:   sprintf (mnemonic, "%s%s\t%%0, %%2, %%4, %s %%5", instr, condbit, shift);
                   1441:   return (arm_output_asm_insn (mnemonic, operands));
                   1442: } /* output_arithmetic_with_shift */
                   1443: 
                   1444: 
                   1445: /* Output an arithmetic instruction with a power of two multiplication.
                   1446:    OPERANDS[0] is the destination register.
                   1447:    OPERANDS[1] is the arithmetic operator expression.
                   1448:    OPERANDS[2] is the unmultiplied register.
                   1449:    OPERANDS[3] is the multiplied register.
                   1450:    OPERANDS[4] is the constant multiple (power of two).
                   1451:    SHIFT_FIRST_ARG is TRUE if the first arg of the operator was multiplied.  */
                   1452: 
                   1453: char *
                   1454: output_arithmetic_with_immediate_multiply (operands, shift_first_arg)
                   1455:      rtx operands[5];
                   1456:      int shift_first_arg;
                   1457: {
                   1458:   char mnemonic[80];
                   1459:   char *instr = arithmetic_instr (operands[1], shift_first_arg);
                   1460:   int shift = int_log2 (INTVAL (operands[4]));
                   1461: 
                   1462:   sprintf (mnemonic, "%s\t%%0, %%2, %%3, asl#%d", instr, shift);
                   1463:   return (arm_output_asm_insn (mnemonic, operands));
                   1464: } /* output_arithmetic_with_immediate_multiply */
                   1465: 
                   1466: 
                   1467: /* Output a move with a shift.
                   1468:    OP is the shift rtx code.
                   1469:    OPERANDS[0] = destination register.
                   1470:    OPERANDS[1] = source register.
                   1471:    OPERANDS[2] = shift constant or register.  */
                   1472: 
                   1473: char *
                   1474: output_shifted_move (op, operands)
                   1475:      enum rtx_code op;
                   1476:      rtx operands[2];
                   1477: {
                   1478:   char mnemonic[80];
                   1479: 
                   1480:   if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0)
                   1481:     sprintf (mnemonic, "mov\t%%0, %%1");
                   1482:   else
                   1483:     sprintf (mnemonic, "mov\t%%0, %%1, %s %%2",
                   1484:             shift_instr (op, &operands[2]));
                   1485:   return (arm_output_asm_insn (mnemonic, operands));
                   1486: } /* output_shifted_move */
                   1487: 
                   1488: char *
                   1489: output_shift_compare (operands, neg)
                   1490: rtx *operands;
                   1491: int neg;
                   1492: {
                   1493:   char buf[80];
                   1494: 
                   1495:   if (neg)
                   1496:     sprintf (buf, "cmn\t%%1, %%3, %s %%4", shift_instr (GET_CODE (operands[2]),
                   1497:                                                        &operands[4]));
                   1498:   else
                   1499:     sprintf (buf, "cmp\t%%1, %%3, %s %%4", shift_instr (GET_CODE (operands[2]),
                   1500:                                                        &operands[4]));
                   1501:   return arm_output_asm_insn (buf, operands);
                   1502: } /* output_shift_compare */
                   1503: 
                   1504: /* Output a .ascii pseudo-op, keeping track of lengths.  This is because
                   1505:    /bin/as is horribly restrictive.  */
                   1506: 
                   1507: void
                   1508: output_ascii_pseudo_op (stream, p, len)
                   1509:      FILE *stream;
                   1510:      unsigned char *p;
                   1511:      int len;
                   1512: {
                   1513:   int i;
                   1514:   int len_so_far = 1000;
                   1515:   int chars_so_far = 0;
                   1516: 
                   1517:   for (i = 0; i < len; i++)
                   1518:     {
                   1519:       register int c = p[i];
                   1520: 
                   1521:       if (len_so_far > 50)
                   1522:        {
                   1523:          if (chars_so_far)
                   1524:            fputs ("\"\n", stream);
                   1525:          fputs ("\t.ascii\t\"", stream);
                   1526:          len_so_far = 0;
                   1527:          arm_increase_location (chars_so_far);
                   1528:          chars_so_far = 0;
                   1529:        }
                   1530: 
                   1531:       if (c == '\"' || c == '\\')
                   1532:        {
                   1533:          putc('\\', stream);
                   1534:          len_so_far++;
                   1535:        }
                   1536:       if (c >= ' ' && c < 0177)
                   1537:        {
                   1538:          putc (c, stream);
                   1539:          len_so_far++;
                   1540:        }
                   1541:       else
                   1542:        {
                   1543:          fprintf (stream, "\\%03o", c);
                   1544:          len_so_far +=4;
                   1545:        }
                   1546:       chars_so_far++;
                   1547:     }
                   1548:   fputs ("\"\n", stream);
                   1549:   arm_increase_location (chars_so_far);
                   1550: } /* output_ascii_pseudo_op */
                   1551: 
                   1552: 
                   1553: /* Try to determine whether a pattern really clobbers the link register.
                   1554:    This information is useful when peepholing, so that lr need not be pushed
                   1555:    if we combine a call followed by a return.
                   1556:    NOTE: This code does not check for side-effect expressions in a SET_SRC:
                   1557:    such a check should not be needed because these only update an existing
                   1558:    value within a register; the register must still be set elsewhere within
                   1559:    the function. */
                   1560: 
                   1561: static int
                   1562: pattern_really_clobbers_lr (x)
                   1563: rtx x;
                   1564: {
                   1565:   int i;
                   1566:   
                   1567:   switch (GET_CODE (x))
                   1568:     {
                   1569:     case SET:
                   1570:       switch (GET_CODE (SET_DEST (x)))
                   1571:        {
                   1572:        case REG:
                   1573:          return REGNO (SET_DEST (x)) == 14;
                   1574:         case SUBREG:
                   1575:          if (GET_CODE (XEXP (SET_DEST (x), 0)) == REG)
                   1576:            return REGNO (XEXP (SET_DEST (x), 0)) == 14;
                   1577:          if (GET_CODE (XEXP (SET_DEST (x), 0)) == MEM)
                   1578:            return 0;
                   1579:          abort ();
                   1580:         default:
                   1581:          return 0;
                   1582:         }
                   1583:     case PARALLEL:
                   1584:       for (i = 0; i < XVECLEN (x, 0); i++)
                   1585:        if (pattern_really_clobbers_lr (XVECEXP (x, 0, i)))
                   1586:          return 1;
                   1587:       return 0;
                   1588:     case CLOBBER:
                   1589:       switch (GET_CODE (XEXP (x, 0)))
                   1590:         {
                   1591:        case REG:
                   1592:          return REGNO (XEXP (x, 0)) == 14;
                   1593:         case SUBREG:
                   1594:          if (GET_CODE (XEXP (XEXP (x, 0), 0)) == REG)
                   1595:            return REGNO (XEXP (XEXP (x, 0), 0)) == 14;
                   1596:          abort ();
                   1597:         default:
                   1598:          return 0;
                   1599:         }
                   1600:     case UNSPEC:
                   1601:       return 1;
                   1602:     default:
                   1603:       return 0;
                   1604:     }
                   1605: }
                   1606: 
                   1607: static int
                   1608: function_really_clobbers_lr (first)
                   1609: rtx first;
                   1610: {
                   1611:   rtx insn, next;
                   1612:   
                   1613:   for (insn = first; insn; insn = next_nonnote_insn (insn))
                   1614:     {
                   1615:       switch (GET_CODE (insn))
                   1616:         {
                   1617:        case BARRIER:
                   1618:        case NOTE:
                   1619:        case CODE_LABEL:
                   1620:        case JUMP_INSN:         /* Jump insns only change the PC (and conds) */
                   1621:        case INLINE_HEADER:
                   1622:          break;
                   1623:         case INSN:
                   1624:          if (pattern_really_clobbers_lr (PATTERN (insn)))
                   1625:            return 1;
                   1626:          break;
                   1627:         case CALL_INSN:
                   1628:          /* Don't yet know how to handle those calls that are not to a 
                   1629:             SYMBOL_REF */
                   1630:          if (GET_CODE (PATTERN (insn)) != PARALLEL)
                   1631:            abort ();
                   1632:          switch (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)))
                   1633:            {
                   1634:            case CALL:
                   1635:              if (GET_CODE (XEXP (XEXP (XVECEXP (PATTERN (insn), 0, 0), 0), 0))
                   1636:                  != SYMBOL_REF)
                   1637:                return 1;
                   1638:              break;
                   1639:            case SET:
                   1640:              if (GET_CODE (XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (insn),
                   1641:                                                          0, 0)), 0), 0))
                   1642:                  != SYMBOL_REF)
                   1643:                return 1;
                   1644:              break;
                   1645:            default:    /* Don't recognize it, be safe */
                   1646:              return 1;
                   1647:            }
                   1648:          /* A call can be made (by peepholing) not to clobber lr iff it is
                   1649:             followed by a return.  There may, however, be a use insn iff
                   1650:             we are returning the result of the call. 
                   1651:             If we run off the end of the insn chain, then that means the
                   1652:             call was at the end of the function.  Unfortunately we don't
                   1653:             have a return insn for the peephole to recognize, so we
                   1654:             must reject this.  (Can this be fixed by adding our own insn?) */
                   1655:          if ((next = next_nonnote_insn (insn)) == NULL)
                   1656:            return 1;
                   1657:          if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == USE
                   1658:              && (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
                   1659:              && (REGNO (SET_DEST (XVECEXP (PATTERN (insn), 0, 0)))
                   1660:                  == REGNO (XEXP (PATTERN (next), 0))))
                   1661:            if ((next = next_nonnote_insn (next)) == NULL)
                   1662:              return 1;
                   1663:          if (GET_CODE (next) == JUMP_INSN
                   1664:              && GET_CODE (PATTERN (next)) == RETURN)
                   1665:            break;
                   1666:          return 1;
                   1667:         default:
                   1668:          abort ();
                   1669:         }
                   1670:     }
                   1671:   /* We have reached the end of the chain so lr was _not_ clobbered */
                   1672:   return 0;
                   1673: }
                   1674: 
                   1675: char *
                   1676: output_return_instruction (operand, really_return)
                   1677: rtx operand;
                   1678: int really_return;
                   1679: {
                   1680:   char instr[100];
                   1681:   int reg, live_regs = 0;
                   1682: 
                   1683:   if (current_function_calls_alloca && !really_return)
                   1684:     abort();
                   1685:     
                   1686:   for (reg = 4; reg < 10; reg++)
                   1687:     if (regs_ever_live[reg])
                   1688:       live_regs++;
                   1689: 
                   1690:   if (live_regs || (regs_ever_live[14] && !lr_save_eliminated))
                   1691:     live_regs++;
                   1692: 
                   1693:   if (frame_pointer_needed)
                   1694:     live_regs += 4;
                   1695: 
                   1696:   if (live_regs)
                   1697:     {
                   1698:       if (lr_save_eliminated || !regs_ever_live[14])
                   1699:         live_regs++;
                   1700:       if (frame_pointer_needed)
                   1701:         strcpy (instr, "ldm%d0ea\tfp, {");
                   1702:       else
                   1703:         strcpy (instr, "ldm%d0fd\tsp!, {");
                   1704:       for (reg = 4; reg < 10; reg++)
                   1705:         if (regs_ever_live[reg])
                   1706:           {
                   1707:             strcat (instr, reg_names[reg]);
                   1708:            if (--live_regs)
                   1709:               strcat (instr, ", ");
                   1710:           }
                   1711:       if (frame_pointer_needed)
                   1712:         {
                   1713:           strcat (instr, reg_names[11]);
                   1714:           strcat (instr, ", ");
                   1715:           strcat (instr, reg_names[13]);
                   1716:           strcat (instr, ", ");
                   1717:           strcat (instr, really_return ? reg_names[15] : reg_names[14]);
                   1718:         }
                   1719:       else
                   1720:         strcat (instr, really_return ? reg_names[15] : reg_names[14]);
                   1721:       strcat (instr, (TARGET_6 || !really_return) ? "}" : "}^");
                   1722:       arm_output_asm_insn (instr, &operand);
                   1723:     }
                   1724:   else if (really_return)
                   1725:     {
                   1726:       strcpy (instr, TARGET_6 ? "mov%d0\tpc, lr" : "mov%d0s\tpc, lr");
                   1727:       arm_output_asm_insn (instr, &operand);
                   1728:     }
                   1729:   return_used_this_function = 1;
                   1730:   return "";
                   1731: }
                   1732: 
                   1733: /* The amount of stack adjustment that happens here, in output_return and in
                   1734:    output_epilogue must be exactly the same as was calculated during reload,
                   1735:    or things will point to the wrong place.  The only time we can safely
                   1736:    ignore this constraint is when a function has no arguments on the stack,
                   1737:    no stack frame requirement and no live registers execpt for `lr'.  If we
                   1738:    can guarantee that by making all function calls into tail calls and that
                   1739:    lr is not clobbered in any other way, then there is no need to push lr
                   1740:    onto the stack. */
                   1741:    
                   1742: void
                   1743: output_prologue (f, frame_size)
                   1744:      FILE *f;
                   1745:      int frame_size;
                   1746: {
                   1747:   int reg, live_regs_mask = 0, code_size = 0;
                   1748:   rtx operands[3];
                   1749: 
                   1750:   /* Nonzero if we must stuff some register arguments onto the stack as if
                   1751:      they were passed there.  */
                   1752:   int store_arg_regs = 0;
                   1753: 
                   1754:   if (arm_ccfsm_state || arm_target_insn)
                   1755:     abort ();                                  /* Sanity check */
                   1756:   
                   1757:   return_used_this_function = 0;
                   1758:   lr_save_eliminated = 0;
                   1759:   
                   1760:   fprintf (f, "\t@ args = %d, pretend = %d, frame = %d\n",
                   1761:           current_function_args_size, current_function_pretend_args_size,
                   1762:           frame_size);
                   1763:   fprintf (f, "\t@ frame_needed = %d, current_function_anonymous_args = %d\n",
                   1764:           frame_pointer_needed, current_function_anonymous_args);
                   1765: 
                   1766:   if (current_function_anonymous_args && current_function_pretend_args_size)
                   1767:     store_arg_regs = 1;
                   1768: 
                   1769:   for (reg = 4; reg < 10; reg++)
                   1770:     if (regs_ever_live[reg])
                   1771:       live_regs_mask |= (1 << reg);
                   1772: 
                   1773:   if (frame_pointer_needed)
                   1774:     {
                   1775:       live_regs_mask |= 0xD800;
                   1776:       fputs ("\tmov\tip, sp\n", f);
                   1777:       code_size += 4;
                   1778:     }
                   1779:   else if (regs_ever_live[14])
                   1780:     {
                   1781:       if (! current_function_args_size
                   1782:          && !function_really_clobbers_lr (get_insns ()))
                   1783:        {
                   1784:          fprintf (f,"\t@ I don't think this function clobbers lr\n");
                   1785:          lr_save_eliminated = 1;
                   1786:         }
                   1787:       else
                   1788:         live_regs_mask |= 0x4000;
                   1789:     }
                   1790: 
                   1791:   /* If CURRENT_FUNCTION_PRETEND_ARGS_SIZE, adjust the stack pointer to make
                   1792:      room.  If also STORE_ARG_REGS store the argument registers involved in
                   1793:      the created slot (this is for stdarg and varargs).  */
                   1794:   if (current_function_pretend_args_size)
                   1795:     {
                   1796:       if (store_arg_regs)
                   1797:        {
                   1798:          int arg_size, mask = 0;
                   1799: 
                   1800:          assert (current_function_pretend_args_size <= 16);
                   1801:          for (reg = 3, arg_size = current_function_pretend_args_size;
                   1802:               arg_size > 0; reg--, arg_size -= 4)
                   1803:            mask |= (1 << reg);
                   1804:          print_multi_reg (f, "stmfd\tsp!", mask, FALSE);
                   1805:          code_size += 4;
                   1806:        }
                   1807:       else
                   1808:        {
                   1809:          operands[0] = operands[1] = stack_pointer_rtx;
                   1810:          operands[2] = gen_rtx (CONST_INT, VOIDmode,
                   1811:                                 -current_function_pretend_args_size);
                   1812:          output_add_immediate (operands);
                   1813:        }
                   1814:     }
                   1815: 
                   1816:   if (live_regs_mask)
                   1817:     {
                   1818:       /* if a di mode load/store multiple is used, and the base register
                   1819:         is r3, then r4 can become an ever live register without lr
                   1820:         doing so,  in this case we need to push lr as well, or we
                   1821:         will fail to get a proper return. */
                   1822: 
                   1823:       live_regs_mask |= 0x4000;
                   1824:       lr_save_eliminated = 0;
                   1825:       print_multi_reg (f, "stmfd\tsp!", live_regs_mask, FALSE);
                   1826:       code_size += 4;
                   1827:     }
                   1828: 
                   1829:   for (reg = 23; reg > 19; reg--)
                   1830:     if (regs_ever_live[reg])
                   1831:       {
                   1832:        fprintf (f, "\tstfe\t%s, [sp, #-12]!\n", reg_names[reg]);
                   1833:        code_size += 4;
                   1834:       }
                   1835: 
                   1836:   if (frame_pointer_needed)
                   1837:     {
                   1838:       /* Make `fp' point to saved value of `pc'. */
                   1839: 
                   1840:       operands[0] = gen_rtx (REG, SImode, HARD_FRAME_POINTER_REGNUM);
                   1841:       operands[1] = gen_rtx (REG, SImode, 12);
                   1842:       operands[2] = gen_rtx (CONST_INT, VOIDmode,
                   1843:                             - (4 + current_function_pretend_args_size));
                   1844:       output_add_immediate (operands);
                   1845:     }
                   1846: 
                   1847:   if (frame_size)
                   1848:     {
                   1849:       operands[0] = operands[1] = stack_pointer_rtx;
                   1850:       operands[2] = gen_rtx (CONST_INT, VOIDmode, -frame_size);
                   1851:       output_add_immediate (operands);
                   1852:     }
                   1853: 
                   1854:   arm_increase_location (code_size);
                   1855: } /* output_prologue */
                   1856: 
                   1857: 
                   1858: void
                   1859: output_epilogue (f, frame_size)
                   1860:      FILE *f;
                   1861:      int frame_size;
                   1862: {
                   1863:   int reg, live_regs_mask = 0, code_size = 0;
                   1864:   /* If we need this then it will always be at lesat this much */
                   1865:   int floats_offset = 24;
                   1866:   rtx operands[3];
                   1867: 
                   1868:   if (use_return_insn() && return_used_this_function)
                   1869:     {
                   1870:       if (frame_size && !(frame_pointer_needed || TARGET_APCS))
                   1871:         {
                   1872:           abort ();
                   1873:         }
                   1874:       return;
                   1875:     }
                   1876: 
                   1877:   for (reg = 4; reg <= 10; reg++)
                   1878:     if (regs_ever_live[reg])
                   1879:       {
                   1880:         live_regs_mask |= (1 << reg);
                   1881:        floats_offset += 4;
                   1882:       }
                   1883: 
                   1884: 
                   1885:   if (frame_pointer_needed)
                   1886:     {
                   1887:       for (reg = 23; reg >= 20; reg--)
                   1888:        if (regs_ever_live[reg])
                   1889:          {
                   1890:            fprintf (f, "\tldfe\t%s, [fp, #-%d]\n", reg_names[reg],
                   1891:                     floats_offset);
                   1892:            floats_offset += 12;
                   1893:            code_size += 4;
                   1894:          }
                   1895: 
                   1896:       live_regs_mask |= 0xA800;
                   1897:       print_multi_reg (f, "ldmea\tfp", live_regs_mask,
                   1898:                       TARGET_6 ? FALSE : TRUE);
                   1899:       code_size += 4;
                   1900:     }
                   1901:   else
                   1902:     {
                   1903:       /* Restore stack pointer if necessary.  */
                   1904:       if (frame_size)
                   1905:        {
                   1906:          operands[0] = operands[1] = stack_pointer_rtx;
                   1907:          operands[2] = gen_rtx (CONST_INT, VOIDmode, frame_size);
                   1908:          output_add_immediate (operands);
                   1909:        }
                   1910: 
                   1911:       for (reg = 20; reg < 24; reg++)
                   1912:        if (regs_ever_live[reg])
                   1913:          {
                   1914:            fprintf (f, "\tldfe\t%s, [sp], #12\n", reg_names[reg]);
                   1915:            code_size += 4;
                   1916:          }
                   1917:       if (current_function_pretend_args_size == 0 && regs_ever_live[14])
                   1918:        {
                   1919:          print_multi_reg (f, "ldmfd\tsp!", live_regs_mask | 0x8000,
                   1920:                           TARGET_6 ? FALSE : TRUE);
                   1921:          code_size += 4;
                   1922:        }
                   1923:       else
                   1924:        {
                   1925:          if (live_regs_mask || regs_ever_live[14])
                   1926:            {
                   1927:              live_regs_mask |= 0x4000;
                   1928:              print_multi_reg (f, "ldmfd\tsp!", live_regs_mask, FALSE);
                   1929:              code_size += 4;
                   1930:            }
                   1931:          if (current_function_pretend_args_size)
                   1932:            {
                   1933:              operands[0] = operands[1] = stack_pointer_rtx;
                   1934:              operands[2] = gen_rtx (CONST_INT, VOIDmode,
                   1935:                                     current_function_pretend_args_size);
                   1936:              output_add_immediate (operands);
                   1937:            }
                   1938:          fputs (TARGET_6 ? "\tmov\tpc, lr\n" : "\tmovs\tpc, lr\n", f);
                   1939:          code_size += 4;
                   1940:        }
                   1941:     }
                   1942:   arm_increase_location (code_size);
                   1943:   current_function_anonymous_args = 0;
                   1944: } /* output_epilogue */
                   1945: 
                   1946: /* Increase the `arm_text_location' by AMOUNT if we're in the text
                   1947:    segment.  */
                   1948: 
                   1949: void
                   1950: arm_increase_location (amount)
                   1951:      int amount;
                   1952: {
                   1953:   if (in_text_section ())
                   1954:     arm_text_location += amount;
                   1955: } /* arm_increase_location */
                   1956: 
                   1957: 
                   1958: /* Like output_asm_insn (), but also increases the arm_text_location (if in
                   1959:    the .text segment, of course, even though this will always be true).
                   1960:    Returns the empty string.  */
                   1961: 
                   1962: char *
                   1963: arm_output_asm_insn (template, operands)
                   1964:      char *template;
                   1965:      rtx *operands;
                   1966: {
                   1967:   extern FILE *asm_out_file;
                   1968: 
                   1969:   output_asm_insn (template, operands);
                   1970:   if (in_text_section ())
                   1971:     arm_text_location += 4;
                   1972:   fflush (asm_out_file);
                   1973:   return ("");
                   1974: } /* arm_output_asm_insn */
                   1975: 
                   1976: 
                   1977: /* Output a label definition.  If this label is within the .text segment, it
                   1978:    is stored in OFFSET_TABLE, to be used when building `llc' instructions.
                   1979:    Maybe GCC remembers names not starting with a `*' for a long time, but this
                   1980:    is a minority anyway, so we just make a copy.  Do not store the leading `*'
                   1981:    if the name starts with one.  */
                   1982: 
                   1983: void
                   1984: arm_asm_output_label (stream, name)
                   1985:      FILE *stream;
                   1986:      char *name;
                   1987: {
                   1988:   char *real_name, *s;
                   1989:   struct label_offset *cur;
                   1990:   int hash = 0;
                   1991: 
                   1992:   assemble_name (stream, name);
                   1993:   fputs (":\n", stream);
                   1994:   if (! in_text_section ())
                   1995:     return;
                   1996: 
                   1997:   if (name[0] == '*')
                   1998:     {
                   1999:       real_name = xmalloc (1 + strlen (&name[1]));
                   2000:       strcpy (real_name, &name[1]);
                   2001:     }
                   2002:   else
                   2003:     {
                   2004:       real_name = xmalloc (2 + strlen (name));
                   2005:       strcpy (real_name, "_");
                   2006:       strcat (real_name, name);
                   2007:     }
                   2008:   for (s = real_name; *s; s++)
                   2009:     hash += *s;
                   2010:   hash = hash % LABEL_HASH_SIZE;
                   2011:   cur = (struct label_offset *) xmalloc (sizeof (struct label_offset));
                   2012:   cur->name = real_name;
                   2013:   cur->offset = arm_text_location;
                   2014:   cur->cdr = offset_table[hash];
                   2015:   offset_table[hash] = cur;
                   2016: } /* arm_asm_output_label */
                   2017: 
                   2018: 
                   2019: /* Output the instructions needed to perform what Martin's /bin/as called
                   2020:    llc: load an SImode thing from the function's constant pool.
                   2021: 
                   2022:    XXX This could be enhanced in that we do not really need a pointer in the
                   2023:    constant pool pointing to the real thing.  If we can address this pointer,
                   2024:    we can also address what it is pointing at, in fact, anything in the text
                   2025:    segment which has been defined already within this .s file.  */
                   2026: 
                   2027: char *
                   2028: arm_output_llc (operands)
                   2029:      rtx *operands;
                   2030: {
                   2031:   char *s, *name = XSTR (XEXP (operands[1], 0), 0);
                   2032:   struct label_offset *he;
                   2033:   int hash = 0, conditional = (arm_ccfsm_state == 3 || arm_ccfsm_state == 4);
                   2034: 
                   2035:   if (*name != '*')
                   2036:     abort ();
                   2037: 
                   2038:   for (s = &name[1]; *s; s++)
                   2039:     hash += *s;
                   2040:   hash = hash % LABEL_HASH_SIZE;
                   2041:   he = offset_table[hash];
                   2042:   while (he && strcmp (he->name, &name[1]))
                   2043:     he = he->cdr;
                   2044: 
                   2045:   if (!he)
                   2046:     abort ();
                   2047: 
                   2048:   if (arm_text_location + 8 - he->offset < 4095)
                   2049:     {
                   2050:       fprintf (asm_out_file, "\tldr%s\t%s, [pc, #%s - . - 8]\n",
                   2051:               conditional ? arm_condition_codes[arm_current_cc] : "",
                   2052:               reg_names[REGNO (operands[0])], &name[1]);
                   2053:       arm_increase_location (4);
                   2054:       return ("");
                   2055:     }
                   2056:   else
                   2057:     {
                   2058:       int offset = - (arm_text_location + 8 - he->offset);
                   2059:       char *reg_name = reg_names[REGNO (operands[0])];
                   2060: 
                   2061:       /* ??? This is a hack, assuming the constant pool never is more than
                   2062:         (1 + 255) * 4096 == 1Meg away from the PC.  */
                   2063: 
                   2064:       if (offset > 1000000)
                   2065:        abort ();
                   2066: 
                   2067:       fprintf (asm_out_file, "\tsub%s\t%s, pc, #(8 + . - %s) & ~4095\n",
                   2068:               conditional ? arm_condition_codes[arm_current_cc] : "",
                   2069:               reg_name, &name[1]);
                   2070:       fprintf (asm_out_file, "\tldr%s\t%s, [%s, #- ((4 + . - %s) & 4095)]\n",
                   2071:               conditional ? arm_condition_codes[arm_current_cc] : "",
                   2072:               reg_name, reg_name, &name[1]);
                   2073:       arm_increase_location (8);
                   2074:     }
                   2075:   return ("");
                   2076: } /* arm_output_llc */
                   2077: 
                   2078: /* output_load_symbol ()
                   2079:    load a symbol that is known to be in the text segment into a register */
                   2080: 
                   2081: char *
                   2082: output_load_symbol (operands)
                   2083: rtx *operands;
                   2084: {
                   2085:   char *s, *name = XSTR (operands[1], 0);
                   2086:   struct label_offset *he;
                   2087:   int hash = 0;
                   2088:   int offset;
                   2089:   
                   2090:   if (*name != '*')
                   2091:     abort ();
                   2092: 
                   2093:   for (s = &name[1]; *s; s++)
                   2094:     hash += *s;
                   2095:   hash = hash % LABEL_HASH_SIZE;
                   2096:   he = offset_table[hash];
                   2097:   while (he && strcmp (he->name, &name[1]))
                   2098:     he = he->cdr;
                   2099:   
                   2100:   if (!he)
                   2101:     abort ();
                   2102:   
                   2103:   offset = (arm_text_location + 8 - he->offset);
                   2104:   if (offset < 0)
                   2105:     abort ();
                   2106: 
                   2107:   /* If the symbol is word aligned then we might be able to reduce the
                   2108:      number of loads */
                   2109:   if ((offset & 3) == 0)
                   2110:     {
                   2111:       arm_output_asm_insn ("sub\t%0, pc, #(8 + . -%a1) & 1023", operands);
                   2112:       if (offset > 0x3ff)
                   2113:         {
                   2114:          arm_output_asm_insn ("sub\t%0, %0, #(4 + . -%a1) & 261120",
                   2115:                               operands);
                   2116:          if (offset > 0x3ffff)
                   2117:            {
                   2118:              arm_output_asm_insn ("sub\t%0, %0, #(. -%a1) & 66846720",
                   2119:                                   operands);
                   2120:              if (offset > 0x3ffffff)
                   2121:                arm_output_asm_insn ("sub\t%0, %0, #(. - 4 -%a1) & -67108864",
                   2122:                                       operands);
                   2123:            }
                   2124:         }
                   2125:     }
                   2126:   else
                   2127:     {
                   2128:       arm_output_asm_insn ("sub\t%0, pc, #(8 + . -%a1) & 255", operands);
                   2129:       if (offset > 0x0ff)
                   2130:         {
                   2131:          arm_output_asm_insn ("sub\t%0, %0, #(4 + . -%a1) & 65280", operands);
                   2132:          if (offset > 0x0ffff)
                   2133:            {
                   2134:              arm_output_asm_insn ("sub\t%0, %0, #(. -%a1) & 16711680",
                   2135:                                   operands);
                   2136:              if (offset > 0x0ffffff)
                   2137:                arm_output_asm_insn ("sub\t%0, %0, #(. - 4 -%a1) & -16777216",
                   2138:                                     operands);
                   2139:            }
                   2140:         }
                   2141:     }
                   2142:   return "";
                   2143: }
                   2144: 
                   2145: /* Output code resembling an .lcomm directive.  /bin/as doesn't have this
                   2146:    directive hence this hack, which works by reserving some `.space' in the
                   2147:    bss segment directly.
                   2148: 
                   2149:    XXX This is a severe hack, which is guaranteed NOT to work since it doesn't
                   2150:    define STATIC COMMON space but merely STATIC BSS space.  */
                   2151: 
                   2152: void
                   2153: output_lcomm_directive (stream, name, size, rounded)
                   2154:      FILE *stream;
                   2155:      char *name;
                   2156:      int size, rounded;
                   2157: {
                   2158:   fputs ("\n\t.bss\t@ .lcomm\n", stream);
                   2159:   assemble_name (stream, name);
                   2160:   fprintf (stream, ":\t.space\t%d\n", rounded);
                   2161:   if (in_text_section ())
                   2162:     fputs ("\n\t.text\n", stream);
                   2163:   else
                   2164:     fputs ("\n\t.data\n", stream);
                   2165: } /* output_lcomm_directive */
                   2166: 
                   2167: /* A finite state machine takes care of noticing whether or not instructions
                   2168:    can be conditionally executed, and thus decrease execution time and code
                   2169:    size by deleting branch instructions.  The fsm is controlled by
                   2170:    final_prescan_insn, and controls the actions of ASM_OUTPUT_OPCODE.  */
                   2171: 
                   2172: /* The state of the fsm controlling condition codes are:
                   2173:    0: normal, do nothing special
                   2174:    1: make ASM_OUTPUT_OPCODE not output this instruction
                   2175:    2: make ASM_OUTPUT_OPCODE not output this instruction
                   2176:    3: make instructions conditional
                   2177:    4: make instructions conditional
                   2178: 
                   2179:    State transitions (state->state by whom under condition):
                   2180:    0 -> 1 final_prescan_insn if the `target' is a label
                   2181:    0 -> 2 final_prescan_insn if the `target' is an unconditional branch
                   2182:    1 -> 3 ASM_OUTPUT_OPCODE after not having output the conditional branch
                   2183:    2 -> 4 ASM_OUTPUT_OPCODE after not having output the conditional branch
                   2184:    3 -> 0 ASM_OUTPUT_INTERNAL_LABEL if the `target' label is reached
                   2185:           (the target label has CODE_LABEL_NUMBER equal to arm_target_label).
                   2186:    4 -> 0 final_prescan_insn if the `target' unconditional branch is reached
                   2187:           (the target insn is arm_target_insn).
                   2188: 
                   2189:    If the jump clobbers the conditions then we use states 2 and 4.
                   2190: 
                   2191:    A similar thing can be done with conditional return insns.
                   2192: 
                   2193:    XXX In case the `target' is an unconditional branch, this conditionalising
                   2194:    of the instructions always reduces code size, but not always execution
                   2195:    time.  But then, I want to reduce the code size to somewhere near what
                   2196:    /bin/cc produces.  */
                   2197: 
                   2198: /* The condition codes of the ARM, and the inverse function.  */
                   2199: char *arm_condition_codes[] =
                   2200: {
                   2201:   "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
                   2202:   "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
                   2203: };
                   2204: 
                   2205: #define ARM_INVERSE_CONDITION_CODE(X)  ((X) ^ 1)
                   2206: 
                   2207: /* Returns the index of the ARM condition code string in
                   2208:    `arm_condition_codes'.  COMPARISON should be an rtx like
                   2209:    `(eq (...) (...))'.  */
                   2210: 
                   2211: int
                   2212: get_arm_condition_code (comparison)
                   2213:      rtx comparison;
                   2214: {
                   2215:   switch (GET_CODE (comparison))
                   2216:     {
                   2217:     case NE: return (1);
                   2218:     case EQ: return (0);
                   2219:     case GE: return (10);
                   2220:     case GT: return (12);
                   2221:     case LE: return (13);
                   2222:     case LT: return (11);
                   2223:     case GEU: return (2);
                   2224:     case GTU: return (8);
                   2225:     case LEU: return (9);
                   2226:     case LTU: return (3);
                   2227:     default: abort ();
                   2228:     }
                   2229:   /*NOTREACHED*/
                   2230:   return (42);
                   2231: } /* get_arm_condition_code */
                   2232: 
                   2233: 
                   2234: void
                   2235: final_prescan_insn (insn, opvec, noperands)
                   2236:      rtx insn;
                   2237:      rtx *opvec;
                   2238:      int noperands;
                   2239: {
                   2240:   /* BODY will hold the body of INSN.  */
                   2241:   register rtx body = PATTERN (insn);
                   2242: 
                   2243:   /* This will be 1 if trying to repeat the trick, and things need to be
                   2244:      reversed if it appears to fail.  */
                   2245:   int reverse = 0;
                   2246: 
                   2247:   /* JUMP_CLOBBERS will be one implies that the conditions if a branch is
                   2248:      taken are clobbered, even if the rtl suggests otherwise.  It also
                   2249:      means that we have to grub around within the jump expression to find
                   2250:      out what the conditions are when the jump isn't taken.  */
                   2251:   int jump_clobbers = 0;
                   2252:   
                   2253:   /* If we start with a return insn, we only succeed if we find another one. */
                   2254:   int seeking_return = 0;
                   2255:   
                   2256:   /* START_INSN will hold the insn from where we start looking.  This is the
                   2257:      first insn after the following code_label if REVERSE is true.  */
                   2258:   rtx start_insn = insn;
                   2259: 
                   2260:   /* If in state 4, check if the target branch is reached, in order to
                   2261:      change back to state 0.  */
                   2262:   if (arm_ccfsm_state == 4)
                   2263:     {
                   2264:       if (insn == arm_target_insn)
                   2265:       {
                   2266:        arm_target_insn = NULL;
                   2267:        arm_ccfsm_state = 0;
                   2268:       }
                   2269:       return;
                   2270:     }
                   2271: 
                   2272:   /* If in state 3, it is possible to repeat the trick, if this insn is an
                   2273:      unconditional branch to a label, and immediately following this branch
                   2274:      is the previous target label which is only used once, and the label this
                   2275:      branch jumps to is not too far off.  */
                   2276:   if (arm_ccfsm_state == 3)
                   2277:     {
                   2278:       if (simplejump_p (insn))
                   2279:        {
                   2280:          start_insn = next_nonnote_insn (start_insn);
                   2281:          if (GET_CODE (start_insn) == BARRIER)
                   2282:            {
                   2283:              /* XXX Isn't this always a barrier?  */
                   2284:              start_insn = next_nonnote_insn (start_insn);
                   2285:            }
                   2286:          if (GET_CODE (start_insn) == CODE_LABEL
                   2287:              && CODE_LABEL_NUMBER (start_insn) == arm_target_label
                   2288:              && LABEL_NUSES (start_insn) == 1)
                   2289:            reverse = TRUE;
                   2290:          else
                   2291:            return;
                   2292:        }
                   2293:       else if (GET_CODE (body) == RETURN)
                   2294:         {
                   2295:          start_insn = next_nonnote_insn (start_insn);
                   2296:          if (GET_CODE (start_insn) == BARRIER)
                   2297:            start_insn = next_nonnote_insn (start_insn);
                   2298:          if (GET_CODE (start_insn) == CODE_LABEL
                   2299:              && CODE_LABEL_NUMBER (start_insn) == arm_target_label
                   2300:              && LABEL_NUSES (start_insn) == 1)
                   2301:            {
                   2302:              reverse = TRUE;
                   2303:              seeking_return = 1;
                   2304:            }
                   2305:          else
                   2306:            return;
                   2307:         }
                   2308:       else
                   2309:        return;
                   2310:     }
                   2311: 
                   2312:   if (arm_ccfsm_state != 0 && !reverse)
                   2313:     abort ();
                   2314:   if (GET_CODE (insn) != JUMP_INSN)
                   2315:     return;
                   2316: 
                   2317:   /* This jump might be paralled with a clobber of the condition codes 
                   2318:      the jump should always come first */
                   2319:   if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
                   2320:     body = XVECEXP (body, 0, 0);
                   2321: 
                   2322: #if 0  
                   2323:   /* If this is a conditional return then we don't want to know */
                   2324:   if (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
                   2325:       && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
                   2326:       && (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN
                   2327:           || GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN))
                   2328:     return;
                   2329: #endif
                   2330: 
                   2331:   if (reverse
                   2332:       || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
                   2333:          && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE))
                   2334:     {
                   2335:       int insns_skipped = 0, fail = FALSE, succeed = FALSE;
                   2336:       /* Flag which part of the IF_THEN_ELSE is the LABEL_REF.  */
                   2337:       int then_not_else = TRUE;
                   2338:       rtx this_insn = start_insn, label = 0;
                   2339: 
                   2340:       if (get_attr_conds (insn) == CONDS_JUMP_CLOB)
                   2341:        jump_clobbers = 1;
                   2342:       
                   2343:       /* Register the insn jumped to.  */
                   2344:       if (reverse)
                   2345:         {
                   2346:          if (!seeking_return)
                   2347:            label = XEXP (SET_SRC (body), 0);
                   2348:         }
                   2349:       else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF)
                   2350:        label = XEXP (XEXP (SET_SRC (body), 1), 0);
                   2351:       else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF)
                   2352:        {
                   2353:          label = XEXP (XEXP (SET_SRC (body), 2), 0);
                   2354:          then_not_else = FALSE;
                   2355:        }
                   2356:       else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN)
                   2357:        seeking_return = 1;
                   2358:       else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN)
                   2359:         {
                   2360:          seeking_return = 1;
                   2361:          then_not_else = FALSE;
                   2362:         }
                   2363:       else
                   2364:        abort ();
                   2365: 
                   2366:       /* See how many insns this branch skips, and what kind of insns.  If all
                   2367:         insns are okay, and the label or unconditional branch to the same
                   2368:         label is not too far away, succeed.  */
                   2369:       for (insns_skipped = 0;
                   2370:           !fail && !succeed && insns_skipped < MAX_INSNS_SKIPPED;
                   2371:           insns_skipped++)
                   2372:        {
                   2373:          rtx scanbody;
                   2374: 
                   2375:          this_insn = next_nonnote_insn (this_insn);
                   2376:          if (!this_insn)
                   2377:            break;
                   2378: 
                   2379:          scanbody = PATTERN (this_insn);
                   2380: 
                   2381:          switch (GET_CODE (this_insn))
                   2382:            {
                   2383:            case CODE_LABEL:
                   2384:              /* Succeed if it is the target label, otherwise fail since
                   2385:                 control falls in from somewhere else.  */
                   2386:              if (this_insn == label)
                   2387:                {
                   2388:                  if (jump_clobbers)
                   2389:                    {
                   2390:                      arm_ccfsm_state = 2;
                   2391:                      this_insn = next_nonnote_insn (this_insn);
                   2392:                    }
                   2393:                  else
                   2394:                    arm_ccfsm_state = 1;
                   2395:                  succeed = TRUE;
                   2396:                }
                   2397:              else
                   2398:                fail = TRUE;
                   2399:              break;
                   2400: 
                   2401:            case BARRIER:
                   2402:              /* Succeed if the following insn is the target label.
                   2403:                 Otherwise fail.  
                   2404:                 If return insns are used then the last insn in a function 
                   2405:                 will be a barrier. */
                   2406:              this_insn = next_nonnote_insn (this_insn);
                   2407:              if (this_insn && this_insn == label)
                   2408:                {
                   2409:                  if (jump_clobbers)
                   2410:                    {
                   2411:                      arm_ccfsm_state = 2;
                   2412:                      this_insn = next_nonnote_insn (this_insn);
                   2413:                    }
                   2414:                  else
                   2415:                    arm_ccfsm_state = 1;
                   2416:                  succeed = TRUE;
                   2417:                }
                   2418:              else
                   2419:                fail = TRUE;
                   2420:              break;
                   2421: 
                   2422:            case CALL_INSN:
                   2423:              /* The arm 6xx uses full 32 bit addresses so the cc is not 
                   2424:                 preserved over calls */
                   2425:              if (TARGET_6)
                   2426:                fail = TRUE;
                   2427:              break;
                   2428:            case JUMP_INSN:
                   2429:              /* If this is an unconditional branch to the same label, succeed.
                   2430:                 If it is to another label, do nothing.  If it is conditional,
                   2431:                 fail.  */
                   2432:              /* XXX Probably, the test for the SET and the PC are unnecessary. */
                   2433: 
                   2434:              if (GET_CODE (scanbody) == SET
                   2435:                  && GET_CODE (SET_DEST (scanbody)) == PC)
                   2436:                {
                   2437:                  if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF
                   2438:                      && XEXP (SET_SRC (scanbody), 0) == label && !reverse)
                   2439:                    {
                   2440:                      arm_ccfsm_state = 2;
                   2441:                      succeed = TRUE;
                   2442:                    }
                   2443:                  else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE)
                   2444:                    fail = TRUE;
                   2445:                }
                   2446:              else if (GET_CODE (scanbody) == RETURN
                   2447:                       && seeking_return)
                   2448:                {
                   2449:                  arm_ccfsm_state = 2;
                   2450:                  succeed = TRUE;
                   2451:                }
                   2452:              else if (GET_CODE (scanbody) == PARALLEL)
                   2453:                {
                   2454:                  switch (get_attr_conds (this_insn))
                   2455:                    {
                   2456:                    case CONDS_NOCOND:
                   2457:                      break;
                   2458:                    default:
                   2459:                      fail = TRUE;
                   2460:                      break;
                   2461:                    }
                   2462:                }
                   2463:              break;
                   2464: 
                   2465:            case INSN:
                   2466:              /* Instructions using or affecting the condition codes make it
                   2467:                 fail.  */
                   2468:              if ((GET_CODE (scanbody) == SET
                   2469:                   || GET_CODE (scanbody) == PARALLEL)
                   2470:                  && get_attr_conds (this_insn) != CONDS_NOCOND)
                   2471:                fail = TRUE;
                   2472:              break;
                   2473: 
                   2474:            default:
                   2475:              break;
                   2476:            }
                   2477:        }
                   2478:       if (succeed)
                   2479:        {
                   2480:          if ((!seeking_return) && (arm_ccfsm_state == 1 || reverse))
                   2481:            arm_target_label = CODE_LABEL_NUMBER (label);
                   2482:          else if (seeking_return || arm_ccfsm_state == 2)
                   2483:            {
                   2484:              while (this_insn && GET_CODE (PATTERN (this_insn)) == USE)
                   2485:                {
                   2486:                  this_insn = next_nonnote_insn (this_insn);
                   2487:                  if (this_insn && (GET_CODE (this_insn) == BARRIER
                   2488:                                    || GET_CODE (this_insn) == CODE_LABEL))
                   2489:                    abort ();
                   2490:                }
                   2491:              if (!this_insn)
                   2492:                {
                   2493:                  /* Oh, dear! we ran off the end.. give up */
                   2494:                  recog (PATTERN (insn), insn, NULL_PTR);
                   2495:                  arm_ccfsm_state = 0;
                   2496:                  arm_target_insn = NULL;
                   2497:                  return;
                   2498:                }
                   2499:              arm_target_insn = this_insn;
                   2500:            }
                   2501:          else
                   2502:            abort ();
                   2503:          if (jump_clobbers)
                   2504:            {
                   2505:              if (reverse)
                   2506:                abort ();
                   2507:              arm_current_cc = 
                   2508:                  get_arm_condition_code (XEXP (XEXP (XEXP (SET_SRC (body),
                   2509:                                                            0), 0), 1));
                   2510:              if (GET_CODE (XEXP (XEXP (SET_SRC (body), 0), 0)) == AND)
                   2511:                arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
                   2512:              if (GET_CODE (XEXP (SET_SRC (body), 0)) == NE)
                   2513:                arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
                   2514:            }
                   2515:          else
                   2516:            {
                   2517:              /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from
                   2518:                 what it was.  */
                   2519:              if (!reverse)
                   2520:                arm_current_cc = get_arm_condition_code (XEXP (SET_SRC (body),
                   2521:                                                               0));
                   2522:            }
                   2523: 
                   2524:          if (reverse || then_not_else)
                   2525:            arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
                   2526:        }
                   2527:       /* restore recog_operand (getting the attributes of other insns can
                   2528:         destroy this array, but final.c assumes that it remains intact
                   2529:         accross this call; since the insn has been recognized already we
                   2530:         call recog direct). */
                   2531:       recog (PATTERN (insn), insn, NULL_PTR);
                   2532:     }
                   2533: } /* final_prescan_insn */
                   2534: 
                   2535: /* EOF */

unix.superglobalmegacorp.com

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