Annotation of gcc/config/arm/arm.c, revision 1.1.1.4

1.1       root        1: /* Output routines for GCC for ARM/RISCiX.
1.1.1.4 ! root        2:    Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
1.1       root        3:    Contributed by Pieter `Tiggr' Schoenmakers ([email protected])
                      4:              and Martin Simmons (@harleqn.co.uk).
1.1.1.2   root        5:    More major hacks by Richard Earnshaw ([email protected])
1.1       root        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
1.1.1.4 ! root       21: the Free Software Foundation, 59 Temple Place - Suite 330,
        !            22: Boston, MA 02111-1307, USA.  */
1.1.1.2   root       23:     
1.1       root       24: #include <stdio.h>
1.1.1.3   root       25: #include <string.h>
1.1       root       26: #include "assert.h"
                     27: #include "config.h"
                     28: #include "rtl.h"
                     29: #include "regs.h"
                     30: #include "hard-reg-set.h"
                     31: #include "real.h"
                     32: #include "insn-config.h"
                     33: #include "conditions.h"
                     34: #include "insn-flags.h"
                     35: #include "output.h"
                     36: #include "insn-attr.h"
                     37: #include "flags.h"
1.1.1.2   root       38: #include "reload.h"
1.1.1.3   root       39: #include "tree.h"
                     40: #include "expr.h"
1.1       root       41: 
                     42: /* The maximum number of insns skipped which will be conditionalised if
                     43:    possible.  */
                     44: #define MAX_INSNS_SKIPPED  5
                     45: 
                     46: /* Some function declarations.  */
                     47: extern FILE *asm_out_file;
                     48: extern char *output_multi_immediate ();
                     49: extern void arm_increase_location ();
                     50: 
1.1.1.3   root       51: HOST_WIDE_INT int_log2 PROTO ((HOST_WIDE_INT));
                     52: static int get_prologue_size PROTO ((void));
                     53: 
1.1.1.2   root       54: /*  Define the information needed to generate branch insns.  This is
                     55:    stored from the compare operation. */
                     56: 
                     57: rtx arm_compare_op0, arm_compare_op1;
                     58: int arm_compare_fp;
                     59: 
                     60: /* What type of cpu are we compiling for? */
                     61: enum processor_type arm_cpu;
                     62: 
1.1.1.4 ! root       63: /* What type of floating point are we compiling for? */
1.1.1.3   root       64: enum floating_point_type arm_fpu;
                     65: 
1.1       root       66: /* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we
                     67:    must report the mode of the memory reference from PRINT_OPERAND to
                     68:    PRINT_OPERAND_ADDRESS.  */
1.1.1.3   root       69: enum machine_mode output_memory_reference_mode;
1.1       root       70: 
                     71: /* Nonzero if the prologue must setup `fp'.  */
                     72: int current_function_anonymous_args;
                     73: 
                     74: /* Location counter of .text segment.  */
                     75: int arm_text_location = 0;
                     76: 
1.1.1.2   root       77: /* Set to one if we think that lr is only saved because of subroutine calls,
                     78:    but all of these can be `put after' return insns */
                     79: int lr_save_eliminated;
                     80: 
1.1       root       81: /* A hash table is used to store text segment labels and their associated
                     82:    offset from the start of the text segment.  */
                     83: struct label_offset
                     84: {
                     85:   char *name;
                     86:   int offset;
                     87:   struct label_offset *cdr;
                     88: };
                     89: 
                     90: #define LABEL_HASH_SIZE  257
                     91: 
                     92: static struct label_offset *offset_table[LABEL_HASH_SIZE];
                     93: 
1.1.1.2   root       94: /* Set to 1 when a return insn is output, this means that the epilogue
                     95:    is not needed. */
                     96: 
                     97: static int return_used_this_function;
                     98: 
1.1       root       99: /* For an explanation of these variables, see final_prescan_insn below.  */
                    100: int arm_ccfsm_state;
                    101: int arm_current_cc;
                    102: rtx arm_target_insn;
                    103: int arm_target_label;
1.1.1.3   root      104: 
                    105: /* The condition codes of the ARM, and the inverse function.  */
                    106: char *arm_condition_codes[] =
                    107: {
                    108:   "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
                    109:   "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
                    110: };
                    111: 
                    112: #define ARM_INVERSE_CONDITION_CODE(X)  ((X) ^ 1)
1.1       root      113: 
1.1.1.2   root      114: /* Return 1 if it is possible to return using a single instruction */
                    115: 
                    116: int
                    117: use_return_insn ()
                    118: {
                    119:   int regno;
                    120: 
                    121:   if (!reload_completed ||current_function_pretend_args_size
                    122:       || current_function_anonymous_args
                    123:       || (get_frame_size () && !(TARGET_APCS || frame_pointer_needed)))
                    124:     return 0;
                    125: 
                    126:   /* Can't be done if any of the FPU regs are pushed, since this also
                    127:      requires an insn */
                    128:   for (regno = 20; regno < 24; regno++)
                    129:     if (regs_ever_live[regno])
                    130:       return 0;
                    131: 
                    132:   return 1;
                    133: }
                    134: 
1.1       root      135: /* Return TRUE if int I is a valid immediate ARM constant.  */
                    136: 
                    137: int
                    138: const_ok_for_arm (i)
1.1.1.2   root      139:      HOST_WIDE_INT i;
1.1       root      140: {
1.1.1.2   root      141:   unsigned HOST_WIDE_INT mask = ~0xFF;
1.1       root      142: 
1.1.1.3   root      143:   /* Fast return for 0 and powers of 2 */
                    144:   if ((i & (i - 1)) == 0)
                    145:     return TRUE;
                    146: 
1.1       root      147:   do
                    148:     {
1.1.1.2   root      149:       if ((i & mask & (unsigned HOST_WIDE_INT) 0xffffffff) == 0)
1.1.1.3   root      150:         return TRUE;
1.1.1.2   root      151:       mask =
                    152:          (mask << 2) | ((mask & (unsigned HOST_WIDE_INT) 0xffffffff)
                    153:                         >> (32 - 2)) | ~((unsigned HOST_WIDE_INT) 0xffffffff);
1.1       root      154:     } while (mask != ~0xFF);
                    155: 
1.1.1.3   root      156:   return FALSE;
                    157: }
                    158: 
                    159: /* Return true if I is a valid constant for the operation CODE. */
                    160: int
                    161: const_ok_for_op (i, code, mode)
                    162:      HOST_WIDE_INT i;
                    163:      enum rtx_code code;
                    164:      enum machine_mode mode;
                    165: {
                    166:   if (const_ok_for_arm (i))
                    167:     return 1;
                    168: 
                    169:   switch (code)
                    170:     {
                    171:     case PLUS:
                    172:       return const_ok_for_arm (ARM_SIGN_EXTEND (-i));
                    173: 
                    174:     case MINUS:                /* Should only occur with (MINUS I reg) => rsb */
                    175:     case XOR:
                    176:     case IOR:
                    177:       return 0;
                    178: 
                    179:     case AND:
                    180:       return const_ok_for_arm (ARM_SIGN_EXTEND (~i));
                    181: 
                    182:     default:
                    183:       abort ();
                    184:     }
                    185: }
                    186: 
                    187: /* Emit a sequence of insns to handle a large constant.
                    188:    CODE is the code of the operation required, it can be any of SET, PLUS,
                    189:    IOR, AND, XOR, MINUS;
                    190:    MODE is the mode in which the operation is being performed;
                    191:    VAL is the integer to operate on;
                    192:    SOURCE is the other operand (a register, or a null-pointer for SET);
                    193:    SUBTARGETS means it is safe to create scratch registers if that will
                    194:    either produce a simpler sequence, or we will want to cse the values. */
                    195: 
                    196: int
                    197: arm_split_constant (code, mode, val, target, source, subtargets)
                    198:      enum rtx_code code;
                    199:      enum machine_mode mode;
                    200:      HOST_WIDE_INT val;
                    201:      rtx target;
                    202:      rtx source;
                    203:      int subtargets;
                    204: {
                    205:   int can_add = 0;
                    206:   int can_invert = 0;
                    207:   int can_negate = 0;
                    208:   int can_negate_initial = 0;
                    209:   int can_shift = 0;
                    210:   int i;
                    211:   int num_bits_set = 0;
                    212:   int set_sign_bit_copies = 0;
                    213:   int clear_sign_bit_copies = 0;
                    214:   int clear_zero_bit_copies = 0;
                    215:   int set_zero_bit_copies = 0;
                    216:   int insns = 0;
                    217:   rtx new_src;
                    218:   unsigned HOST_WIDE_INT temp1, temp2;
                    219:   unsigned HOST_WIDE_INT remainder = val & 0xffffffff;
                    220: 
                    221:   /* find out which operations are safe for a given CODE.  Also do a quick
                    222:      check for degenerate cases; these can occur when DImode operations
                    223:      are split.  */
                    224:   switch (code)
                    225:     {
                    226:     case SET:
                    227:       can_invert = 1;
                    228:       can_shift = 1;
                    229:       can_negate = 1;
                    230:       break;
                    231: 
                    232:     case PLUS:
                    233:       can_negate = 1;
                    234:       can_negate_initial = 1;
                    235:       break;
                    236: 
                    237:     case IOR:
                    238:       if (remainder == 0xffffffff)
                    239:        {
                    240:          emit_insn (gen_rtx (SET, VOIDmode, target,
                    241:                              GEN_INT (ARM_SIGN_EXTEND (val))));
                    242:          return 1;
                    243:        }
                    244:       if (remainder == 0)
                    245:        {
                    246:          if (reload_completed && rtx_equal_p (target, source))
                    247:            return 0;
                    248:          emit_insn (gen_rtx (SET, VOIDmode, target, source));
                    249:          return 1;
                    250:        }
                    251:       break;
                    252: 
                    253:     case AND:
                    254:       if (remainder == 0)
                    255:        {
                    256:          emit_insn (gen_rtx (SET, VOIDmode, target, const0_rtx));
                    257:          return 1;
                    258:        }
                    259:       if (remainder == 0xffffffff)
                    260:        {
                    261:          if (reload_completed && rtx_equal_p (target, source))
                    262:            return 0;
                    263:          emit_insn (gen_rtx (SET, VOIDmode, target, source));
                    264:          return 1;
                    265:        }
                    266:       can_invert = 1;
                    267:       break;
                    268: 
                    269:     case XOR:
                    270:       if (remainder == 0)
                    271:        {
                    272:          if (reload_completed && rtx_equal_p (target, source))
                    273:            return 0;
                    274:          emit_insn (gen_rtx (SET, VOIDmode, target, source));
                    275:          return 1;
                    276:        }
                    277:       if (remainder == 0xffffffff)
                    278:        {
                    279:          emit_insn (gen_rtx (SET, VOIDmode, target,
                    280:                              gen_rtx (NOT, mode, source)));
                    281:          return 1;
                    282:        }
                    283: 
                    284:       /* We don't know how to handle this yet below.  */
                    285:       abort ();
                    286: 
                    287:     case MINUS:
                    288:       /* We treat MINUS as (val - source), since (source - val) is always
                    289:         passed as (source + (-val)).  */
                    290:       if (remainder == 0)
                    291:        {
                    292:          emit_insn (gen_rtx (SET, VOIDmode, target,
                    293:                              gen_rtx (NEG, mode, source)));
                    294:          return 1;
                    295:        }
                    296:       if (const_ok_for_arm (val))
                    297:        {
                    298:          emit_insn (gen_rtx (SET, VOIDmode, target, 
                    299:                              gen_rtx (MINUS, mode, GEN_INT (val), source)));
                    300:          return 1;
                    301:        }
                    302:       can_negate = 1;
                    303: 
                    304:       break;
                    305: 
                    306:     default:
                    307:       abort ();
                    308:     }
                    309: 
                    310:   /* If we can do it in one insn get out quickly */
                    311:   if (const_ok_for_arm (val)
                    312:       || (can_negate_initial && const_ok_for_arm (-val))
                    313:       || (can_invert && const_ok_for_arm (~val)))
                    314:     {
                    315:       emit_insn (gen_rtx (SET, VOIDmode, target,
                    316:                          (source ? gen_rtx (code, mode, source,
                    317:                                             GEN_INT (val)) : GEN_INT (val))));
                    318:       return 1;
                    319:     }
                    320: 
                    321: 
                    322:   /* Calculate a few attributes that may be useful for specific
                    323:      optimizations. */
                    324: 
                    325:   for (i = 31; i >= 0; i--)
                    326:     {
                    327:       if ((remainder & (1 << i)) == 0)
                    328:        clear_sign_bit_copies++;
                    329:       else
                    330:        break;
                    331:     }
                    332: 
                    333:   for (i = 31; i >= 0; i--)
                    334:     {
                    335:       if ((remainder & (1 << i)) != 0)
                    336:        set_sign_bit_copies++;
                    337:       else
                    338:        break;
                    339:     }
                    340: 
                    341:   for (i = 0; i <= 31; i++)
                    342:     {
                    343:       if ((remainder & (1 << i)) == 0)
                    344:        clear_zero_bit_copies++;
                    345:       else
                    346:        break;
                    347:     }
                    348: 
                    349:   for (i = 0; i <= 31; i++)
                    350:     {
                    351:       if ((remainder & (1 << i)) != 0)
                    352:        set_zero_bit_copies++;
                    353:       else
                    354:        break;
                    355:     }
                    356: 
                    357:   switch (code)
                    358:     {
                    359:     case SET:
                    360:       /* See if we can do this by sign_extending a constant that is known
                    361:         to be negative.  This is a good, way of doing it, since the shift
                    362:         may well merge into a subsequent insn.  */
                    363:       if (set_sign_bit_copies > 1)
                    364:        {
                    365:          if (const_ok_for_arm
                    366:              (temp1 = ARM_SIGN_EXTEND (remainder 
                    367:                                        << (set_sign_bit_copies - 1))))
                    368:            {
                    369:              new_src = subtargets ? gen_reg_rtx (mode) : target;
                    370:              emit_insn (gen_rtx (SET, VOIDmode, new_src, GEN_INT (temp1)));
                    371:              emit_insn (gen_ashrsi3 (target, new_src, 
                    372:                                      GEN_INT (set_sign_bit_copies - 1)));
                    373:              return 2;
                    374:            }
                    375:          /* For an inverted constant, we will need to set the low bits,
                    376:             these will be shifted out of harm's way.  */
                    377:          temp1 |= (1 << (set_sign_bit_copies - 1)) - 1;
                    378:          if (const_ok_for_arm (~temp1))
                    379:            {
                    380:              new_src = subtargets ? gen_reg_rtx (mode) : target;
                    381:              emit_insn (gen_rtx (SET, VOIDmode, new_src, GEN_INT (temp1)));
                    382:              emit_insn (gen_ashrsi3 (target, new_src, 
                    383:                                      GEN_INT (set_sign_bit_copies - 1)));
                    384:              return 2;
                    385:            }
                    386:        }
                    387: 
                    388:       /* See if we can generate this by setting the bottom (or the top)
                    389:         16 bits, and then shifting these into the other half of the
                    390:         word.  We only look for the simplest cases, to do more would cost
                    391:         too much.  Be careful, however, not to generate this when the
                    392:         alternative would take fewer insns.  */
                    393:       if (val & 0xffff0000)
                    394:        {
                    395:          temp1 = remainder & 0xffff0000;
                    396:          temp2 = remainder & 0x0000ffff;
                    397: 
                    398:          /* Overlaps outside this range are best done using other methods. */
                    399:          for (i = 9; i < 24; i++)
                    400:            {
                    401:              if ((((temp2 | (temp2 << i)) & 0xffffffff) == remainder)
                    402:                  && ! const_ok_for_arm (temp2))
                    403:                {
                    404:                  insns
                    405:                    = arm_split_constant (code, mode, temp2,
                    406:                                          (new_src
                    407:                                           = subtargets ? gen_reg_rtx (mode)
                    408:                                           : target),
                    409:                                          source, subtargets);
                    410:                  source = new_src;
                    411:                  emit_insn (gen_rtx (SET, VOIDmode, target,
                    412:                                      gen_rtx (IOR, mode,
                    413:                                               gen_rtx (ASHIFT, mode, source,
                    414:                                                        GEN_INT (i)),
                    415:                                               source)));
                    416:                  return insns + 1;
                    417:                }
                    418:            }
                    419: 
                    420:          /* Don't duplicate cases already considered. */
                    421:          for (i = 17; i < 24; i++)
                    422:            {
                    423:              if (((temp1 | (temp1 >> i)) == remainder)
                    424:                  && ! const_ok_for_arm (temp1))
                    425:                {
                    426:                  insns
                    427:                    = arm_split_constant (code, mode, temp1,
                    428:                                          (new_src
                    429:                                           = subtargets ? gen_reg_rtx (mode)
                    430:                                           : target),
                    431:                                          source, subtargets);
                    432:                  source = new_src;
                    433:                  emit_insn (gen_rtx (SET, VOIDmode, target,
                    434:                                      gen_rtx (IOR, mode,
                    435:                                               gen_rtx (LSHIFTRT, mode, source,
                    436:                                                        GEN_INT (i)),
                    437:                                               source)));
                    438:                  return insns + 1;
                    439:                }
                    440:            }
                    441:        }
                    442:       break;
                    443: 
                    444:     case IOR:
                    445:     case XOR:
                    446:       /* If we have IOR or XOR, and the inverse of the constant can be loaded
                    447:         in a single instruction, and we can find a temporary to put it in,
                    448:         then this can be done in two instructions instead of 3-4.  */
                    449:       if (subtargets
                    450:          || (reload_completed && ! reg_mentioned_p (target, source)))
                    451:        {
                    452:          if (const_ok_for_arm (ARM_SIGN_EXTEND (~ val)))
                    453:            {
                    454:              rtx sub = subtargets ? gen_reg_rtx (mode) : target;
                    455: 
                    456:              emit_insn (gen_rtx (SET, VOIDmode, sub,
                    457:                                  GEN_INT (ARM_SIGN_EXTEND (~ val))));
                    458:              emit_insn (gen_rtx (SET, VOIDmode, target, 
                    459:                                  gen_rtx (code, mode, source, sub)));
                    460:              return 2;
                    461:            }
                    462:        }
                    463: 
                    464:       if (code == XOR)
                    465:        break;
                    466: 
                    467:       if (set_sign_bit_copies > 8
                    468:          && (val & (-1 << (32 - set_sign_bit_copies))) == val)
                    469:        {
                    470:          rtx sub = subtargets ? gen_reg_rtx (mode) : target;
                    471:          rtx shift = GEN_INT (set_sign_bit_copies);
                    472: 
                    473:          emit_insn (gen_rtx (SET, VOIDmode, sub,
                    474:                              gen_rtx (NOT, mode, 
                    475:                                       gen_rtx (ASHIFT, mode, source, 
                    476:                                                shift))));
                    477:          emit_insn (gen_rtx (SET, VOIDmode, target,
                    478:                              gen_rtx (NOT, mode,
                    479:                                       gen_rtx (LSHIFTRT, mode, sub,
                    480:                                                shift))));
                    481:          return 2;
                    482:        }
                    483: 
                    484:       if (set_zero_bit_copies > 8
                    485:          && (remainder & ((1 << set_zero_bit_copies) - 1)) == remainder)
                    486:        {
                    487:          rtx sub = subtargets ? gen_reg_rtx (mode) : target;
                    488:          rtx shift = GEN_INT (set_zero_bit_copies);
                    489:          
                    490:          emit_insn (gen_rtx (SET, VOIDmode, sub,
                    491:                              gen_rtx (NOT, mode,
                    492:                                       gen_rtx (LSHIFTRT, mode, source,
                    493:                                                shift))));
                    494:          emit_insn (gen_rtx (SET, VOIDmode, target,
                    495:                              gen_rtx (NOT, mode,
                    496:                                       gen_rtx (ASHIFT, mode, sub,
                    497:                                                shift))));
                    498:          return 2;
                    499:        }
                    500: 
                    501:       if (const_ok_for_arm (temp1 = ARM_SIGN_EXTEND (~ val)))
                    502:        {
                    503:          rtx sub = subtargets ? gen_reg_rtx (mode) : target;
                    504:          emit_insn (gen_rtx (SET, VOIDmode, sub,
                    505:                              gen_rtx (NOT, mode, source)));
                    506:          source = sub;
                    507:          if (subtargets)
                    508:            sub = gen_reg_rtx (mode);
                    509:          emit_insn (gen_rtx (SET, VOIDmode, sub,
                    510:                              gen_rtx (AND, mode, source, GEN_INT (temp1))));
                    511:          emit_insn (gen_rtx (SET, VOIDmode, target,
                    512:                              gen_rtx (NOT, mode, sub)));
                    513:          return 3;
                    514:        }
                    515:       break;
                    516: 
                    517:     case AND:
                    518:       /* See if two shifts will do 2 or more insn's worth of work.  */
                    519:       if (clear_sign_bit_copies >= 16 && clear_sign_bit_copies < 24)
                    520:        {
                    521:          HOST_WIDE_INT shift_mask = ((0xffffffff 
                    522:                                       << (32 - clear_sign_bit_copies))
                    523:                                      & 0xffffffff);
                    524:          rtx new_source;
                    525:          rtx shift = GEN_INT (clear_sign_bit_copies);
                    526: 
                    527:          if ((remainder | shift_mask) != 0xffffffff)
                    528:            {
                    529:              new_source = subtargets ? gen_reg_rtx (mode) : target;
                    530:              insns = arm_split_constant (AND, mode, remainder | shift_mask,
                    531:                                          new_source, source, subtargets);
                    532:              source = new_source;
                    533:            }
                    534: 
                    535:          new_source = subtargets ? gen_reg_rtx (mode) : target;
                    536:          emit_insn (gen_ashlsi3 (new_source, source, shift));
                    537:          emit_insn (gen_lshrsi3 (target, new_source, shift));
                    538:          return insns + 2;
                    539:        }
                    540: 
                    541:       if (clear_zero_bit_copies >= 16 && clear_zero_bit_copies < 24)
                    542:        {
                    543:          HOST_WIDE_INT shift_mask = (1 << clear_zero_bit_copies) - 1;
                    544:          rtx new_source;
                    545:          rtx shift = GEN_INT (clear_zero_bit_copies);
                    546:          
                    547:          if ((remainder | shift_mask) != 0xffffffff)
                    548:            {
                    549:              new_source = subtargets ? gen_reg_rtx (mode) : target;
                    550:              insns = arm_split_constant (AND, mode, remainder | shift_mask,
                    551:                                          new_source, source, subtargets);
                    552:              source = new_source;
                    553:            }
                    554: 
                    555:          new_source = subtargets ? gen_reg_rtx (mode) : target;
                    556:          emit_insn (gen_lshrsi3 (new_source, source, shift));
                    557:          emit_insn (gen_ashlsi3 (target, new_source, shift));
                    558:          return insns + 2;
                    559:        }
                    560: 
                    561:       break;
                    562: 
                    563:     default:
                    564:       break;
                    565:     }
                    566: 
                    567:   for (i = 0; i < 32; i++)
                    568:     if (remainder & (1 << i))
                    569:       num_bits_set++;
                    570: 
                    571:   if (code == AND || (can_invert && num_bits_set > 16))
                    572:     remainder = (~remainder) & 0xffffffff;
                    573:   else if (code == PLUS && num_bits_set > 16)
                    574:     remainder = (-remainder) & 0xffffffff;
                    575:   else
                    576:     {
                    577:       can_invert = 0;
                    578:       can_negate = 0;
                    579:     }
                    580: 
                    581:   /* Now try and find a way of doing the job in either two or three
                    582:      instructions.
                    583:      We start by looking for the largest block of zeros that are aligned on
                    584:      a 2-bit boundary, we then fill up the temps, wrapping around to the
                    585:      top of the word when we drop off the bottom.
                    586:      In the worst case this code should produce no more than four insns. */
                    587:   {
                    588:     int best_start = 0;
                    589:     int best_consecutive_zeros = 0;
                    590: 
                    591:     for (i = 0; i < 32; i += 2)
                    592:       {
                    593:        int consecutive_zeros = 0;
                    594: 
                    595:        if (! (remainder & (3 << i)))
                    596:          {
                    597:            while ((i < 32) && ! (remainder & (3 << i)))
                    598:              {
                    599:                consecutive_zeros += 2;
                    600:                i += 2;
                    601:              }
                    602:            if (consecutive_zeros > best_consecutive_zeros)
                    603:              {
                    604:                best_consecutive_zeros = consecutive_zeros;
                    605:                best_start = i - consecutive_zeros;
                    606:              }
                    607:            i -= 2;
                    608:          }
                    609:       }
                    610: 
                    611:     /* Now start emitting the insns, starting with the one with the highest
                    612:        bit set: we do this so that the smallest number will be emitted last;
                    613:        this is more likely to be combinable with addressing insns. */
                    614:     i = best_start;
                    615:     do
                    616:       {
                    617:        int end;
                    618: 
                    619:        if (i <= 0)
                    620:          i += 32;
                    621:        if (remainder & (3 << (i - 2)))
                    622:          {
                    623:            end = i - 8;
                    624:            if (end < 0)
                    625:              end += 32;
                    626:            temp1 = remainder & ((0x0ff << end)
                    627:                                 | ((i < end) ? (0xff >> (32 - end)) : 0));
                    628:            remainder &= ~temp1;
                    629: 
                    630:            if (code == SET)
                    631:              {
                    632:                emit_insn (gen_rtx (SET, VOIDmode,
                    633:                                    new_src = (subtargets ? gen_reg_rtx (mode)
                    634:                                               : target),
                    635:                                    GEN_INT (can_invert ? ~temp1 : temp1)));
                    636:                can_invert = 0;
                    637:                code = PLUS;
                    638:              }
                    639:            else if (code == MINUS)
                    640:              {
                    641:                emit_insn (gen_rtx (SET, VOIDmode,
                    642:                                    new_src = (subtargets ? gen_reg_rtx (mode)
                    643:                                               : target),
                    644:                                    gen_rtx (code, mode, GEN_INT (temp1),
                    645:                                             source)));
                    646:                code = PLUS;
                    647:              }
                    648:            else
                    649:              {
                    650:                emit_insn (gen_rtx (SET, VOIDmode,
                    651:                                    new_src = remainder ? (subtargets
                    652:                                                           ? gen_reg_rtx (mode)
                    653:                                                           : target) : target,
                    654:                                    gen_rtx (code, mode, source,
                    655:                                             GEN_INT (can_invert ? ~temp1
                    656:                                                      : (can_negate
                    657:                                                         ? -temp1 : temp1)))));
                    658:              }
                    659: 
                    660:            insns++;
                    661:            source = new_src;
                    662:            i -= 6;
                    663:          }
                    664:        i -= 2;
                    665:       } while (remainder);
                    666:   }
                    667:   return insns;
                    668: }
                    669: 
                    670: #define REG_OR_SUBREG_REG(X)                                           \
                    671:   (GET_CODE (X) == REG                                                 \
                    672:    || (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG))
                    673: 
                    674: #define REG_OR_SUBREG_RTX(X)                   \
                    675:    (GET_CODE (X) == REG ? (X) : SUBREG_REG (X))
                    676: 
                    677: #define ARM_FRAME_RTX(X)                               \
                    678:   ((X) == frame_pointer_rtx || (X) == stack_pointer_rtx        \
                    679:    || (X) == arg_pointer_rtx)
                    680: 
                    681: int
                    682: arm_rtx_costs (x, code, outer_code)
                    683:      rtx x;
                    684:      enum rtx_code code, outer_code;
                    685: {
                    686:   enum machine_mode mode = GET_MODE (x);
                    687:   enum rtx_code subcode;
                    688:   int extra_cost;
                    689: 
                    690:   switch (code)
                    691:     {
                    692:     case MEM:
                    693:       /* Memory costs quite a lot for the first word, but subsequent words
                    694:         load at the equivalent of a single insn each.  */
                    695:       return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
                    696:              + (CONSTANT_POOL_ADDRESS_P (x) ? 4 : 0));
                    697: 
                    698:     case DIV:
                    699:     case MOD:
                    700:       return 100;
                    701: 
                    702:     case ROTATE:
                    703:       if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG)
                    704:        return 4;
                    705:       /* Fall through */
                    706:     case ROTATERT:
                    707:       if (mode != SImode)
                    708:        return 8;
                    709:       /* Fall through */
                    710:     case ASHIFT: case LSHIFTRT: case ASHIFTRT:
                    711:       if (mode == DImode)
                    712:        return (8 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : 8)
                    713:                + ((GET_CODE (XEXP (x, 0)) == REG 
                    714:                    || (GET_CODE (XEXP (x, 0)) == SUBREG
                    715:                        && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
                    716:                   ? 0 : 8));
                    717:       return (1 + ((GET_CODE (XEXP (x, 0)) == REG
                    718:                    || (GET_CODE (XEXP (x, 0)) == SUBREG
                    719:                        && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
                    720:                   ? 0 : 4)
                    721:              + ((GET_CODE (XEXP (x, 1)) == REG
                    722:                  || (GET_CODE (XEXP (x, 1)) == SUBREG
                    723:                      && GET_CODE (SUBREG_REG (XEXP (x, 1))) == REG)
                    724:                  || (GET_CODE (XEXP (x, 1)) == CONST_INT))
                    725:                 ? 0 : 4));
                    726: 
                    727:     case MINUS:
                    728:       if (mode == DImode)
                    729:        return (4 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 8)
                    730:                + ((REG_OR_SUBREG_REG (XEXP (x, 0))
                    731:                    || (GET_CODE (XEXP (x, 0)) == CONST_INT
                    732:                       && const_ok_for_arm (INTVAL (XEXP (x, 0)))))
                    733:                   ? 0 : 8));
                    734: 
                    735:       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
                    736:        return (2 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
                    737:                      || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
                    738:                          && const_double_rtx_ok_for_fpu (XEXP (x, 1))))
                    739:                     ? 0 : 8)
                    740:                + ((REG_OR_SUBREG_REG (XEXP (x, 0))
                    741:                    || (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE
                    742:                        && const_double_rtx_ok_for_fpu (XEXP (x, 0))))
                    743:                   ? 0 : 8));
                    744: 
                    745:       if (((GET_CODE (XEXP (x, 0)) == CONST_INT
                    746:            && const_ok_for_arm (INTVAL (XEXP (x, 0)))
                    747:            && REG_OR_SUBREG_REG (XEXP (x, 1))))
                    748:          || (((subcode = GET_CODE (XEXP (x, 1))) == ASHIFT
                    749:               || subcode == ASHIFTRT || subcode == LSHIFTRT
                    750:               || subcode == ROTATE || subcode == ROTATERT
                    751:               || (subcode == MULT
                    752:                   && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
                    753:                   && ((INTVAL (XEXP (XEXP (x, 1), 1)) &
                    754:                        (INTVAL (XEXP (XEXP (x, 1), 1)) - 1)) == 0)))
                    755:              && REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 0))
                    756:              && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 1))
                    757:                  || GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT)
                    758:              && REG_OR_SUBREG_REG (XEXP (x, 0))))
                    759:        return 1;
                    760:       /* Fall through */
                    761: 
                    762:     case PLUS: 
                    763:       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
                    764:        return (2 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
                    765:                + ((REG_OR_SUBREG_REG (XEXP (x, 1))
                    766:                    || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
                    767:                        && const_double_rtx_ok_for_fpu (XEXP (x, 1))))
                    768:                   ? 0 : 8));
                    769: 
                    770:       /* Fall through */
                    771:     case AND: case XOR: case IOR: 
                    772:       extra_cost = 0;
                    773: 
                    774:       /* Normally the frame registers will be spilt into reg+const during
                    775:         reload, so it is a bad idea to combine them with other instructions,
                    776:         since then they might not be moved outside of loops.  As a compromise
                    777:         we allow integration with ops that have a constant as their second
                    778:         operand.  */
                    779:       if ((REG_OR_SUBREG_REG (XEXP (x, 0))
                    780:           && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))
                    781:           && GET_CODE (XEXP (x, 1)) != CONST_INT)
                    782:          || (REG_OR_SUBREG_REG (XEXP (x, 0))
                    783:              && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))))
                    784:        extra_cost = 4;
                    785: 
                    786:       if (mode == DImode)
                    787:        return (4 + extra_cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
                    788:                + ((REG_OR_SUBREG_REG (XEXP (x, 1))
                    789:                    || (GET_CODE (XEXP (x, 1)) == CONST_INT
                    790:                        && const_ok_for_op (INTVAL (XEXP (x, 1)), code, mode)))
                    791:                   ? 0 : 8));
                    792: 
                    793:       if (REG_OR_SUBREG_REG (XEXP (x, 0)))
                    794:        return (1 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : extra_cost)
                    795:                + ((REG_OR_SUBREG_REG (XEXP (x, 1))
                    796:                    || (GET_CODE (XEXP (x, 1)) == CONST_INT
                    797:                        && const_ok_for_op (INTVAL (XEXP (x, 1)), code, mode)))
                    798:                   ? 0 : 4));
                    799: 
                    800:       else if (REG_OR_SUBREG_REG (XEXP (x, 1)))
                    801:        return (1 + extra_cost
                    802:                + ((((subcode = GET_CODE (XEXP (x, 0))) == ASHIFT
                    803:                     || subcode == LSHIFTRT || subcode == ASHIFTRT
                    804:                     || subcode == ROTATE || subcode == ROTATERT
                    805:                     || (subcode == MULT
                    806:                         && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
                    807:                         && ((INTVAL (XEXP (XEXP (x, 0), 1)) &
                    808:                              (INTVAL (XEXP (XEXP (x, 0), 1)) - 1)) == 0))
                    809:                    && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 0)))
                    810:                    && ((REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 1)))
                    811:                        || GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
                    812:                   ? 0 : 4));
                    813: 
                    814:       return 8;
                    815: 
                    816:     case MULT:
                    817:       if (GET_MODE_CLASS (mode) == MODE_FLOAT
                    818:          || mode == DImode)
                    819:        return 30;
                    820: 
                    821:       if (GET_CODE (XEXP (x, 1)) == CONST_INT)
                    822:        {
                    823:          HOST_WIDE_INT i = INTVAL (XEXP (x, 1)) & 0xffffffff;
                    824:          int add_cost = const_ok_for_arm (i) ? 4 : 8;
                    825:          int j;
                    826:          
                    827:          /* This will need adjusting for ARM's with fast multiplies */
                    828:          for (j = 0; i && j < 32; j += 2)
                    829:            {
                    830:              i &= ~(3 << j);
                    831:              add_cost += 2;
                    832:            }
                    833: 
                    834:          return add_cost;
                    835:        }
                    836: 
                    837:       return (30 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
                    838:              + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4));
                    839: 
                    840:     case NEG:
                    841:       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
                    842:        return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 6);
                    843:       /* Fall through */
                    844:     case NOT:
                    845:       if (mode == DImode)
                    846:        return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
                    847: 
                    848:       return 1 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
                    849: 
                    850:     case IF_THEN_ELSE:
                    851:       if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
                    852:        return 14;
                    853:       return 2;
                    854: 
                    855:     case COMPARE:
                    856:       return 1;
                    857: 
                    858:     case ABS:
                    859:       return 4 + (mode == DImode ? 4 : 0);
                    860: 
                    861:     case SIGN_EXTEND:
                    862:       if (GET_MODE (XEXP (x, 0)) == QImode)
                    863:        return (4 + (mode == DImode ? 4 : 0)
                    864:                + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
                    865:       /* Fall through */
                    866:     case ZERO_EXTEND:
                    867:       switch (GET_MODE (XEXP (x, 0)))
                    868:        {
                    869:        case QImode:
                    870:          return (1 + (mode == DImode ? 4 : 0)
                    871:                  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
                    872: 
                    873:        case HImode:
                    874:          return (4 + (mode == DImode ? 4 : 0)
                    875:                  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
                    876: 
                    877:        case SImode:
                    878:          return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
                    879:        }
                    880:       abort ();
1.1       root      881: 
1.1.1.3   root      882:     default:
                    883:       return 99;
                    884:     }
                    885: }
                    886:      
1.1.1.2   root      887: /* This code has been fixed for cross compilation. */
                    888: 
                    889: static int fpa_consts_inited = 0;
                    890: 
                    891: char *strings_fpa[8] = {
                    892:   "0.0",
                    893:   "1.0",
                    894:   "2.0",
                    895:   "3.0",
                    896:   "4.0",
                    897:   "5.0",
                    898:   "0.5",
                    899:   "10.0"
                    900:   };
                    901: 
                    902: static REAL_VALUE_TYPE values_fpa[8];
                    903: 
                    904: static void
                    905: init_fpa_table ()
                    906: {
                    907:   int i;
                    908:   REAL_VALUE_TYPE r;
                    909: 
                    910:   for (i = 0; i < 8; i++)
                    911:     {
                    912:       r = REAL_VALUE_ATOF (strings_fpa[i], DFmode);
                    913:       values_fpa[i] = r;
                    914:     }
1.1.1.3   root      915: 
1.1.1.2   root      916:   fpa_consts_inited = 1;
                    917: }
                    918: 
1.1       root      919: /* Return TRUE if rtx X is a valid immediate FPU constant. */
                    920: 
                    921: int
                    922: const_double_rtx_ok_for_fpu (x)
                    923:      rtx x;
                    924: {
1.1.1.2   root      925:   REAL_VALUE_TYPE r;
                    926:   int i;
                    927:   
                    928:   if (!fpa_consts_inited)
                    929:     init_fpa_table ();
                    930:   
                    931:   REAL_VALUE_FROM_CONST_DOUBLE (r, x);
                    932:   if (REAL_VALUE_MINUS_ZERO (r))
                    933:     return 0;
1.1.1.3   root      934: 
1.1.1.2   root      935:   for (i = 0; i < 8; i++)
                    936:     if (REAL_VALUES_EQUAL (r, values_fpa[i]))
                    937:       return 1;
1.1.1.3   root      938: 
1.1.1.2   root      939:   return 0;
1.1.1.3   root      940: }
1.1.1.2   root      941: 
                    942: /* Return TRUE if rtx X is a valid immediate FPU constant. */
                    943: 
                    944: int
                    945: neg_const_double_rtx_ok_for_fpu (x)
                    946:      rtx x;
                    947: {
                    948:   REAL_VALUE_TYPE r;
                    949:   int i;
                    950:   
                    951:   if (!fpa_consts_inited)
                    952:     init_fpa_table ();
                    953:   
                    954:   REAL_VALUE_FROM_CONST_DOUBLE (r, x);
                    955:   r = REAL_VALUE_NEGATE (r);
                    956:   if (REAL_VALUE_MINUS_ZERO (r))
                    957:     return 0;
1.1.1.3   root      958: 
1.1.1.2   root      959:   for (i = 0; i < 8; i++)
                    960:     if (REAL_VALUES_EQUAL (r, values_fpa[i]))
                    961:       return 1;
1.1.1.3   root      962: 
1.1.1.2   root      963:   return 0;
1.1.1.3   root      964: }
1.1       root      965: 
                    966: /* Predicates for `match_operand' and `match_operator'.  */
                    967: 
1.1.1.2   root      968: /* s_register_operand is the same as register_operand, but it doesn't accept
                    969:    (SUBREG (MEM)...). */
                    970: 
                    971: int
                    972: s_register_operand (op, mode)
                    973:      register rtx op;
                    974:      enum machine_mode mode;
                    975: {
                    976:   if (GET_MODE (op) != mode && mode != VOIDmode)
                    977:     return 0;
                    978: 
                    979:   if (GET_CODE (op) == SUBREG)
1.1.1.3   root      980:     op = SUBREG_REG (op);
                    981: 
                    982:   /* We don't consider registers whose class is NO_REGS
                    983:      to be a register operand.  */
                    984:   return (GET_CODE (op) == REG
                    985:          && (REGNO (op) >= FIRST_PSEUDO_REGISTER
                    986:              || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
                    987: }
                    988: 
                    989: /* Only accept reg, subreg(reg), const_int.  */
                    990: 
                    991: int
                    992: reg_or_int_operand (op, mode)
                    993:      register rtx op;
                    994:      enum machine_mode mode;
                    995: {
                    996:   if (GET_CODE (op) == CONST_INT)
                    997:     return 1;
                    998: 
                    999:   if (GET_MODE (op) != mode && mode != VOIDmode)
                   1000:     return 0;
                   1001: 
                   1002:   if (GET_CODE (op) == SUBREG)
                   1003:     op = SUBREG_REG (op);
1.1.1.2   root     1004: 
                   1005:   /* We don't consider registers whose class is NO_REGS
                   1006:      to be a register operand.  */
                   1007:   return (GET_CODE (op) == REG
                   1008:          && (REGNO (op) >= FIRST_PSEUDO_REGISTER
                   1009:              || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
                   1010: }
                   1011: 
                   1012: /* Return 1 if OP is an item in memory, given that we are in reload.  */
                   1013: 
                   1014: int
                   1015: reload_memory_operand (op, mode)
                   1016:      rtx op;
                   1017:      enum machine_mode mode;
                   1018: {
                   1019:   int regno = true_regnum (op);
                   1020: 
                   1021:   return (! CONSTANT_P (op)
                   1022:          && (regno == -1
                   1023:              || (GET_CODE (op) == REG
                   1024:                  && REGNO (op) >= FIRST_PSEUDO_REGISTER)));
                   1025: }
                   1026: 
1.1       root     1027: /* Return TRUE for valid operands for the rhs of an ARM instruction.  */
                   1028: 
                   1029: int
                   1030: arm_rhs_operand (op, mode)
                   1031:      rtx op;
                   1032:      enum machine_mode mode;
                   1033: {
1.1.1.2   root     1034:   return (s_register_operand (op, mode)
1.1       root     1035:          || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))));
1.1.1.3   root     1036: }
1.1       root     1037: 
1.1.1.2   root     1038: /* Return TRUE for valid operands for the rhs of an ARM instruction, or a load.
                   1039:  */
                   1040: 
                   1041: int
                   1042: arm_rhsm_operand (op, mode)
                   1043:      rtx op;
                   1044:      enum machine_mode mode;
                   1045: {
                   1046:   return (s_register_operand (op, mode)
                   1047:          || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op)))
                   1048:          || memory_operand (op, mode));
1.1.1.3   root     1049: }
1.1.1.2   root     1050: 
                   1051: /* Return TRUE for valid operands for the rhs of an ARM instruction, or if a
                   1052:    constant that is valid when negated.  */
                   1053: 
                   1054: int
                   1055: arm_add_operand (op, mode)
                   1056:      rtx op;
                   1057:      enum machine_mode mode;
                   1058: {
                   1059:   return (s_register_operand (op, mode)
                   1060:          || (GET_CODE (op) == CONST_INT
                   1061:              && (const_ok_for_arm (INTVAL (op))
                   1062:                  || const_ok_for_arm (-INTVAL (op)))));
1.1.1.3   root     1063: }
1.1.1.2   root     1064: 
                   1065: int
                   1066: arm_not_operand (op, mode)
                   1067:      rtx op;
                   1068:      enum machine_mode mode;
                   1069: {
                   1070:   return (s_register_operand (op, mode)
                   1071:          || (GET_CODE (op) == CONST_INT
                   1072:              && (const_ok_for_arm (INTVAL (op))
                   1073:                  || const_ok_for_arm (~INTVAL (op)))));
1.1.1.3   root     1074: }
1.1.1.2   root     1075: 
1.1       root     1076: /* Return TRUE for valid operands for the rhs of an FPU instruction.  */
                   1077: 
                   1078: int
                   1079: fpu_rhs_operand (op, mode)
                   1080:      rtx op;
                   1081:      enum machine_mode mode;
                   1082: {
1.1.1.2   root     1083:   if (s_register_operand (op, mode))
1.1.1.3   root     1084:     return TRUE;
1.1       root     1085:   else if (GET_CODE (op) == CONST_DOUBLE)
                   1086:     return (const_double_rtx_ok_for_fpu (op));
1.1.1.3   root     1087: 
                   1088:   return FALSE;
                   1089: }
1.1       root     1090: 
1.1.1.2   root     1091: int
                   1092: fpu_add_operand (op, mode)
                   1093:      rtx op;
                   1094:      enum machine_mode mode;
                   1095: {
                   1096:   if (s_register_operand (op, mode))
1.1.1.3   root     1097:     return TRUE;
1.1.1.2   root     1098:   else if (GET_CODE (op) == CONST_DOUBLE)
1.1.1.3   root     1099:     return (const_double_rtx_ok_for_fpu (op) 
                   1100:            || neg_const_double_rtx_ok_for_fpu (op));
                   1101: 
                   1102:   return FALSE;
1.1.1.2   root     1103: }
                   1104: 
1.1       root     1105: /* Return nonzero if OP is a constant power of two.  */
                   1106: 
                   1107: int
                   1108: power_of_two_operand (op, mode)
                   1109:      rtx op;
                   1110:      enum machine_mode mode;
                   1111: {
                   1112:   if (GET_CODE (op) == CONST_INT)
                   1113:     {
1.1.1.3   root     1114:       HOST_WIDE_INT value = INTVAL(op);
                   1115:       return value != 0  &&  (value & (value - 1)) == 0;
1.1       root     1116:     }
1.1.1.3   root     1117:   return FALSE;
                   1118: }
1.1       root     1119: 
                   1120: /* Return TRUE for a valid operand of a DImode operation.
1.1.1.2   root     1121:    Either: REG, CONST_DOUBLE or MEM(DImode_address).
                   1122:    Note that this disallows MEM(REG+REG), but allows
                   1123:    MEM(PRE/POST_INC/DEC(REG)).  */
1.1       root     1124: 
                   1125: int
                   1126: di_operand (op, mode)
                   1127:      rtx op;
                   1128:      enum machine_mode mode;
                   1129: {
1.1.1.2   root     1130:   if (s_register_operand (op, mode))
1.1.1.3   root     1131:     return TRUE;
1.1       root     1132: 
                   1133:   switch (GET_CODE (op))
                   1134:     {
                   1135:     case CONST_DOUBLE:
                   1136:     case CONST_INT:
1.1.1.3   root     1137:       return TRUE;
                   1138: 
1.1       root     1139:     case MEM:
1.1.1.3   root     1140:       return memory_address_p (DImode, XEXP (op, 0));
                   1141: 
1.1       root     1142:     default:
1.1.1.3   root     1143:       return FALSE;
1.1       root     1144:     }
1.1.1.3   root     1145: }
1.1       root     1146: 
1.1.1.4 ! root     1147: /* Return TRUE for a valid operand of a DFmode operation when -msoft-float.
        !          1148:    Either: REG, CONST_DOUBLE or MEM(DImode_address).
        !          1149:    Note that this disallows MEM(REG+REG), but allows
        !          1150:    MEM(PRE/POST_INC/DEC(REG)).  */
        !          1151: 
        !          1152: int
        !          1153: soft_df_operand (op, mode)
        !          1154:      rtx op;
        !          1155:      enum machine_mode mode;
        !          1156: {
        !          1157:   if (s_register_operand (op, mode))
        !          1158:     return TRUE;
        !          1159: 
        !          1160:   switch (GET_CODE (op))
        !          1161:     {
        !          1162:     case CONST_DOUBLE:
        !          1163:       return TRUE;
        !          1164: 
        !          1165:     case MEM:
        !          1166:       return memory_address_p (DFmode, XEXP (op, 0));
        !          1167: 
        !          1168:     default:
        !          1169:       return FALSE;
        !          1170:     }
        !          1171: }
        !          1172: 
1.1       root     1173: /* Return TRUE for valid index operands. */
                   1174: 
                   1175: int
                   1176: index_operand (op, mode)
                   1177:      rtx op;
                   1178:      enum machine_mode mode;
                   1179: {
1.1.1.2   root     1180:   return (s_register_operand(op, mode)
                   1181:          || (immediate_operand (op, mode)
                   1182:              && INTVAL (op) < 4096 && INTVAL (op) > -4096));
1.1.1.3   root     1183: }
1.1       root     1184: 
1.1.1.2   root     1185: /* Return TRUE for valid shifts by a constant. This also accepts any
                   1186:    power of two on the (somewhat overly relaxed) assumption that the
                   1187:    shift operator in this case was a mult. */
                   1188: 
                   1189: int
                   1190: const_shift_operand (op, mode)
                   1191:      rtx op;
                   1192:      enum machine_mode mode;
                   1193: {
                   1194:   return (power_of_two_operand (op, mode)
                   1195:          || (immediate_operand (op, mode)
                   1196:              && (INTVAL (op) < 32 && INTVAL (op) > 0)));
1.1.1.3   root     1197: }
1.1.1.2   root     1198: 
1.1       root     1199: /* Return TRUE for arithmetic operators which can be combined with a multiply
                   1200:    (shift).  */
                   1201: 
                   1202: int
                   1203: shiftable_operator (x, mode)
                   1204:      rtx x;
                   1205:      enum machine_mode mode;
                   1206: {
                   1207:   if (GET_MODE (x) != mode)
                   1208:     return FALSE;
                   1209:   else
                   1210:     {
                   1211:       enum rtx_code code = GET_CODE (x);
                   1212: 
                   1213:       return (code == PLUS || code == MINUS
                   1214:              || code == IOR || code == XOR || code == AND);
                   1215:     }
1.1.1.3   root     1216: }
1.1       root     1217: 
                   1218: /* Return TRUE for shift operators. */
                   1219: 
                   1220: int
                   1221: shift_operator (x, mode)
                   1222:      rtx x;
                   1223:      enum machine_mode mode;
                   1224: {
                   1225:   if (GET_MODE (x) != mode)
                   1226:     return FALSE;
                   1227:   else
                   1228:     {
                   1229:       enum rtx_code code = GET_CODE (x);
                   1230: 
1.1.1.2   root     1231:       if (code == MULT)
                   1232:        return power_of_two_operand (XEXP (x, 1));
1.1.1.3   root     1233: 
                   1234:       return (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT
                   1235:              || code == ROTATERT);
1.1       root     1236:     }
1.1.1.3   root     1237: }
1.1.1.2   root     1238: 
                   1239: int equality_operator (x, mode)
1.1.1.3   root     1240:      rtx x;
                   1241:      enum machine_mode mode;
1.1.1.2   root     1242: {
1.1.1.3   root     1243:   return GET_CODE (x) == EQ || GET_CODE (x) == NE;
1.1.1.2   root     1244: }
                   1245: 
                   1246: /* Return TRUE for SMIN SMAX UMIN UMAX operators. */
                   1247: 
                   1248: int
                   1249: minmax_operator (x, mode)
                   1250:      rtx x;
                   1251:      enum machine_mode mode;
                   1252: {
                   1253:   enum rtx_code code = GET_CODE (x);
                   1254: 
                   1255:   if (GET_MODE (x) != mode)
                   1256:     return FALSE;
1.1.1.3   root     1257: 
1.1.1.2   root     1258:   return code == SMIN || code == SMAX || code == UMIN || code == UMAX;
1.1.1.3   root     1259: }
                   1260: 
                   1261: /* return TRUE if x is EQ or NE */
                   1262: 
                   1263: /* Return TRUE if this is the condition code register, if we aren't given
                   1264:    a mode, accept any class CCmode register */
                   1265: 
                   1266: int
                   1267: cc_register (x, mode)
                   1268:      rtx x;
                   1269:      enum machine_mode mode;
                   1270: {
                   1271:   if (mode == VOIDmode)
                   1272:     {
                   1273:       mode = GET_MODE (x);
                   1274:       if (GET_MODE_CLASS (mode) != MODE_CC)
                   1275:        return FALSE;
                   1276:     }
                   1277: 
                   1278:   if (mode == GET_MODE (x) && GET_CODE (x) == REG && REGNO (x) == 24)
                   1279:     return TRUE;
1.1.1.2   root     1280: 
1.1.1.3   root     1281:   return FALSE;
                   1282: }
1.1.1.2   root     1283: 
                   1284: /* Return TRUE if this is the condition code register, if we aren't given
1.1.1.3   root     1285:    a mode, accept any mode in class CC_MODE that is reversible */
1.1.1.2   root     1286: 
                   1287: int
1.1.1.3   root     1288: reversible_cc_register (x, mode)
                   1289:      rtx x;
                   1290:      enum machine_mode mode;
1.1.1.2   root     1291: {
                   1292:   if (mode == VOIDmode)
                   1293:     {
                   1294:       mode = GET_MODE (x);
1.1.1.3   root     1295:       if (GET_MODE_CLASS (mode) != MODE_CC
                   1296:          && GET_CODE (x) == REG && REGNO (x) == 24)
                   1297:        abort ();
                   1298:       if (GET_MODE_CLASS (mode) != MODE_CC
                   1299:          || (! flag_fast_math && ! REVERSIBLE_CC_MODE (mode)))
1.1.1.2   root     1300:        return FALSE;
                   1301:     }
1.1.1.3   root     1302: 
1.1.1.2   root     1303:   if (mode == GET_MODE (x) && GET_CODE (x) == REG && REGNO (x) == 24)
                   1304:     return TRUE;
1.1.1.3   root     1305: 
1.1.1.2   root     1306:   return FALSE;
                   1307: }
1.1.1.3   root     1308: 
1.1.1.2   root     1309: enum rtx_code
                   1310: minmax_code (x)
1.1.1.3   root     1311:      rtx x;
1.1.1.2   root     1312: {
                   1313:   enum rtx_code code = GET_CODE (x);
                   1314: 
                   1315:   if (code == SMAX)
                   1316:     return GE;
1.1.1.3   root     1317:   else if (code == SMIN)
1.1.1.2   root     1318:     return LE;
1.1.1.3   root     1319:   else if (code == UMIN)
1.1.1.2   root     1320:     return LEU;
1.1.1.3   root     1321:   else if (code == UMAX)
1.1.1.2   root     1322:     return GEU;
1.1.1.3   root     1323: 
1.1.1.2   root     1324:   abort ();
                   1325: }
                   1326: 
                   1327: /* Return 1 if memory locations are adjacent */
                   1328: 
1.1.1.3   root     1329: int
1.1.1.2   root     1330: adjacent_mem_locations (a, b)
                   1331:      rtx a, b;
                   1332: {
                   1333:   int val0 = 0, val1 = 0;
                   1334:   int reg0, reg1;
                   1335:   
                   1336:   if ((GET_CODE (XEXP (a, 0)) == REG
                   1337:        || (GET_CODE (XEXP (a, 0)) == PLUS
                   1338:           && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT))
                   1339:       && (GET_CODE (XEXP (b, 0)) == REG
                   1340:          || (GET_CODE (XEXP (b, 0)) == PLUS
                   1341:              && GET_CODE (XEXP (XEXP (b, 0), 1)) == CONST_INT)))
                   1342:     {
                   1343:       if (GET_CODE (XEXP (a, 0)) == PLUS)
                   1344:         {
                   1345:          reg0 = REGNO (XEXP (XEXP (a, 0), 0));
                   1346:          val0 = INTVAL (XEXP (XEXP (a, 0), 1));
                   1347:         }
                   1348:       else
                   1349:        reg0 = REGNO (XEXP (a, 0));
                   1350:       if (GET_CODE (XEXP (b, 0)) == PLUS)
                   1351:         {
                   1352:          reg1 = REGNO (XEXP (XEXP (b, 0), 0));
                   1353:          val1 = INTVAL (XEXP (XEXP (b, 0), 1));
                   1354:         }
                   1355:       else
                   1356:        reg1 = REGNO (XEXP (b, 0));
                   1357:       return (reg0 == reg1) && ((val1 - val0) == 4 || (val0 - val1) == 4);
                   1358:     }
                   1359:   return 0;
                   1360: }
                   1361: 
                   1362: /* Return 1 if OP is a load multiple operation.  It is known to be
                   1363:    parallel and the first section will be tested. */
                   1364: 
1.1.1.3   root     1365: int
1.1.1.2   root     1366: load_multiple_operation (op, mode)
                   1367:      rtx op;
                   1368:      enum machine_mode mode;
                   1369: {
1.1.1.3   root     1370:   HOST_WIDE_INT count = XVECLEN (op, 0);
1.1.1.2   root     1371:   int dest_regno;
                   1372:   rtx src_addr;
1.1.1.3   root     1373:   HOST_WIDE_INT i = 1, base = 0;
1.1.1.2   root     1374:   rtx elt;
                   1375: 
                   1376:   if (count <= 1
                   1377:       || GET_CODE (XVECEXP (op, 0, 0)) != SET)
                   1378:     return 0;
                   1379: 
                   1380:   /* Check to see if this might be a write-back */
                   1381:   if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
                   1382:     {
                   1383:       i++;
                   1384:       base = 1;
                   1385: 
                   1386:       /* Now check it more carefully */
                   1387:       if (GET_CODE (SET_DEST (elt)) != REG
                   1388:           || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
                   1389:           || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt))
                   1390:           || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
                   1391:           || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 2) * 4
                   1392:           || GET_CODE (XVECEXP (op, 0, count - 1)) != CLOBBER
                   1393:           || GET_CODE (XEXP (XVECEXP (op, 0, count - 1), 0)) != REG
                   1394:           || REGNO (XEXP (XVECEXP (op, 0, count - 1), 0))
                   1395:               != REGNO (SET_DEST (elt)))
                   1396:         return 0;
1.1.1.3   root     1397: 
1.1.1.2   root     1398:       count--;
                   1399:     }
                   1400: 
                   1401:   /* Perform a quick check so we don't blow up below.  */
                   1402:   if (count <= i
                   1403:       || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
                   1404:       || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != REG
                   1405:       || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != MEM)
                   1406:     return 0;
                   1407: 
                   1408:   dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1)));
                   1409:   src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0);
                   1410: 
                   1411:   for (; i < count; i++)
                   1412:     {
                   1413:       rtx elt = XVECEXP (op, 0, i);
                   1414: 
                   1415:       if (GET_CODE (elt) != SET
                   1416:           || GET_CODE (SET_DEST (elt)) != REG
                   1417:           || GET_MODE (SET_DEST (elt)) != SImode
                   1418:           || REGNO (SET_DEST (elt)) != dest_regno + i - base
                   1419:           || GET_CODE (SET_SRC (elt)) != MEM
                   1420:           || GET_MODE (SET_SRC (elt)) != SImode
                   1421:           || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
                   1422:           || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
                   1423:           || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
                   1424:           || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != (i - base) * 4)
                   1425:         return 0;
                   1426:     }
                   1427: 
                   1428:   return 1;
                   1429: }
                   1430: 
                   1431: /* Return 1 if OP is a store multiple operation.  It is known to be
                   1432:    parallel and the first section will be tested. */
                   1433: 
1.1.1.3   root     1434: int
1.1.1.2   root     1435: store_multiple_operation (op, mode)
                   1436:      rtx op;
                   1437:      enum machine_mode mode;
                   1438: {
1.1.1.3   root     1439:   HOST_WIDE_INT count = XVECLEN (op, 0);
1.1.1.2   root     1440:   int src_regno;
                   1441:   rtx dest_addr;
1.1.1.3   root     1442:   HOST_WIDE_INT i = 1, base = 0;
1.1.1.2   root     1443:   rtx elt;
                   1444: 
                   1445:   if (count <= 1
                   1446:       || GET_CODE (XVECEXP (op, 0, 0)) != SET)
                   1447:     return 0;
                   1448: 
                   1449:   /* Check to see if this might be a write-back */
                   1450:   if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
                   1451:     {
                   1452:       i++;
                   1453:       base = 1;
                   1454: 
                   1455:       /* Now check it more carefully */
                   1456:       if (GET_CODE (SET_DEST (elt)) != REG
                   1457:           || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
                   1458:           || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt))
                   1459:           || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
                   1460:           || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 2) * 4
                   1461:           || GET_CODE (XVECEXP (op, 0, count - 1)) != CLOBBER
                   1462:           || GET_CODE (XEXP (XVECEXP (op, 0, count - 1), 0)) != REG
                   1463:           || REGNO (XEXP (XVECEXP (op, 0, count - 1), 0))
                   1464:               != REGNO (SET_DEST (elt)))
                   1465:         return 0;
1.1.1.3   root     1466: 
1.1.1.2   root     1467:       count--;
                   1468:     }
                   1469: 
                   1470:   /* Perform a quick check so we don't blow up below.  */
                   1471:   if (count <= i
                   1472:       || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
                   1473:       || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != MEM
                   1474:       || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != REG)
                   1475:     return 0;
                   1476: 
                   1477:   src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1)));
                   1478:   dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0);
                   1479: 
                   1480:   for (; i < count; i++)
                   1481:     {
                   1482:       elt = XVECEXP (op, 0, i);
                   1483: 
                   1484:       if (GET_CODE (elt) != SET
                   1485:           || GET_CODE (SET_SRC (elt)) != REG
                   1486:           || GET_MODE (SET_SRC (elt)) != SImode
                   1487:           || REGNO (SET_SRC (elt)) != src_regno + i - base
                   1488:           || GET_CODE (SET_DEST (elt)) != MEM
                   1489:           || GET_MODE (SET_DEST (elt)) != SImode
                   1490:           || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
                   1491:           || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
                   1492:           || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
                   1493:           || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != (i - base) * 4)
                   1494:         return 0;
                   1495:     }
                   1496: 
                   1497:   return 1;
                   1498: }
1.1.1.3   root     1499: 
                   1500: int
                   1501: multi_register_push (op, mode)
                   1502:      rtx op;
                   1503:      enum machine_mode mode;
                   1504: {
                   1505:   if (GET_CODE (op) != PARALLEL
                   1506:       || (GET_CODE (XVECEXP (op, 0, 0)) != SET)
                   1507:       || (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC)
                   1508:       || (XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != 2))
                   1509:     return 0;
                   1510: 
                   1511:   return 1;
                   1512: }
                   1513: 
                   1514: 
                   1515: /* Routines for use with attributes */
                   1516: 
                   1517: int
                   1518: const_pool_offset (symbol)
                   1519:      rtx symbol;
                   1520: {
                   1521:   return get_pool_offset (symbol) - get_pool_size () - get_prologue_size ();
                   1522: }
1.1.1.2   root     1523: 
                   1524: /* Routines for use in generating RTL */
                   1525: 
1.1.1.3   root     1526: rtx
                   1527: arm_gen_load_multiple (base_regno, count, from, up, write_back)
1.1.1.2   root     1528:      int base_regno;
                   1529:      int count;
                   1530:      rtx from;
                   1531:      int up;
                   1532:      int write_back;
                   1533: {
                   1534:   int i = 0, j;
                   1535:   rtx result;
                   1536:   int sign = up ? 1 : -1;
                   1537: 
                   1538:   result = gen_rtx (PARALLEL, VOIDmode,
                   1539:                     rtvec_alloc (count + (write_back ? 2 : 0)));
                   1540:   if (write_back)
1.1.1.3   root     1541:     {
1.1.1.2   root     1542:       XVECEXP (result, 0, 0)
1.1.1.3   root     1543:        = gen_rtx (SET, GET_MODE (from), from,
                   1544:                   plus_constant (from, count * 4 * sign));
1.1.1.2   root     1545:       i = 1;
                   1546:       count++;
1.1.1.3   root     1547:     }
                   1548: 
1.1.1.2   root     1549:   for (j = 0; i < count; i++, j++)
1.1.1.3   root     1550:     {
1.1.1.2   root     1551:       XVECEXP (result, 0, i)
1.1.1.3   root     1552:        = gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, base_regno + j),
                   1553:                   gen_rtx (MEM, SImode,
                   1554:                            plus_constant (from, j * 4 * sign)));
                   1555:     }
                   1556: 
1.1.1.2   root     1557:   if (write_back)
                   1558:     XVECEXP (result, 0, i) = gen_rtx (CLOBBER, SImode, from);
                   1559: 
                   1560:   return result;
                   1561: }
                   1562: 
1.1.1.3   root     1563: rtx
                   1564: arm_gen_store_multiple (base_regno, count, to, up, write_back)
1.1.1.2   root     1565:      int base_regno;
                   1566:      int count;
                   1567:      rtx to;
                   1568:      int up;
                   1569:      int write_back;
                   1570: {
                   1571:   int i = 0, j;
                   1572:   rtx result;
                   1573:   int sign = up ? 1 : -1;
                   1574: 
                   1575:   result = gen_rtx (PARALLEL, VOIDmode,
                   1576:                     rtvec_alloc (count + (write_back ? 2 : 0)));
                   1577:   if (write_back)
1.1.1.3   root     1578:     {
1.1.1.2   root     1579:       XVECEXP (result, 0, 0)
1.1.1.3   root     1580:        = gen_rtx (SET, GET_MODE (to), to,
                   1581:                   plus_constant (to, count * 4 * sign));
1.1.1.2   root     1582:       i = 1;
                   1583:       count++;
1.1.1.3   root     1584:     }
                   1585: 
1.1.1.2   root     1586:   for (j = 0; i < count; i++, j++)
1.1.1.3   root     1587:     {
1.1.1.2   root     1588:       XVECEXP (result, 0, i)
1.1.1.3   root     1589:        = gen_rtx (SET, VOIDmode,
                   1590:                   gen_rtx (MEM, SImode, plus_constant (to, j * 4 * sign)),
                   1591:                   gen_rtx (REG, SImode, base_regno + j));
                   1592:     }
                   1593: 
1.1.1.2   root     1594:   if (write_back)
                   1595:     XVECEXP (result, 0, i) = gen_rtx (CLOBBER, SImode, to);
                   1596: 
                   1597:   return result;
                   1598: }
                   1599: 
1.1.1.3   root     1600: int
                   1601: arm_gen_movstrqi (operands)
                   1602:      rtx *operands;
                   1603: {
                   1604:   HOST_WIDE_INT in_words_to_go, out_words_to_go, last_bytes;
                   1605:   int i, r;
                   1606:   rtx src, dst;
                   1607:   rtx st_src, st_dst, end_src, end_dst, fin_src, fin_dst;
                   1608:   rtx part_bytes_reg = NULL;
                   1609:   extern int optimize;
                   1610: 
                   1611:   if (GET_CODE (operands[2]) != CONST_INT
                   1612:       || GET_CODE (operands[3]) != CONST_INT
                   1613:       || INTVAL (operands[2]) > 64
                   1614:       || INTVAL (operands[3]) & 3)
                   1615:     return 0;
                   1616: 
                   1617:   st_dst = XEXP (operands[0], 0);
                   1618:   st_src = XEXP (operands[1], 0);
                   1619:   fin_dst = dst = copy_to_mode_reg (SImode, st_dst);
                   1620:   fin_src = src = copy_to_mode_reg (SImode, st_src);
                   1621: 
                   1622:   in_words_to_go = (INTVAL (operands[2]) + 3) / 4;
                   1623:   out_words_to_go = INTVAL (operands[2]) / 4;
                   1624:   last_bytes = INTVAL (operands[2]) & 3;
                   1625: 
                   1626:   if (out_words_to_go != in_words_to_go && ((in_words_to_go - 1) & 3) != 0)
                   1627:     part_bytes_reg = gen_rtx (REG, SImode, (in_words_to_go - 1) & 3);
                   1628: 
                   1629:   for (i = 0; in_words_to_go >= 2; i+=4)
                   1630:     {
                   1631:       emit_insn (arm_gen_load_multiple (0, (in_words_to_go > 4 
                   1632:                                            ? 4 : in_words_to_go),
                   1633:                                         src, TRUE, TRUE));
                   1634:       if (out_words_to_go)
                   1635:        {
                   1636:          if (out_words_to_go != 1)
                   1637:            emit_insn (arm_gen_store_multiple (0, (out_words_to_go > 4
                   1638:                                                   ? 4 : out_words_to_go),
                   1639:                                               dst, TRUE, TRUE));
                   1640:          else
                   1641:            {
                   1642:              emit_move_insn (gen_rtx (MEM, SImode, dst),
                   1643:                              gen_rtx (REG, SImode, 0));
                   1644:              emit_insn (gen_addsi3 (dst, dst, GEN_INT (4)));
                   1645:            }
                   1646:        }
                   1647: 
                   1648:       in_words_to_go -= in_words_to_go < 4 ? in_words_to_go : 4;
                   1649:       out_words_to_go -= out_words_to_go < 4 ? out_words_to_go : 4;
                   1650:     }
                   1651: 
                   1652:   /* OUT_WORDS_TO_GO will be zero here if there are byte stores to do.  */
                   1653:   if (out_words_to_go)
                   1654:   {
                   1655:     rtx sreg;
                   1656: 
                   1657:     emit_move_insn (sreg = gen_reg_rtx (SImode), gen_rtx (MEM, SImode, src));
                   1658:     emit_move_insn (fin_src = gen_reg_rtx (SImode), plus_constant (src, 4));
                   1659:     emit_move_insn (gen_rtx (MEM, SImode, dst), sreg);
                   1660:     emit_move_insn (fin_dst = gen_reg_rtx (SImode), plus_constant (dst, 4));
                   1661:     in_words_to_go--;
                   1662: 
                   1663:     if (in_words_to_go)        /* Sanity check */
                   1664:       abort ();
                   1665:   }
                   1666: 
                   1667:   if (in_words_to_go)
                   1668:     {
                   1669:       if (in_words_to_go < 0)
                   1670:        abort ();
                   1671: 
                   1672:       part_bytes_reg = copy_to_mode_reg (SImode, gen_rtx (MEM, SImode, src));
                   1673:       emit_insn (gen_addsi3 (src, src, GEN_INT (4)));
                   1674:     }
                   1675: 
                   1676:   if (BYTES_BIG_ENDIAN && last_bytes)
                   1677:     {
                   1678:       rtx tmp = gen_reg_rtx (SImode);
                   1679: 
                   1680:       if (part_bytes_reg == NULL)
                   1681:        abort ();
                   1682: 
                   1683:       /* The bytes we want are in the top end of the word */
                   1684:       emit_insn (gen_lshrsi3 (tmp, part_bytes_reg,
                   1685:                              GEN_INT (8 * (4 - last_bytes))));
                   1686:       part_bytes_reg = tmp;
                   1687:       
                   1688:       while (last_bytes)
                   1689:        {
                   1690:          emit_move_insn (gen_rtx (MEM, QImode, 
                   1691:                                   plus_constant (dst, last_bytes - 1)),
                   1692:                          gen_rtx (SUBREG, QImode, part_bytes_reg, 0));
                   1693:          if (--last_bytes)
                   1694:            {
                   1695:              tmp = gen_reg_rtx (SImode);
                   1696:              emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8)));
                   1697:              part_bytes_reg = tmp;
                   1698:            }
                   1699:        }
                   1700:          
                   1701:     }
                   1702:   else
                   1703:     {
                   1704:       while (last_bytes)
                   1705:        {
                   1706:          if (part_bytes_reg == NULL)
                   1707:            abort ();
                   1708: 
                   1709:          emit_move_insn (gen_rtx (MEM, QImode, dst),
                   1710:                          gen_rtx (SUBREG, QImode, part_bytes_reg, 0));
                   1711:          emit_insn (gen_addsi3 (dst, dst, const1_rtx));
                   1712:          if (--last_bytes)
                   1713:            {
                   1714:              rtx tmp = gen_reg_rtx (SImode);
                   1715:              emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8)));
                   1716:              part_bytes_reg = tmp;
                   1717:            }
                   1718:        }
                   1719:     }
                   1720: 
                   1721:   return 1;
                   1722: }
                   1723: 
1.1.1.2   root     1724: /* X and Y are two things to compare using CODE.  Emit the compare insn and
                   1725:    return the rtx for register 0 in the proper mode.  FP means this is a
                   1726:    floating point compare: I don't think that it is needed on the arm.  */
                   1727: 
                   1728: rtx
                   1729: gen_compare_reg (code, x, y, fp)
                   1730:      enum rtx_code code;
                   1731:      rtx x, y;
                   1732: {
                   1733:   enum machine_mode mode = SELECT_CC_MODE (code, x, y);
                   1734:   rtx cc_reg = gen_rtx (REG, mode, 24);
                   1735: 
                   1736:   emit_insn (gen_rtx (SET, VOIDmode, cc_reg,
                   1737:                       gen_rtx (COMPARE, mode, x, y)));
                   1738: 
                   1739:   return cc_reg;
                   1740: }
                   1741: 
1.1.1.3   root     1742: void
                   1743: arm_reload_in_hi (operands)
                   1744:      rtx *operands;
                   1745: {
                   1746:   rtx base = find_replacement (&XEXP (operands[1], 0));
                   1747: 
                   1748:   emit_insn (gen_zero_extendqisi2 (operands[2], gen_rtx (MEM, QImode, base)));
                   1749:   emit_insn (gen_zero_extendqisi2 (gen_rtx (SUBREG, SImode, operands[0], 0),
                   1750:                                   gen_rtx (MEM, QImode, 
                   1751:                                            plus_constant (base, 1))));
                   1752:   if (BYTES_BIG_ENDIAN)
                   1753:     emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (SUBREG, SImode, 
                   1754:                                                operands[0], 0),
                   1755:                        gen_rtx (IOR, SImode, 
                   1756:                                 gen_rtx (ASHIFT, SImode,
                   1757:                                          gen_rtx (SUBREG, SImode,
                   1758:                                                   operands[0], 0),
                   1759:                                          GEN_INT (8)),
                   1760:                                 operands[2])));
                   1761:   else
                   1762:     emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (SUBREG, SImode, 
                   1763:                                                operands[0], 0),
                   1764:                        gen_rtx (IOR, SImode, 
                   1765:                                 gen_rtx (ASHIFT, SImode,
                   1766:                                          operands[2],
                   1767:                                          GEN_INT (8)),
                   1768:                                 gen_rtx (SUBREG, SImode, operands[0], 0))));
                   1769: }
                   1770: 
                   1771: void
1.1.1.2   root     1772: arm_reload_out_hi (operands)
1.1.1.3   root     1773:      rtx *operands;
1.1.1.2   root     1774: {
                   1775:   rtx base = find_replacement (&XEXP (operands[0], 0));
                   1776: 
1.1.1.3   root     1777:   if (BYTES_BIG_ENDIAN)
                   1778:     {
                   1779:       emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (base, 1)),
                   1780:                            gen_rtx (SUBREG, QImode, operands[1], 0)));
                   1781:       emit_insn (gen_lshrsi3 (operands[2],
                   1782:                              gen_rtx (SUBREG, SImode, operands[1], 0),
                   1783:                              GEN_INT (8)));
                   1784:       emit_insn (gen_movqi (gen_rtx (MEM, QImode, base),
                   1785:                            gen_rtx (SUBREG, QImode, operands[2], 0)));
                   1786:     }
                   1787:   else
                   1788:     {
                   1789:       emit_insn (gen_movqi (gen_rtx (MEM, QImode, base),
                   1790:                            gen_rtx (SUBREG, QImode, operands[1], 0)));
                   1791:       emit_insn (gen_lshrsi3 (operands[2],
                   1792:                              gen_rtx (SUBREG, SImode, operands[1], 0),
                   1793:                              GEN_INT (8)));
                   1794:       emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (base, 1)),
                   1795:                            gen_rtx (SUBREG, QImode, operands[2], 0)));
                   1796:     }
1.1.1.2   root     1797: }
                   1798: 
                   1799: /* Check to see if a branch is forwards or backwards.  Return TRUE if it
                   1800:    is backwards.  */
                   1801: 
                   1802: int
                   1803: arm_backwards_branch (from, to)
1.1.1.3   root     1804:      int from, to;
1.1.1.2   root     1805: {
1.1.1.3   root     1806:   return insn_addresses[to] <= insn_addresses[from];
1.1.1.2   root     1807: }
                   1808: 
                   1809: /* Check to see if a branch is within the distance that can be done using
                   1810:    an arithmetic expression. */
                   1811: int
                   1812: short_branch (from, to)
1.1.1.3   root     1813:      int from, to;
1.1.1.2   root     1814: {
1.1.1.3   root     1815:   int delta = insn_addresses[from] + 8 - insn_addresses[to];
1.1.1.2   root     1816: 
1.1.1.3   root     1817:   return abs (delta) < 980;    /* A small margin for safety */
1.1.1.2   root     1818: }
                   1819: 
                   1820: /* Check to see that the insn isn't the target of the conditionalizing
                   1821:    code */
                   1822: int
                   1823: arm_insn_not_targeted (insn)
1.1.1.3   root     1824:      rtx insn;
1.1.1.2   root     1825: {
                   1826:   return insn != arm_target_insn;
                   1827: }
                   1828: 
1.1       root     1829: 
                   1830: /* Routines to output assembly language.  */
                   1831: 
1.1.1.3   root     1832: /* If the rtx is the correct value then return the string of the number.
1.1.1.2   root     1833:    In this way we can ensure that valid double constants are generated even
                   1834:    when cross compiling. */
                   1835: char *
                   1836: fp_immediate_constant (x)
1.1.1.3   root     1837:      rtx x;
1.1.1.2   root     1838: {
                   1839:   REAL_VALUE_TYPE r;
                   1840:   int i;
                   1841:   
                   1842:   if (!fpa_consts_inited)
                   1843:     init_fpa_table ();
                   1844:   
                   1845:   REAL_VALUE_FROM_CONST_DOUBLE (r, x);
                   1846:   for (i = 0; i < 8; i++)
                   1847:     if (REAL_VALUES_EQUAL (r, values_fpa[i]))
                   1848:       return strings_fpa[i];
1.1.1.3   root     1849: 
1.1.1.2   root     1850:   abort ();
                   1851: }
                   1852: 
1.1.1.3   root     1853: /* As for fp_immediate_constant, but value is passed directly, not in rtx.  */
                   1854: static char *
                   1855: fp_const_from_val (r)
                   1856:      REAL_VALUE_TYPE *r;
                   1857: {
                   1858:   int i;
                   1859: 
                   1860:   if (! fpa_consts_inited)
                   1861:     init_fpa_table ();
                   1862: 
                   1863:   for (i = 0; i < 8; i++)
                   1864:     if (REAL_VALUES_EQUAL (*r, values_fpa[i]))
                   1865:       return strings_fpa[i];
                   1866: 
                   1867:   abort ();
                   1868: }
1.1.1.2   root     1869: 
1.1       root     1870: /* Output the operands of a LDM/STM instruction to STREAM.
                   1871:    MASK is the ARM register set mask of which only bits 0-15 are important.
                   1872:    INSTR is the possibly suffixed base register.  HAT unequals zero if a hat
                   1873:    must follow the register list.  */
                   1874: 
                   1875: void
                   1876: print_multi_reg (stream, instr, mask, hat)
                   1877:      FILE *stream;
                   1878:      char *instr;
                   1879:      int mask, hat;
                   1880: {
                   1881:   int i;
                   1882:   int not_first = FALSE;
                   1883: 
1.1.1.3   root     1884:   fputc ('\t', stream);
1.1.1.4 ! root     1885:   fprintf (stream, instr, REGISTER_PREFIX);
1.1.1.3   root     1886:   fputs (", {", stream);
1.1       root     1887:   for (i = 0; i < 16; i++)
                   1888:     if (mask & (1 << i))
                   1889:       {
                   1890:        if (not_first)
                   1891:          fprintf (stream, ", ");
1.1.1.4 ! root     1892:        fprintf (stream, "%s%s", REGISTER_PREFIX, reg_names[i]);
1.1       root     1893:        not_first = TRUE;
                   1894:       }
1.1.1.3   root     1895: 
1.1       root     1896:   fprintf (stream, "}%s\n", hat ? "^" : "");
1.1.1.3   root     1897: }
1.1       root     1898: 
                   1899: /* Output a 'call' insn. */
                   1900: 
                   1901: char *
                   1902: output_call (operands)
1.1.1.3   root     1903:      rtx *operands;
1.1       root     1904: {
                   1905:   /* Handle calls to lr using ip (which may be clobbered in subr anyway). */
                   1906: 
                   1907:   if (REGNO (operands[0]) == 14)
                   1908:     {
                   1909:       operands[0] = gen_rtx (REG, SImode, 12);
1.1.1.3   root     1910:       output_asm_insn ("mov%?\t%0, %|lr", operands);
1.1       root     1911:     }
1.1.1.3   root     1912:   output_asm_insn ("mov%?\t%|lr, %|pc", operands);
                   1913:   output_asm_insn ("mov%?\t%|pc, %0", operands);
                   1914:   return "";
                   1915: }
1.1       root     1916: 
1.1.1.2   root     1917: static int
                   1918: eliminate_lr2ip (x)
1.1.1.3   root     1919:      rtx *x;
1.1.1.2   root     1920: {
                   1921:   int something_changed = 0;
                   1922:   rtx x0 = *x;
                   1923:   int code = GET_CODE (x0);
                   1924:   register int i, j;
                   1925:   register char *fmt;
                   1926:   
                   1927:   switch (code)
                   1928:     {
                   1929:     case REG:
                   1930:       if (REGNO (x0) == 14)
                   1931:         {
                   1932:          *x = gen_rtx (REG, SImode, 12);
                   1933:          return 1;
                   1934:         }
                   1935:       return 0;
                   1936:     default:
                   1937:       /* Scan through the sub-elements and change any references there */
                   1938:       fmt = GET_RTX_FORMAT (code);
                   1939:       for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
                   1940:        if (fmt[i] == 'e')
                   1941:          something_changed |= eliminate_lr2ip (&XEXP (x0, i));
                   1942:        else if (fmt[i] == 'E')
                   1943:          for (j = 0; j < XVECLEN (x0, i); j++)
                   1944:            something_changed |= eliminate_lr2ip (&XVECEXP (x0, i, j));
                   1945:       return something_changed;
                   1946:     }
                   1947: }
                   1948:   
                   1949: /* Output a 'call' insn that is a reference in memory. */
                   1950: 
                   1951: char *
                   1952: output_call_mem (operands)
1.1.1.3   root     1953:      rtx *operands;
1.1.1.2   root     1954: {
                   1955:   operands[0] = copy_rtx (operands[0]); /* Be ultra careful */
                   1956:   /* Handle calls using lr by using ip (which may be clobbered in subr anyway).
                   1957:    */
                   1958:   if (eliminate_lr2ip (&operands[0]))
1.1.1.3   root     1959:     output_asm_insn ("mov%?\t%|ip, %|lr", operands);
                   1960: 
                   1961:   output_asm_insn ("mov%?\t%|lr, %|pc", operands);
                   1962:   output_asm_insn ("ldr%?\t%|pc, %0", operands);
                   1963:   return "";
                   1964: }
1.1.1.2   root     1965: 
                   1966: 
                   1967: /* Output a move from arm registers to an fpu registers.
                   1968:    OPERANDS[0] is an fpu register.
                   1969:    OPERANDS[1] is the first registers of an arm register pair.  */
                   1970: 
                   1971: char *
                   1972: output_mov_long_double_fpu_from_arm (operands)
1.1.1.3   root     1973:      rtx *operands;
1.1.1.2   root     1974: {
                   1975:   int arm_reg0 = REGNO (operands[1]);
                   1976:   rtx ops[3];
                   1977: 
                   1978:   if (arm_reg0 == 12)
                   1979:     abort();
1.1.1.3   root     1980: 
1.1.1.2   root     1981:   ops[0] = gen_rtx (REG, SImode, arm_reg0);
                   1982:   ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
                   1983:   ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0);
                   1984:   
1.1.1.3   root     1985:   output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops);
                   1986:   output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands);
                   1987:   return "";
                   1988: }
1.1.1.2   root     1989: 
                   1990: /* Output a move from an fpu register to arm registers.
                   1991:    OPERANDS[0] is the first registers of an arm register pair.
                   1992:    OPERANDS[1] is an fpu register.  */
                   1993: 
                   1994: char *
                   1995: output_mov_long_double_arm_from_fpu (operands)
1.1.1.3   root     1996:      rtx *operands;
1.1.1.2   root     1997: {
                   1998:   int arm_reg0 = REGNO (operands[0]);
                   1999:   rtx ops[3];
                   2000: 
                   2001:   if (arm_reg0 == 12)
                   2002:     abort();
1.1.1.3   root     2003: 
1.1.1.2   root     2004:   ops[0] = gen_rtx (REG, SImode, arm_reg0);
                   2005:   ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
                   2006:   ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0);
                   2007: 
1.1.1.3   root     2008:   output_asm_insn ("stf%?e\t%1, [%|sp, #-12]!", operands);
                   2009:   output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1, %2}", ops);
                   2010:   return "";
                   2011: }
1.1.1.2   root     2012: 
                   2013: /* Output a move from arm registers to arm registers of a long double
                   2014:    OPERANDS[0] is the destination.
                   2015:    OPERANDS[1] is the source.  */
                   2016: char *
                   2017: output_mov_long_double_arm_from_arm (operands)
1.1.1.3   root     2018:      rtx *operands;
1.1.1.2   root     2019: {
                   2020:   /* We have to be careful here because the two might overlap */
                   2021:   int dest_start = REGNO (operands[0]);
                   2022:   int src_start = REGNO (operands[1]);
                   2023:   rtx ops[2];
                   2024:   int i;
                   2025: 
                   2026:   if (dest_start < src_start)
                   2027:     {
                   2028:       for (i = 0; i < 3; i++)
                   2029:        {
                   2030:          ops[0] = gen_rtx (REG, SImode, dest_start + i);
                   2031:          ops[1] = gen_rtx (REG, SImode, src_start + i);
1.1.1.3   root     2032:          output_asm_insn ("mov%?\t%0, %1", ops);
1.1.1.2   root     2033:        }
                   2034:     }
                   2035:   else
                   2036:     {
                   2037:       for (i = 2; i >= 0; i--)
                   2038:        {
                   2039:          ops[0] = gen_rtx (REG, SImode, dest_start + i);
                   2040:          ops[1] = gen_rtx (REG, SImode, src_start + i);
1.1.1.3   root     2041:          output_asm_insn ("mov%?\t%0, %1", ops);
1.1.1.2   root     2042:        }
                   2043:     }
1.1.1.3   root     2044: 
1.1.1.2   root     2045:   return "";
                   2046: }
                   2047: 
                   2048: 
1.1       root     2049: /* Output a move from arm registers to an fpu registers.
                   2050:    OPERANDS[0] is an fpu register.
                   2051:    OPERANDS[1] is the first registers of an arm register pair.  */
                   2052: 
                   2053: char *
                   2054: output_mov_double_fpu_from_arm (operands)
1.1.1.3   root     2055:      rtx *operands;
1.1       root     2056: {
                   2057:   int arm_reg0 = REGNO (operands[1]);
                   2058:   rtx ops[2];
                   2059: 
                   2060:   if (arm_reg0 == 12)
                   2061:     abort();
                   2062:   ops[0] = gen_rtx (REG, SImode, arm_reg0);
                   2063:   ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
1.1.1.3   root     2064:   output_asm_insn ("stm%?fd\t%|sp!, {%0, %1}", ops);
                   2065:   output_asm_insn ("ldf%?d\t%0, [%|sp], #8", operands);
                   2066:   return "";
                   2067: }
1.1       root     2068: 
                   2069: /* Output a move from an fpu register to arm registers.
                   2070:    OPERANDS[0] is the first registers of an arm register pair.
                   2071:    OPERANDS[1] is an fpu register.  */
                   2072: 
                   2073: char *
                   2074: output_mov_double_arm_from_fpu (operands)
1.1.1.3   root     2075:      rtx *operands;
1.1       root     2076: {
                   2077:   int arm_reg0 = REGNO (operands[0]);
                   2078:   rtx ops[2];
                   2079: 
                   2080:   if (arm_reg0 == 12)
                   2081:     abort();
1.1.1.3   root     2082: 
1.1       root     2083:   ops[0] = gen_rtx (REG, SImode, arm_reg0);
                   2084:   ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
1.1.1.3   root     2085:   output_asm_insn ("stf%?d\t%1, [%|sp, #-8]!", operands);
                   2086:   output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1}", ops);
                   2087:   return "";
                   2088: }
1.1       root     2089: 
                   2090: /* Output a move between double words.
                   2091:    It must be REG<-REG, REG<-CONST_DOUBLE, REG<-CONST_INT, REG<-MEM
                   2092:    or MEM<-REG and all MEMs must be offsettable addresses.  */
                   2093: 
                   2094: char *
                   2095: output_move_double (operands)
1.1.1.3   root     2096:      rtx *operands;
1.1       root     2097: {
                   2098:   enum rtx_code code0 = GET_CODE (operands[0]);
                   2099:   enum rtx_code code1 = GET_CODE (operands[1]);
                   2100:   rtx otherops[2];
                   2101: 
                   2102:   if (code0 == REG)
                   2103:     {
                   2104:       int reg0 = REGNO (operands[0]);
                   2105: 
                   2106:       otherops[0] = gen_rtx (REG, SImode, 1 + reg0);
                   2107:       if (code1 == REG)
                   2108:        {
                   2109:          int reg1 = REGNO (operands[1]);
                   2110:          if (reg1 == 12)
                   2111:            abort();
1.1.1.3   root     2112: 
1.1       root     2113:          otherops[1] = gen_rtx (REG, SImode, 1 + reg1);
                   2114: 
                   2115:          /* Ensure the second source is not overwritten */
                   2116:          if (reg0 == 1 + reg1)
                   2117:            {
1.1.1.3   root     2118:              output_asm_insn("mov%?\t%0, %1", otherops);
                   2119:              output_asm_insn("mov%?\t%0, %1", operands);
1.1       root     2120:            }
                   2121:          else
                   2122:            {
1.1.1.3   root     2123:              output_asm_insn("mov%?\t%0, %1", operands);
                   2124:              output_asm_insn("mov%?\t%0, %1", otherops);
1.1       root     2125:            }
                   2126:        }
                   2127:       else if (code1 == CONST_DOUBLE)
                   2128:        {
                   2129:          otherops[1] = gen_rtx (CONST_INT, VOIDmode,
                   2130:                                 CONST_DOUBLE_HIGH (operands[1]));
                   2131:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
                   2132:                                 CONST_DOUBLE_LOW (operands[1]));
1.1.1.2   root     2133:          output_mov_immediate (operands, FALSE, "");
                   2134:          output_mov_immediate (otherops, FALSE, "");
1.1       root     2135:        }
                   2136:       else if (code1 == CONST_INT)
                   2137:        {
                   2138:          otherops[1] = const0_rtx;
1.1.1.2   root     2139:          /* sign extend the intval into the high-order word */
                   2140:          /* Note: output_mov_immediate may clobber operands[1], so we
                   2141:             put this out first */
                   2142:          if (INTVAL (operands[1]) < 0)
1.1.1.3   root     2143:            output_asm_insn ("mvn%?\t%0, %1", otherops);
1.1.1.2   root     2144:          else
1.1.1.3   root     2145:            output_asm_insn ("mov%?\t%0, %1", otherops);
1.1.1.2   root     2146:          output_mov_immediate (operands, FALSE, "");
1.1       root     2147:        }
                   2148:       else if (code1 == MEM)
                   2149:        {
1.1.1.2   root     2150:          switch (GET_CODE (XEXP (operands[1], 0)))
1.1       root     2151:            {
1.1.1.2   root     2152:            case REG:
1.1       root     2153:              /* Handle the simple case where address is [r, #0] more
                   2154:                 efficient.  */
1.1.1.3   root     2155:              output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
1.1.1.2   root     2156:              break;
                   2157:            case PRE_INC:
1.1.1.3   root     2158:              output_asm_insn ("add%?\t%m1, %m1, #8", operands);
                   2159:              output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
1.1.1.2   root     2160:              break;
                   2161:            case PRE_DEC:
1.1.1.3   root     2162:              output_asm_insn ("sub%?\t%m1, %m1, #8", operands);
                   2163:              output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
1.1.1.2   root     2164:              break;
                   2165:            case POST_INC:
1.1.1.3   root     2166:              output_asm_insn ("ldm%?ia\t%m1!, %M0", operands);
1.1.1.2   root     2167:              break;
                   2168:            case POST_DEC:
1.1.1.3   root     2169:              output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
                   2170:              output_asm_insn ("sub%?\t%m1, %m1, #8", operands);
1.1.1.2   root     2171:              break;
                   2172:            default:
1.1       root     2173:              otherops[1] = adj_offsettable_operand (operands[1], 4);
                   2174:              /* Take care of overlapping base/data reg.  */
                   2175:              if (reg_mentioned_p (operands[0], operands[1]))
                   2176:                {
1.1.1.3   root     2177:                  output_asm_insn ("ldr%?\t%0, %1", otherops);
                   2178:                  output_asm_insn ("ldr%?\t%0, %1", operands);
1.1       root     2179:                }
                   2180:              else
                   2181:                {
1.1.1.3   root     2182:                  output_asm_insn ("ldr%?\t%0, %1", operands);
                   2183:                  output_asm_insn ("ldr%?\t%0, %1", otherops);
1.1       root     2184:                }
                   2185:            }
                   2186:        }
                   2187:       else abort();  /* Constraints should prevent this */
                   2188:     }
                   2189:   else if (code0 == MEM && code1 == REG)
                   2190:     {
                   2191:       if (REGNO (operands[1]) == 12)
                   2192:        abort();
1.1.1.2   root     2193:       switch (GET_CODE (XEXP (operands[0], 0)))
                   2194:         {
                   2195:        case REG:
1.1.1.3   root     2196:          output_asm_insn ("stm%?ia\t%m0, %M1", operands);
1.1.1.2   root     2197:          break;
                   2198:         case PRE_INC:
1.1.1.3   root     2199:          output_asm_insn ("add%?\t%m0, %m0, #8", operands);
                   2200:          output_asm_insn ("stm%?ia\t%m0, %M1", operands);
1.1.1.2   root     2201:          break;
                   2202:         case PRE_DEC:
1.1.1.3   root     2203:          output_asm_insn ("sub%?\t%m0, %m0, #8", operands);
                   2204:          output_asm_insn ("stm%?ia\t%m0, %M1", operands);
1.1.1.2   root     2205:          break;
                   2206:         case POST_INC:
1.1.1.3   root     2207:          output_asm_insn ("stm%?ia\t%m0!, %M1", operands);
1.1.1.2   root     2208:          break;
                   2209:         case POST_DEC:
1.1.1.3   root     2210:          output_asm_insn ("stm%?ia\t%m0, %M1", operands);
                   2211:          output_asm_insn ("sub%?\t%m0, %m0, #8", operands);
1.1.1.2   root     2212:          break;
                   2213:         default:
1.1       root     2214:          otherops[0] = adj_offsettable_operand (operands[0], 4);
                   2215:          otherops[1] = gen_rtx (REG, SImode, 1 + REGNO (operands[1]));
1.1.1.3   root     2216:          output_asm_insn ("str%?\t%1, %0", operands);
                   2217:          output_asm_insn ("str%?\t%1, %0", otherops);
1.1       root     2218:        }
                   2219:     }
                   2220:   else abort();  /* Constraints should prevent this */
                   2221: 
1.1.1.3   root     2222:   return "";
                   2223: }
1.1       root     2224: 
                   2225: 
                   2226: /* Output an arbitrary MOV reg, #n.
                   2227:    OPERANDS[0] is a register.  OPERANDS[1] is a const_int.  */
                   2228: 
                   2229: char *
                   2230: output_mov_immediate (operands)
1.1.1.3   root     2231:      rtx *operands;
1.1       root     2232: {
1.1.1.3   root     2233:   HOST_WIDE_INT n = INTVAL (operands[1]);
1.1       root     2234:   int n_ones = 0;
                   2235:   int i;
                   2236: 
                   2237:   /* Try to use one MOV */
                   2238:   if (const_ok_for_arm (n))
1.1.1.3   root     2239:     {
                   2240:       output_asm_insn ("mov%?\t%0, %1", operands);
                   2241:       return "";
                   2242:     }
1.1       root     2243: 
                   2244:   /* Try to use one MVN */
1.1.1.3   root     2245:   if (const_ok_for_arm (~n))
1.1       root     2246:     {
1.1.1.3   root     2247:       operands[1] = GEN_INT (~n);
                   2248:       output_asm_insn ("mvn%?\t%0, %1", operands);
                   2249:       return "";
1.1       root     2250:     }
                   2251: 
                   2252:   /* If all else fails, make it out of ORRs or BICs as appropriate. */
                   2253: 
                   2254:   for (i=0; i < 32; i++)
                   2255:     if (n & 1 << i)
                   2256:       n_ones++;
                   2257: 
                   2258:   if (n_ones > 16)  /* Shorter to use MVN with BIC in this case. */
1.1.1.3   root     2259:     output_multi_immediate(operands, "mvn%?\t%0, %1", "bic%?\t%0, %0, %1", 1,
                   2260:                           ~n);
1.1       root     2261:   else
1.1.1.3   root     2262:     output_multi_immediate(operands, "mov%?\t%0, %1", "orr%?\t%0, %0, %1", 1,
                   2263:                           n);
                   2264: 
                   2265:   return "";
                   2266: }
1.1       root     2267: 
                   2268: 
                   2269: /* Output an ADD r, s, #n where n may be too big for one instruction.  If
                   2270:    adding zero to one register, output nothing.  */
                   2271: 
                   2272: char *
                   2273: output_add_immediate (operands)
1.1.1.3   root     2274:      rtx *operands;
1.1       root     2275: {
1.1.1.3   root     2276:   HOST_WIDE_INT n = INTVAL (operands[2]);
1.1       root     2277: 
                   2278:   if (n != 0 || REGNO (operands[0]) != REGNO (operands[1]))
                   2279:     {
                   2280:       if (n < 0)
                   2281:        output_multi_immediate (operands,
1.1.1.3   root     2282:                                "sub%?\t%0, %1, %2", "sub%?\t%0, %0, %2", 2,
                   2283:                                -n);
1.1       root     2284:       else
                   2285:        output_multi_immediate (operands,
1.1.1.3   root     2286:                                "add%?\t%0, %1, %2", "add%?\t%0, %0, %2", 2,
                   2287:                                n);
1.1       root     2288:     }
                   2289: 
1.1.1.3   root     2290:   return "";
                   2291: }
1.1       root     2292: 
                   2293: /* Output a multiple immediate operation.
                   2294:    OPERANDS is the vector of operands referred to in the output patterns.
                   2295:    INSTR1 is the output pattern to use for the first constant.
                   2296:    INSTR2 is the output pattern to use for subsequent constants.
                   2297:    IMMED_OP is the index of the constant slot in OPERANDS.
                   2298:    N is the constant value.  */
                   2299: 
                   2300: char *
                   2301: output_multi_immediate (operands, instr1, instr2, immed_op, n)
1.1.1.3   root     2302:      rtx *operands;
1.1       root     2303:      char *instr1, *instr2;
1.1.1.3   root     2304:      int immed_op;
                   2305:      HOST_WIDE_INT n;
1.1       root     2306: {
1.1.1.3   root     2307: #if HOST_BITS_PER_WIDE_INT > 32
                   2308:   n &= 0xffffffff;
                   2309: #endif
                   2310: 
1.1       root     2311:   if (n == 0)
                   2312:     {
                   2313:       operands[immed_op] = const0_rtx;
1.1.1.3   root     2314:       output_asm_insn (instr1, operands); /* Quick and easy output */
1.1       root     2315:     }
                   2316:   else
                   2317:     {
                   2318:       int i;
                   2319:       char *instr = instr1;
                   2320: 
                   2321:       /* Note that n is never zero here (which would give no output) */
                   2322:       for (i = 0; i < 32; i += 2)
                   2323:        {
                   2324:          if (n & (3 << i))
                   2325:            {
1.1.1.3   root     2326:              operands[immed_op] = GEN_INT (n & (255 << i));
                   2327:              output_asm_insn (instr, operands);
1.1       root     2328:              instr = instr2;
                   2329:              i += 6;
                   2330:            }
                   2331:        }
                   2332:     }
1.1.1.3   root     2333:   return "";
                   2334: }
1.1       root     2335: 
                   2336: 
                   2337: /* Return the appropriate ARM instruction for the operation code.
                   2338:    The returned result should not be overwritten.  OP is the rtx of the
                   2339:    operation.  SHIFT_FIRST_ARG is TRUE if the first argument of the operator
                   2340:    was shifted.  */
                   2341: 
                   2342: char *
                   2343: arithmetic_instr (op, shift_first_arg)
                   2344:      rtx op;
1.1.1.3   root     2345:      int shift_first_arg;
1.1       root     2346: {
1.1.1.3   root     2347:   switch (GET_CODE (op))
1.1       root     2348:     {
                   2349:     case PLUS:
1.1.1.3   root     2350:       return "add";
                   2351: 
1.1       root     2352:     case MINUS:
1.1.1.3   root     2353:       return shift_first_arg ? "rsb" : "sub";
                   2354: 
1.1       root     2355:     case IOR:
1.1.1.3   root     2356:       return "orr";
                   2357: 
1.1       root     2358:     case XOR:
1.1.1.3   root     2359:       return "eor";
                   2360: 
1.1       root     2361:     case AND:
1.1.1.3   root     2362:       return "and";
                   2363: 
1.1       root     2364:     default:
1.1.1.3   root     2365:       abort ();
1.1       root     2366:     }
1.1.1.3   root     2367: }
1.1       root     2368: 
                   2369: 
                   2370: /* Ensure valid constant shifts and return the appropriate shift mnemonic
                   2371:    for the operation code.  The returned result should not be overwritten.
                   2372:    OP is the rtx code of the shift.
1.1.1.3   root     2373:    On exit, *AMOUNTP will be -1 if the shift is by a register, or a constant
                   2374:    shift. */
1.1       root     2375: 
1.1.1.3   root     2376: static char *
                   2377: shift_op (op, amountp)
                   2378:      rtx op;
                   2379:      HOST_WIDE_INT *amountp;
1.1       root     2380: {
                   2381:   char *mnem;
1.1.1.3   root     2382:   enum rtx_code code = GET_CODE (op);
1.1       root     2383: 
1.1.1.3   root     2384:   if (GET_CODE (XEXP (op, 1)) == REG || GET_CODE (XEXP (op, 1)) == SUBREG)
                   2385:     *amountp = -1;
                   2386:   else if (GET_CODE (XEXP (op, 1)) == CONST_INT)
                   2387:     *amountp = INTVAL (XEXP (op, 1));
                   2388:   else
                   2389:     abort ();
                   2390: 
                   2391:   switch (code)
1.1       root     2392:     {
                   2393:     case ASHIFT:
                   2394:       mnem = "asl";
                   2395:       break;
1.1.1.3   root     2396: 
1.1       root     2397:     case ASHIFTRT:
                   2398:       mnem = "asr";
                   2399:       break;
1.1.1.3   root     2400: 
1.1       root     2401:     case LSHIFTRT:
                   2402:       mnem = "lsr";
                   2403:       break;
1.1.1.3   root     2404: 
                   2405:     case ROTATERT:
                   2406:       mnem = "ror";
                   2407:       break;
                   2408: 
1.1.1.2   root     2409:     case MULT:
1.1.1.3   root     2410:       /* We never have to worry about the amount being other than a
                   2411:         power of 2, since this case can never be reloaded from a reg.  */
                   2412:       if (*amountp != -1)
                   2413:        *amountp = int_log2 (*amountp);
                   2414:       else
                   2415:        abort ();
                   2416:       return "asl";
                   2417: 
1.1       root     2418:     default:
1.1.1.3   root     2419:       abort ();
1.1       root     2420:     }
                   2421: 
1.1.1.3   root     2422:   if (*amountp != -1)
1.1       root     2423:     {
1.1.1.3   root     2424:       /* This is not 100% correct, but follows from the desire to merge
                   2425:         multiplication by a power of 2 with the recognizer for a
                   2426:         shift.  >=32 is not a valid shift for "asl", so we must try and
                   2427:         output a shift that produces the correct arithmetical result.
1.1.1.4 ! root     2428:         Using lsr #32 is identical except for the fact that the carry bit
1.1.1.3   root     2429:         is not set correctly if we set the flags; but we never use the 
                   2430:         carry bit from such an operation, so we can ignore that.  */
                   2431:       if (code == ROTATERT)
                   2432:        *amountp &= 31;         /* Rotate is just modulo 32 */
                   2433:       else if (*amountp != (*amountp & 31))
                   2434:        {
                   2435:          if (code == ASHIFT)
                   2436:            mnem = "lsr";
                   2437:          *amountp = 32;
                   2438:        }
1.1       root     2439: 
1.1.1.3   root     2440:       /* Shifts of 0 are no-ops.  */
                   2441:       if (*amountp == 0)
                   2442:        return NULL;
                   2443:     }    
                   2444: 
                   2445:   return mnem;
                   2446: }
1.1       root     2447: 
                   2448: 
                   2449: /* Obtain the shift from the POWER of two. */
                   2450: 
1.1.1.3   root     2451: HOST_WIDE_INT
1.1       root     2452: int_log2 (power)
1.1.1.3   root     2453:      HOST_WIDE_INT power;
1.1       root     2454: {
1.1.1.3   root     2455:   HOST_WIDE_INT shift = 0;
1.1       root     2456: 
                   2457:   while (((1 << shift) & power) == 0)
                   2458:     {
                   2459:       if (shift > 31)
1.1.1.3   root     2460:        abort ();
1.1       root     2461:       shift++;
                   2462:     }
                   2463: 
1.1.1.3   root     2464:   return shift;
                   2465: }
1.1       root     2466: 
                   2467: /* Output a .ascii pseudo-op, keeping track of lengths.  This is because
                   2468:    /bin/as is horribly restrictive.  */
                   2469: 
                   2470: void
                   2471: output_ascii_pseudo_op (stream, p, len)
                   2472:      FILE *stream;
1.1.1.2   root     2473:      unsigned char *p;
1.1       root     2474:      int len;
                   2475: {
                   2476:   int i;
                   2477:   int len_so_far = 1000;
                   2478:   int chars_so_far = 0;
                   2479: 
                   2480:   for (i = 0; i < len; i++)
                   2481:     {
                   2482:       register int c = p[i];
                   2483: 
                   2484:       if (len_so_far > 50)
                   2485:        {
                   2486:          if (chars_so_far)
                   2487:            fputs ("\"\n", stream);
                   2488:          fputs ("\t.ascii\t\"", stream);
                   2489:          len_so_far = 0;
                   2490:          arm_increase_location (chars_so_far);
                   2491:          chars_so_far = 0;
                   2492:        }
                   2493: 
                   2494:       if (c == '\"' || c == '\\')
                   2495:        {
                   2496:          putc('\\', stream);
                   2497:          len_so_far++;
                   2498:        }
1.1.1.3   root     2499: 
1.1       root     2500:       if (c >= ' ' && c < 0177)
                   2501:        {
                   2502:          putc (c, stream);
                   2503:          len_so_far++;
                   2504:        }
                   2505:       else
                   2506:        {
                   2507:          fprintf (stream, "\\%03o", c);
                   2508:          len_so_far +=4;
                   2509:        }
1.1.1.3   root     2510: 
1.1       root     2511:       chars_so_far++;
                   2512:     }
1.1.1.3   root     2513: 
1.1       root     2514:   fputs ("\"\n", stream);
                   2515:   arm_increase_location (chars_so_far);
1.1.1.3   root     2516: }
1.1       root     2517: 
1.1.1.2   root     2518: 
                   2519: /* Try to determine whether a pattern really clobbers the link register.
                   2520:    This information is useful when peepholing, so that lr need not be pushed
                   2521:    if we combine a call followed by a return.
                   2522:    NOTE: This code does not check for side-effect expressions in a SET_SRC:
                   2523:    such a check should not be needed because these only update an existing
                   2524:    value within a register; the register must still be set elsewhere within
                   2525:    the function. */
                   2526: 
                   2527: static int
                   2528: pattern_really_clobbers_lr (x)
1.1.1.3   root     2529:      rtx x;
1.1.1.2   root     2530: {
                   2531:   int i;
                   2532:   
                   2533:   switch (GET_CODE (x))
                   2534:     {
                   2535:     case SET:
                   2536:       switch (GET_CODE (SET_DEST (x)))
                   2537:        {
                   2538:        case REG:
                   2539:          return REGNO (SET_DEST (x)) == 14;
1.1.1.3   root     2540: 
1.1.1.2   root     2541:         case SUBREG:
                   2542:          if (GET_CODE (XEXP (SET_DEST (x), 0)) == REG)
                   2543:            return REGNO (XEXP (SET_DEST (x), 0)) == 14;
1.1.1.3   root     2544: 
1.1.1.2   root     2545:          if (GET_CODE (XEXP (SET_DEST (x), 0)) == MEM)
                   2546:            return 0;
                   2547:          abort ();
1.1.1.3   root     2548: 
1.1.1.2   root     2549:         default:
                   2550:          return 0;
                   2551:         }
1.1.1.3   root     2552: 
1.1.1.2   root     2553:     case PARALLEL:
                   2554:       for (i = 0; i < XVECLEN (x, 0); i++)
                   2555:        if (pattern_really_clobbers_lr (XVECEXP (x, 0, i)))
                   2556:          return 1;
                   2557:       return 0;
1.1.1.3   root     2558: 
1.1.1.2   root     2559:     case CLOBBER:
                   2560:       switch (GET_CODE (XEXP (x, 0)))
                   2561:         {
                   2562:        case REG:
                   2563:          return REGNO (XEXP (x, 0)) == 14;
1.1.1.3   root     2564: 
1.1.1.2   root     2565:         case SUBREG:
                   2566:          if (GET_CODE (XEXP (XEXP (x, 0), 0)) == REG)
                   2567:            return REGNO (XEXP (XEXP (x, 0), 0)) == 14;
                   2568:          abort ();
1.1.1.3   root     2569: 
1.1.1.2   root     2570:         default:
                   2571:          return 0;
                   2572:         }
1.1.1.3   root     2573: 
1.1.1.2   root     2574:     case UNSPEC:
                   2575:       return 1;
1.1.1.3   root     2576: 
1.1.1.2   root     2577:     default:
                   2578:       return 0;
                   2579:     }
                   2580: }
                   2581: 
                   2582: static int
                   2583: function_really_clobbers_lr (first)
1.1.1.3   root     2584:      rtx first;
1.1.1.2   root     2585: {
                   2586:   rtx insn, next;
                   2587:   
                   2588:   for (insn = first; insn; insn = next_nonnote_insn (insn))
                   2589:     {
                   2590:       switch (GET_CODE (insn))
                   2591:         {
                   2592:        case BARRIER:
                   2593:        case NOTE:
                   2594:        case CODE_LABEL:
                   2595:        case JUMP_INSN:         /* Jump insns only change the PC (and conds) */
                   2596:        case INLINE_HEADER:
                   2597:          break;
1.1.1.3   root     2598: 
1.1.1.2   root     2599:         case INSN:
                   2600:          if (pattern_really_clobbers_lr (PATTERN (insn)))
                   2601:            return 1;
                   2602:          break;
1.1.1.3   root     2603: 
1.1.1.2   root     2604:         case CALL_INSN:
                   2605:          /* Don't yet know how to handle those calls that are not to a 
                   2606:             SYMBOL_REF */
                   2607:          if (GET_CODE (PATTERN (insn)) != PARALLEL)
                   2608:            abort ();
1.1.1.3   root     2609: 
1.1.1.2   root     2610:          switch (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)))
                   2611:            {
                   2612:            case CALL:
                   2613:              if (GET_CODE (XEXP (XEXP (XVECEXP (PATTERN (insn), 0, 0), 0), 0))
                   2614:                  != SYMBOL_REF)
                   2615:                return 1;
                   2616:              break;
1.1.1.3   root     2617: 
1.1.1.2   root     2618:            case SET:
                   2619:              if (GET_CODE (XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (insn),
                   2620:                                                          0, 0)), 0), 0))
                   2621:                  != SYMBOL_REF)
                   2622:                return 1;
                   2623:              break;
1.1.1.3   root     2624: 
1.1.1.2   root     2625:            default:    /* Don't recognize it, be safe */
                   2626:              return 1;
                   2627:            }
1.1.1.3   root     2628: 
1.1.1.2   root     2629:          /* A call can be made (by peepholing) not to clobber lr iff it is
                   2630:             followed by a return.  There may, however, be a use insn iff
                   2631:             we are returning the result of the call. 
                   2632:             If we run off the end of the insn chain, then that means the
                   2633:             call was at the end of the function.  Unfortunately we don't
                   2634:             have a return insn for the peephole to recognize, so we
                   2635:             must reject this.  (Can this be fixed by adding our own insn?) */
                   2636:          if ((next = next_nonnote_insn (insn)) == NULL)
                   2637:            return 1;
1.1.1.3   root     2638: 
1.1.1.2   root     2639:          if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == USE
                   2640:              && (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
                   2641:              && (REGNO (SET_DEST (XVECEXP (PATTERN (insn), 0, 0)))
                   2642:                  == REGNO (XEXP (PATTERN (next), 0))))
                   2643:            if ((next = next_nonnote_insn (next)) == NULL)
                   2644:              return 1;
1.1.1.3   root     2645: 
1.1.1.2   root     2646:          if (GET_CODE (next) == JUMP_INSN
                   2647:              && GET_CODE (PATTERN (next)) == RETURN)
                   2648:            break;
                   2649:          return 1;
1.1.1.3   root     2650: 
1.1.1.2   root     2651:         default:
                   2652:          abort ();
                   2653:         }
                   2654:     }
1.1.1.3   root     2655: 
1.1.1.2   root     2656:   /* We have reached the end of the chain so lr was _not_ clobbered */
                   2657:   return 0;
                   2658: }
                   2659: 
                   2660: char *
                   2661: output_return_instruction (operand, really_return)
1.1.1.3   root     2662:      rtx operand;
                   2663:      int really_return;
1.1.1.2   root     2664: {
                   2665:   char instr[100];
                   2666:   int reg, live_regs = 0;
1.1.1.3   root     2667:   int volatile_func = (optimize > 0 
                   2668:                       && TREE_THIS_VOLATILE (current_function_decl));
                   2669: 
                   2670:   return_used_this_function = 1;
1.1.1.2   root     2671: 
1.1.1.3   root     2672:   if (volatile_func)
                   2673:     {
                   2674:       rtx ops[2];
                   2675:       /* If this function was declared non-returning, and we have found a tail 
                   2676:         call, then we have to trust that the called function won't return. */
                   2677:       if (! really_return)
                   2678:        return "";
                   2679: 
                   2680:       /* Otherwise, trap an attempted return by aborting. */
                   2681:       ops[0] = operand;
                   2682:       ops[1] = gen_rtx (SYMBOL_REF, Pmode, "abort");
                   2683:       output_asm_insn ("bl%d0\t%a1", ops);
                   2684:       return "";
                   2685:     }
                   2686:       
                   2687:   if (current_function_calls_alloca && ! really_return)
1.1.1.2   root     2688:     abort();
                   2689:     
1.1.1.3   root     2690:   for (reg = 0; reg <= 10; reg++)
                   2691:     if (regs_ever_live[reg] && ! call_used_regs[reg])
1.1.1.2   root     2692:       live_regs++;
                   2693: 
1.1.1.3   root     2694:   if (live_regs || (regs_ever_live[14] && ! lr_save_eliminated))
1.1.1.2   root     2695:     live_regs++;
                   2696: 
                   2697:   if (frame_pointer_needed)
                   2698:     live_regs += 4;
                   2699: 
                   2700:   if (live_regs)
                   2701:     {
1.1.1.3   root     2702:       if (lr_save_eliminated || ! regs_ever_live[14])
1.1.1.2   root     2703:         live_regs++;
1.1.1.3   root     2704: 
1.1.1.2   root     2705:       if (frame_pointer_needed)
1.1.1.3   root     2706:         strcpy (instr, "ldm%?%d0ea\t%|fp, {");
1.1.1.2   root     2707:       else
1.1.1.3   root     2708:         strcpy (instr, "ldm%?%d0fd\t%|sp!, {");
                   2709: 
                   2710:       for (reg = 0; reg <= 10; reg++)
                   2711:         if (regs_ever_live[reg] && ! call_used_regs[reg])
1.1.1.2   root     2712:           {
1.1.1.3   root     2713:            strcat (instr, "%|");
1.1.1.2   root     2714:             strcat (instr, reg_names[reg]);
                   2715:            if (--live_regs)
                   2716:               strcat (instr, ", ");
                   2717:           }
1.1.1.3   root     2718: 
1.1.1.2   root     2719:       if (frame_pointer_needed)
                   2720:         {
1.1.1.3   root     2721:          strcat (instr, "%|");
1.1.1.2   root     2722:           strcat (instr, reg_names[11]);
                   2723:           strcat (instr, ", ");
1.1.1.3   root     2724:          strcat (instr, "%|");
1.1.1.2   root     2725:           strcat (instr, reg_names[13]);
                   2726:           strcat (instr, ", ");
1.1.1.3   root     2727:          strcat (instr, "%|");
1.1.1.2   root     2728:           strcat (instr, really_return ? reg_names[15] : reg_names[14]);
                   2729:         }
                   2730:       else
1.1.1.3   root     2731:        {
                   2732:          strcat (instr, "%|");
                   2733:          strcat (instr, really_return ? reg_names[15] : reg_names[14]);
                   2734:        }
1.1.1.2   root     2735:       strcat (instr, (TARGET_6 || !really_return) ? "}" : "}^");
1.1.1.3   root     2736:       output_asm_insn (instr, &operand);
1.1.1.2   root     2737:     }
                   2738:   else if (really_return)
                   2739:     {
1.1.1.3   root     2740:       strcpy (instr,
                   2741:              TARGET_6 ? "mov%?%d0\t%|pc, lr" : "mov%?%d0s\t%|pc, %|lr");
                   2742:       output_asm_insn (instr, &operand);
1.1.1.2   root     2743:     }
1.1.1.3   root     2744: 
1.1.1.2   root     2745:   return "";
                   2746: }
                   2747: 
1.1.1.4 ! root     2748: /* Return nonzero if optimizing and the current function is volatile.
        !          2749:    Such functions never return, and many memory cycles can be saved
        !          2750:    by not storing register values that will never be needed again.
        !          2751:    This optimization was added to speed up context switching in a
        !          2752:    kernel application. */
        !          2753: 
1.1.1.3   root     2754: int
                   2755: arm_volatile_func ()
                   2756: {
                   2757:   return (optimize > 0 && TREE_THIS_VOLATILE (current_function_decl));
                   2758: }
                   2759: 
                   2760: /* Return the size of the prologue.  It's not too bad if we slightly 
                   2761:    over-estimate.  */
                   2762: 
                   2763: static int
                   2764: get_prologue_size ()
                   2765: {
                   2766:   return profile_flag ? 12 : 0;
                   2767: }
                   2768: 
1.1.1.2   root     2769: /* The amount of stack adjustment that happens here, in output_return and in
                   2770:    output_epilogue must be exactly the same as was calculated during reload,
                   2771:    or things will point to the wrong place.  The only time we can safely
                   2772:    ignore this constraint is when a function has no arguments on the stack,
                   2773:    no stack frame requirement and no live registers execpt for `lr'.  If we
                   2774:    can guarantee that by making all function calls into tail calls and that
                   2775:    lr is not clobbered in any other way, then there is no need to push lr
                   2776:    onto the stack. */
                   2777:    
1.1       root     2778: void
1.1.1.3   root     2779: output_func_prologue (f, frame_size)
1.1       root     2780:      FILE *f;
                   2781:      int frame_size;
                   2782: {
1.1.1.3   root     2783:   int reg, live_regs_mask = 0;
1.1       root     2784:   rtx operands[3];
1.1.1.3   root     2785:   int volatile_func = (optimize > 0
                   2786:                       && TREE_THIS_VOLATILE (current_function_decl));
1.1       root     2787: 
                   2788:   /* Nonzero if we must stuff some register arguments onto the stack as if
                   2789:      they were passed there.  */
                   2790:   int store_arg_regs = 0;
                   2791: 
1.1.1.2   root     2792:   if (arm_ccfsm_state || arm_target_insn)
                   2793:     abort ();                                  /* Sanity check */
                   2794:   
                   2795:   return_used_this_function = 0;
                   2796:   lr_save_eliminated = 0;
                   2797:   
1.1.1.4 ! root     2798:   fprintf (f, "\t%s args = %d, pretend = %d, frame = %d\n",
        !          2799:           ASM_COMMENT_START, current_function_args_size,
1.1.1.3   root     2800:           current_function_pretend_args_size, frame_size);
1.1.1.4 ! root     2801:   fprintf (f, "\t%s frame_needed = %d, current_function_anonymous_args = %d\n",
        !          2802:           ASM_COMMENT_START, frame_pointer_needed,
1.1.1.3   root     2803:           current_function_anonymous_args);
                   2804: 
                   2805:   if (volatile_func)
1.1.1.4 ! root     2806:     fprintf (f, "\t%s Volatile function.\n", ASM_COMMENT_START);
1.1       root     2807: 
                   2808:   if (current_function_anonymous_args && current_function_pretend_args_size)
                   2809:     store_arg_regs = 1;
                   2810: 
1.1.1.3   root     2811:   for (reg = 0; reg <= 10; reg++)
                   2812:     if (regs_ever_live[reg] && ! call_used_regs[reg])
1.1       root     2813:       live_regs_mask |= (1 << reg);
                   2814: 
1.1.1.2   root     2815:   if (frame_pointer_needed)
1.1.1.3   root     2816:     live_regs_mask |= 0xD800;
1.1       root     2817:   else if (regs_ever_live[14])
1.1.1.2   root     2818:     {
                   2819:       if (! current_function_args_size
1.1.1.3   root     2820:          && ! function_really_clobbers_lr (get_insns ()))
                   2821:        lr_save_eliminated = 1;
1.1.1.2   root     2822:       else
                   2823:         live_regs_mask |= 0x4000;
                   2824:     }
1.1       root     2825: 
                   2826:   if (live_regs_mask)
                   2827:     {
1.1.1.2   root     2828:       /* if a di mode load/store multiple is used, and the base register
                   2829:         is r3, then r4 can become an ever live register without lr
                   2830:         doing so,  in this case we need to push lr as well, or we
                   2831:         will fail to get a proper return. */
                   2832: 
                   2833:       live_regs_mask |= 0x4000;
                   2834:       lr_save_eliminated = 0;
1.1       root     2835: 
                   2836:     }
                   2837: 
1.1.1.3   root     2838:   if (lr_save_eliminated)
1.1.1.4 ! root     2839:     fprintf (f,"\t%s I don't think this function clobbers lr\n",
        !          2840:             ASM_COMMENT_START);
1.1.1.3   root     2841: }
1.1       root     2842: 
                   2843: 
                   2844: void
1.1.1.3   root     2845: output_func_epilogue (f, frame_size)
1.1       root     2846:      FILE *f;
                   2847:      int frame_size;
                   2848: {
1.1.1.2   root     2849:   int reg, live_regs_mask = 0, code_size = 0;
                   2850:   /* If we need this then it will always be at lesat this much */
                   2851:   int floats_offset = 24;
1.1       root     2852:   rtx operands[3];
1.1.1.3   root     2853:   int volatile_func = (optimize > 0
                   2854:                       && TREE_THIS_VOLATILE (current_function_decl));
1.1       root     2855: 
1.1.1.2   root     2856:   if (use_return_insn() && return_used_this_function)
1.1       root     2857:     {
1.1.1.2   root     2858:       if (frame_size && !(frame_pointer_needed || TARGET_APCS))
                   2859:         {
                   2860:           abort ();
                   2861:         }
1.1.1.3   root     2862:       goto epilogue_done;
                   2863:     }
                   2864: 
                   2865:   /* A volatile function should never return.  Call abort.  */
                   2866:   if (volatile_func)
                   2867:     {
                   2868:       rtx op = gen_rtx (SYMBOL_REF, Pmode, "abort");
                   2869:       output_asm_insn ("bl\t%a0", &op);
                   2870:       code_size = 4;
                   2871:       goto epilogue_done;
1.1       root     2872:     }
                   2873: 
1.1.1.3   root     2874:   for (reg = 0; reg <= 10; reg++)
                   2875:     if (regs_ever_live[reg] && ! call_used_regs[reg])
1.1       root     2876:       {
1.1.1.2   root     2877:         live_regs_mask |= (1 << reg);
                   2878:        floats_offset += 4;
1.1       root     2879:       }
                   2880: 
1.1.1.2   root     2881:   if (frame_pointer_needed)
1.1       root     2882:     {
1.1.1.3   root     2883:       for (reg = 23; reg > 15; reg--)
                   2884:        if (regs_ever_live[reg] && ! call_used_regs[reg])
1.1.1.2   root     2885:          {
1.1.1.4 ! root     2886:            fprintf (f, "\tldfe\t%s%s, [%sfp, #-%d]\n", REGISTER_PREFIX,
        !          2887:                     reg_names[reg], REGISTER_PREFIX, floats_offset);
1.1.1.2   root     2888:            floats_offset += 12;
                   2889:            code_size += 4;
                   2890:          }
                   2891: 
                   2892:       live_regs_mask |= 0xA800;
1.1.1.3   root     2893:       print_multi_reg (f, "ldmea\t%sfp", live_regs_mask,
1.1.1.2   root     2894:                       TARGET_6 ? FALSE : TRUE);
1.1       root     2895:       code_size += 4;
                   2896:     }
                   2897:   else
                   2898:     {
                   2899:       /* Restore stack pointer if necessary.  */
                   2900:       if (frame_size)
                   2901:        {
                   2902:          operands[0] = operands[1] = stack_pointer_rtx;
                   2903:          operands[2] = gen_rtx (CONST_INT, VOIDmode, frame_size);
                   2904:          output_add_immediate (operands);
                   2905:        }
                   2906: 
1.1.1.3   root     2907:       for (reg = 16; reg < 24; reg++)
                   2908:        if (regs_ever_live[reg] && ! call_used_regs[reg])
1.1.1.2   root     2909:          {
1.1.1.4 ! root     2910:            fprintf (f, "\tldfe\t%s%s, [%ssp], #12\n", REGISTER_PREFIX,
        !          2911:                     reg_names[reg], REGISTER_PREFIX);
1.1.1.2   root     2912:            code_size += 4;
                   2913:          }
1.1       root     2914:       if (current_function_pretend_args_size == 0 && regs_ever_live[14])
                   2915:        {
1.1.1.3   root     2916:          print_multi_reg (f, "ldmfd\t%ssp!", live_regs_mask | 0x8000,
1.1.1.2   root     2917:                           TARGET_6 ? FALSE : TRUE);
1.1       root     2918:          code_size += 4;
                   2919:        }
                   2920:       else
                   2921:        {
1.1.1.2   root     2922:          if (live_regs_mask || regs_ever_live[14])
1.1       root     2923:            {
1.1.1.2   root     2924:              live_regs_mask |= 0x4000;
1.1.1.3   root     2925:              print_multi_reg (f, "ldmfd\t%ssp!", live_regs_mask, FALSE);
1.1       root     2926:              code_size += 4;
                   2927:            }
                   2928:          if (current_function_pretend_args_size)
                   2929:            {
                   2930:              operands[0] = operands[1] = stack_pointer_rtx;
                   2931:              operands[2] = gen_rtx (CONST_INT, VOIDmode,
                   2932:                                     current_function_pretend_args_size);
                   2933:              output_add_immediate (operands);
                   2934:            }
1.1.1.3   root     2935:          fprintf (f,
                   2936:                   TARGET_6 ? "\tmov\t%spc, %slr\n" : "\tmovs\t%spc, %slr\n",
1.1.1.4 ! root     2937:                   REGISTER_PREFIX, REGISTER_PREFIX, f);
1.1       root     2938:          code_size += 4;
                   2939:        }
                   2940:     }
1.1.1.3   root     2941: 
                   2942:  epilogue_done:
                   2943: 
                   2944:   /* insn_addresses isn't allocated when not optimizing */
                   2945: 
                   2946:   if (optimize > 0)
                   2947:     arm_increase_location (code_size
                   2948:                           + insn_addresses[INSN_UID (get_last_insn ())]
                   2949:                           + get_prologue_size ());
                   2950: 
1.1       root     2951:   current_function_anonymous_args = 0;
1.1.1.3   root     2952: }
                   2953: 
                   2954: static void
                   2955: emit_multi_reg_push (mask)
                   2956:      int mask;
                   2957: {
                   2958:   int num_regs = 0;
                   2959:   int i, j;
                   2960:   rtx par;
                   2961: 
                   2962:   for (i = 0; i < 16; i++)
                   2963:     if (mask & (1 << i))
                   2964:       num_regs++;
                   2965: 
                   2966:   if (num_regs == 0 || num_regs > 16)
                   2967:     abort ();
                   2968: 
                   2969:   par = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (num_regs));
                   2970: 
                   2971:   for (i = 0; i < 16; i++)
                   2972:     {
                   2973:       if (mask & (1 << i))
                   2974:        {
                   2975:          XVECEXP (par, 0, 0)
                   2976:            = gen_rtx (SET, VOIDmode, gen_rtx (MEM, BLKmode,
                   2977:                                               gen_rtx (PRE_DEC, BLKmode,
                   2978:                                                        stack_pointer_rtx)),
                   2979:                       gen_rtx (UNSPEC, BLKmode,
                   2980:                                gen_rtvec (1, gen_rtx (REG, SImode, i)),
                   2981:                                2));
                   2982:          break;
                   2983:        }
                   2984:     }
                   2985: 
                   2986:   for (j = 1, i++; j < num_regs; i++)
                   2987:     {
                   2988:       if (mask & (1 << i))
                   2989:        {
                   2990:          XVECEXP (par, 0, j)
                   2991:            = gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, i));
                   2992:          j++;
                   2993:        }
                   2994:     }
                   2995:   emit_insn (par);
                   2996: }
                   2997: 
                   2998: void
                   2999: arm_expand_prologue ()
                   3000: {
                   3001:   int reg;
                   3002:   rtx amount = GEN_INT (- get_frame_size ());
                   3003:   rtx push_insn;
                   3004:   int num_regs;
                   3005:   int live_regs_mask = 0;
                   3006:   int store_arg_regs = 0;
                   3007:   int volatile_func = (optimize > 0
                   3008:                       && TREE_THIS_VOLATILE (current_function_decl));
                   3009: 
                   3010:   if (current_function_anonymous_args && current_function_pretend_args_size)
                   3011:     store_arg_regs = 1;
                   3012: 
                   3013:   if (! volatile_func)
                   3014:     for (reg = 0; reg <= 10; reg++)
                   3015:       if (regs_ever_live[reg] && ! call_used_regs[reg])
                   3016:        live_regs_mask |= 1 << reg;
                   3017: 
                   3018:   if (! volatile_func && regs_ever_live[14])
                   3019:     live_regs_mask |= 0x4000;
                   3020: 
                   3021:   if (frame_pointer_needed)
                   3022:     {
                   3023:       live_regs_mask |= 0xD800;
                   3024:       emit_insn (gen_movsi (gen_rtx (REG, SImode, 12),
                   3025:                            stack_pointer_rtx));
                   3026:     }
                   3027: 
                   3028:   if (current_function_pretend_args_size)
                   3029:     {
                   3030:       if (store_arg_regs)
                   3031:        emit_multi_reg_push ((0xf0 >> (current_function_pretend_args_size / 4))
                   3032:                             & 0xf);
                   3033:       else
                   3034:        emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, 
                   3035:                               GEN_INT (-current_function_pretend_args_size)));
                   3036:     }
                   3037: 
                   3038:   if (live_regs_mask)
                   3039:     {
                   3040:       /* If we have to push any regs, then we must push lr as well, or
1.1.1.4 ! root     3041:         we won't get a proper return.  */
1.1.1.3   root     3042:       live_regs_mask |= 0x4000;
                   3043:       emit_multi_reg_push (live_regs_mask);
                   3044:     }
                   3045:       
                   3046:   /* For now the integer regs are still pushed in output_func_epilogue ().  */
                   3047: 
                   3048:   if (! volatile_func)
                   3049:     for (reg = 23; reg > 15; reg--)
                   3050:       if (regs_ever_live[reg] && ! call_used_regs[reg])
                   3051:        emit_insn (gen_rtx (SET, VOIDmode, 
                   3052:                            gen_rtx (MEM, XFmode, 
                   3053:                                     gen_rtx (PRE_DEC, XFmode,
                   3054:                                              stack_pointer_rtx)),
                   3055:                            gen_rtx (REG, XFmode, reg)));
                   3056: 
                   3057:   if (frame_pointer_needed)
                   3058:     emit_insn (gen_addsi3 (hard_frame_pointer_rtx, gen_rtx (REG, SImode, 12),
                   3059:                           (GEN_INT
                   3060:                            (-(4 + current_function_pretend_args_size)))));
                   3061: 
                   3062:   if (amount != const0_rtx)
                   3063:     {
                   3064:       emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, amount));
                   3065:       emit_insn (gen_rtx (CLOBBER, VOIDmode, 
                   3066:                          gen_rtx (MEM, BLKmode, stack_pointer_rtx)));
                   3067:     }
                   3068: 
                   3069:   /* If we are profiling, make sure no instructions are scheduled before
                   3070:      the call to mcount.  */
                   3071:   if (profile_flag || profile_block_flag)
                   3072:     emit_insn (gen_blockage ());
                   3073: }
                   3074:   
1.1       root     3075: 
1.1.1.3   root     3076: /* If CODE is 'd', then the X is a condition operand and the instruction
                   3077:    should only be executed if the condition is true.
1.1.1.4 ! root     3078:    if CODE is 'D', then the X is a condition operand and the instruction
1.1.1.3   root     3079:    should only be executed if the condition is false: however, if the mode
                   3080:    of the comparison is CCFPEmode, then always execute the instruction -- we
                   3081:    do this because in these circumstances !GE does not necessarily imply LT;
                   3082:    in these cases the instruction pattern will take care to make sure that
                   3083:    an instruction containing %d will follow, thereby undoing the effects of
1.1.1.4 ! root     3084:    doing this instruction unconditionally.
1.1.1.3   root     3085:    If CODE is 'N' then X is a floating point operand that must be negated
                   3086:    before output.
                   3087:    If CODE is 'B' then output a bitwise inverted value of X (a const int).
                   3088:    If X is a REG and CODE is `M', output a ldm/stm style multi-reg.  */
                   3089: 
                   3090: void
                   3091: arm_print_operand (stream, x, code)
                   3092:      FILE *stream;
                   3093:      rtx x;
                   3094:      int code;
                   3095: {
                   3096:   switch (code)
                   3097:     {
                   3098:     case '@':
1.1.1.4 ! root     3099:       fputs (ASM_COMMENT_START, stream);
1.1.1.3   root     3100:       return;
                   3101: 
                   3102:     case '|':
1.1.1.4 ! root     3103:       fputs (REGISTER_PREFIX, stream);
1.1.1.3   root     3104:       return;
                   3105: 
                   3106:     case '?':
                   3107:       if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4)
                   3108:        fputs (arm_condition_codes[arm_current_cc], stream);
                   3109:       return;
                   3110: 
                   3111:     case 'N':
                   3112:       {
                   3113:        REAL_VALUE_TYPE r;
                   3114:        REAL_VALUE_FROM_CONST_DOUBLE (r, x);
                   3115:        r = REAL_VALUE_NEGATE (r);
                   3116:        fprintf (stream, "%s", fp_const_from_val (&r));
                   3117:       }
                   3118:       return;
                   3119: 
                   3120:     case 'B':
                   3121:       if (GET_CODE (x) == CONST_INT)
                   3122:        fprintf (stream,
                   3123: #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
                   3124:                 "%d",
                   3125: #else
                   3126:                 "%ld",
                   3127: #endif
                   3128:                 ARM_SIGN_EXTEND (~ INTVAL (x)));
                   3129:       else
                   3130:        {
                   3131:          putc ('~', stream);
                   3132:          output_addr_const (stream, x);
                   3133:        }
                   3134:       return;
                   3135: 
                   3136:     case 'i':
                   3137:       fprintf (stream, "%s", arithmetic_instr (x, 1));
                   3138:       return;
                   3139: 
                   3140:     case 'I':
                   3141:       fprintf (stream, "%s", arithmetic_instr (x, 0));
                   3142:       return;
                   3143: 
                   3144:     case 'S':
                   3145:       {
                   3146:        HOST_WIDE_INT val;
                   3147:        char *shift = shift_op (x, &val);
                   3148: 
                   3149:        if (shift)
                   3150:          {
                   3151:            fprintf (stream, ", %s ", shift_op (x, &val));
                   3152:            if (val == -1)
                   3153:              arm_print_operand (stream, XEXP (x, 1), 0);
                   3154:            else
                   3155:              fprintf (stream,
                   3156: #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
                   3157:                       "#%d",
                   3158: #else
                   3159:                       "#%ld",
                   3160: #endif
                   3161:                       val);
                   3162:          }
                   3163:       }
                   3164:       return;
                   3165: 
                   3166:     case 'R':
                   3167:       if (REGNO (x) > 15)
                   3168:        abort ();
1.1.1.4 ! root     3169:       fputs (REGISTER_PREFIX, stream);
1.1.1.3   root     3170:       fputs (reg_names[REGNO (x) + 1], stream);
                   3171:       return;
                   3172: 
                   3173:     case 'm':
1.1.1.4 ! root     3174:       fputs (REGISTER_PREFIX, stream);
1.1.1.3   root     3175:       if (GET_CODE (XEXP (x, 0)) == REG)
                   3176:        fputs (reg_names[REGNO (XEXP (x, 0))], stream);
                   3177:       else
                   3178:        fputs (reg_names[REGNO (XEXP (XEXP (x, 0), 0))], stream);
                   3179:       return;
                   3180: 
                   3181:     case 'M':
1.1.1.4 ! root     3182:       fprintf (stream, "{%s%s-%s%s}", REGISTER_PREFIX, reg_names[REGNO (x)],
        !          3183:               REGISTER_PREFIX, reg_names[REGNO (x) - 1
1.1.1.3   root     3184:                                         + ((GET_MODE_SIZE (GET_MODE (x))
                   3185:                                             + GET_MODE_SIZE (SImode) - 1)
                   3186:                                            / GET_MODE_SIZE (SImode))]);
                   3187:       return;
                   3188: 
                   3189:     case 'd':
                   3190:       if (x)
                   3191:         fputs (arm_condition_codes[get_arm_condition_code (x)],
                   3192:               stream);
                   3193:       return;
                   3194: 
                   3195:     case 'D':
                   3196:       if (x && (flag_fast_math
                   3197:                || GET_CODE (x) == EQ || GET_CODE (x) == NE
                   3198:                || (GET_MODE (XEXP (x, 0)) != CCFPEmode
                   3199:                    && (GET_MODE_CLASS (GET_MODE (XEXP (x, 0)))
                   3200:                        != MODE_FLOAT))))
                   3201:         fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE
                   3202:                                   (get_arm_condition_code (x))],
                   3203:               stream);
                   3204:       return;
                   3205: 
                   3206:     default:
                   3207:       if (x == 0)
                   3208:        abort ();
                   3209: 
                   3210:       if (GET_CODE (x) == REG)
                   3211:        {
1.1.1.4 ! root     3212:          fputs (REGISTER_PREFIX, stream);
1.1.1.3   root     3213:          fputs (reg_names[REGNO (x)], stream);
                   3214:        }
                   3215:       else if (GET_CODE (x) == MEM)
                   3216:        {
                   3217:          output_memory_reference_mode = GET_MODE (x);
                   3218:          output_address (XEXP (x, 0));
                   3219:        }
                   3220:       else if (GET_CODE (x) == CONST_DOUBLE)
                   3221:        fprintf (stream, "#%s", fp_immediate_constant (x));
                   3222:       else if (GET_CODE (x) == NEG)
                   3223:        abort (); /* This should never happen now. */
                   3224:       else
                   3225:        {
                   3226:          fputc ('#', stream);
                   3227:          output_addr_const (stream, x);
                   3228:        }
                   3229:     }
                   3230: }
                   3231: 
1.1       root     3232: /* Increase the `arm_text_location' by AMOUNT if we're in the text
                   3233:    segment.  */
                   3234: 
                   3235: void
                   3236: arm_increase_location (amount)
                   3237:      int amount;
                   3238: {
                   3239:   if (in_text_section ())
                   3240:     arm_text_location += amount;
1.1.1.3   root     3241: }
1.1       root     3242: 
                   3243: 
                   3244: /* Output a label definition.  If this label is within the .text segment, it
                   3245:    is stored in OFFSET_TABLE, to be used when building `llc' instructions.
                   3246:    Maybe GCC remembers names not starting with a `*' for a long time, but this
                   3247:    is a minority anyway, so we just make a copy.  Do not store the leading `*'
                   3248:    if the name starts with one.  */
                   3249: 
                   3250: void
                   3251: arm_asm_output_label (stream, name)
                   3252:      FILE *stream;
                   3253:      char *name;
                   3254: {
                   3255:   char *real_name, *s;
                   3256:   struct label_offset *cur;
                   3257:   int hash = 0;
                   3258: 
                   3259:   assemble_name (stream, name);
                   3260:   fputs (":\n", stream);
                   3261:   if (! in_text_section ())
                   3262:     return;
                   3263: 
                   3264:   if (name[0] == '*')
                   3265:     {
                   3266:       real_name = xmalloc (1 + strlen (&name[1]));
                   3267:       strcpy (real_name, &name[1]);
                   3268:     }
                   3269:   else
                   3270:     {
                   3271:       real_name = xmalloc (2 + strlen (name));
1.1.1.4 ! root     3272:       strcpy (real_name, USER_LABEL_PREFIX);
1.1       root     3273:       strcat (real_name, name);
                   3274:     }
                   3275:   for (s = real_name; *s; s++)
                   3276:     hash += *s;
1.1.1.3   root     3277: 
1.1       root     3278:   hash = hash % LABEL_HASH_SIZE;
                   3279:   cur = (struct label_offset *) xmalloc (sizeof (struct label_offset));
                   3280:   cur->name = real_name;
                   3281:   cur->offset = arm_text_location;
                   3282:   cur->cdr = offset_table[hash];
                   3283:   offset_table[hash] = cur;
1.1.1.3   root     3284: }
1.1       root     3285: 
1.1.1.3   root     3286: /* Load a symbol that is known to be in the text segment into a register.
                   3287:    This should never be called when not optimizing.  */
1.1       root     3288: 
                   3289: char *
1.1.1.3   root     3290: output_load_symbol (insn, operands)
                   3291:      rtx insn;
1.1       root     3292:      rtx *operands;
                   3293: {
1.1.1.3   root     3294:   char *s;
                   3295:   char *name = XSTR (operands[1], 0);
1.1.1.2   root     3296:   struct label_offset *he;
                   3297:   int hash = 0;
                   3298:   int offset;
1.1.1.3   root     3299:   unsigned int mask, never_mask = 0xffffffff;
                   3300:   int shift, inst;
                   3301:   char buffer[100];
                   3302: 
                   3303:   if (optimize == 0 || *name != '*')
1.1.1.2   root     3304:     abort ();
                   3305: 
                   3306:   for (s = &name[1]; *s; s++)
                   3307:     hash += *s;
1.1.1.3   root     3308: 
1.1.1.2   root     3309:   hash = hash % LABEL_HASH_SIZE;
                   3310:   he = offset_table[hash];
                   3311:   while (he && strcmp (he->name, &name[1]))
                   3312:     he = he->cdr;
                   3313:   
                   3314:   if (!he)
                   3315:     abort ();
                   3316:   
1.1.1.3   root     3317:   offset = (arm_text_location + insn_addresses[INSN_UID (insn)]
                   3318:            + get_prologue_size () + 8 - he->offset);
1.1.1.2   root     3319:   if (offset < 0)
                   3320:     abort ();
                   3321: 
1.1.1.3   root     3322:   /* When generating the instructions, we never mask out the bits that we
1.1.1.4 ! root     3323:      think will be always zero, then if a mistake has occurred somewhere, the
1.1.1.3   root     3324:      assembler will spot it and generate an error.  */
                   3325: 
1.1.1.2   root     3326:   /* If the symbol is word aligned then we might be able to reduce the
1.1.1.3   root     3327:      number of loads.  */
                   3328:   shift = ((offset & 3) == 0) ? 2 : 0;
                   3329: 
                   3330:   /* Clear the bits from NEVER_MASK that will be orred in with the individual
                   3331:      instructions.  */
                   3332:   for (; shift < 32; shift += 8)
1.1.1.2   root     3333:     {
1.1.1.3   root     3334:       mask = 0xff << shift;
                   3335:       if ((offset & mask) || ((unsigned) offset) > mask)
                   3336:        never_mask &= ~mask;
1.1.1.2   root     3337:     }
1.1.1.3   root     3338: 
                   3339:   inst = 8;
                   3340:   mask = 0xff << (shift - 32);
                   3341: 
                   3342:   while (mask && (never_mask & mask) == 0)
1.1.1.2   root     3343:     {
1.1.1.3   root     3344:       if (inst == 8)
                   3345:        {
                   3346:          strcpy (buffer, "sub%?\t%0, %|pc, #(8 + . -%a1)");
                   3347:          if ((never_mask | mask) != 0xffffffff)
                   3348:            sprintf (buffer + strlen (buffer), " & 0x%x", mask | never_mask);
                   3349:        }
                   3350:       else
                   3351:        sprintf (buffer, "sub%%?\t%%0, %%0, #(%d + . -%%a1) & 0x%x",
                   3352:                 inst, mask | never_mask);
                   3353: 
                   3354:       output_asm_insn (buffer, operands);
                   3355:       mask <<= 8;
                   3356:       inst -= 4;
1.1.1.2   root     3357:     }
1.1.1.3   root     3358: 
1.1.1.2   root     3359:   return "";
                   3360: }
1.1       root     3361: 
                   3362: /* Output code resembling an .lcomm directive.  /bin/as doesn't have this
                   3363:    directive hence this hack, which works by reserving some `.space' in the
                   3364:    bss segment directly.
                   3365: 
                   3366:    XXX This is a severe hack, which is guaranteed NOT to work since it doesn't
                   3367:    define STATIC COMMON space but merely STATIC BSS space.  */
                   3368: 
                   3369: void
                   3370: output_lcomm_directive (stream, name, size, rounded)
                   3371:      FILE *stream;
                   3372:      char *name;
                   3373:      int size, rounded;
                   3374: {
1.1.1.4 ! root     3375:   fprintf (stream, "\n\t.bss\t%s .lcomm\n", ASM_COMMENT_START);
1.1       root     3376:   assemble_name (stream, name);
                   3377:   fprintf (stream, ":\t.space\t%d\n", rounded);
                   3378:   if (in_text_section ())
                   3379:     fputs ("\n\t.text\n", stream);
                   3380:   else
                   3381:     fputs ("\n\t.data\n", stream);
1.1.1.3   root     3382: }
1.1       root     3383: 
                   3384: /* A finite state machine takes care of noticing whether or not instructions
                   3385:    can be conditionally executed, and thus decrease execution time and code
                   3386:    size by deleting branch instructions.  The fsm is controlled by
                   3387:    final_prescan_insn, and controls the actions of ASM_OUTPUT_OPCODE.  */
                   3388: 
                   3389: /* The state of the fsm controlling condition codes are:
                   3390:    0: normal, do nothing special
                   3391:    1: make ASM_OUTPUT_OPCODE not output this instruction
                   3392:    2: make ASM_OUTPUT_OPCODE not output this instruction
                   3393:    3: make instructions conditional
                   3394:    4: make instructions conditional
                   3395: 
                   3396:    State transitions (state->state by whom under condition):
                   3397:    0 -> 1 final_prescan_insn if the `target' is a label
                   3398:    0 -> 2 final_prescan_insn if the `target' is an unconditional branch
                   3399:    1 -> 3 ASM_OUTPUT_OPCODE after not having output the conditional branch
                   3400:    2 -> 4 ASM_OUTPUT_OPCODE after not having output the conditional branch
                   3401:    3 -> 0 ASM_OUTPUT_INTERNAL_LABEL if the `target' label is reached
                   3402:           (the target label has CODE_LABEL_NUMBER equal to arm_target_label).
                   3403:    4 -> 0 final_prescan_insn if the `target' unconditional branch is reached
                   3404:           (the target insn is arm_target_insn).
                   3405: 
1.1.1.2   root     3406:    If the jump clobbers the conditions then we use states 2 and 4.
                   3407: 
                   3408:    A similar thing can be done with conditional return insns.
                   3409: 
1.1       root     3410:    XXX In case the `target' is an unconditional branch, this conditionalising
                   3411:    of the instructions always reduces code size, but not always execution
                   3412:    time.  But then, I want to reduce the code size to somewhere near what
                   3413:    /bin/cc produces.  */
                   3414: 
                   3415: /* Returns the index of the ARM condition code string in
                   3416:    `arm_condition_codes'.  COMPARISON should be an rtx like
                   3417:    `(eq (...) (...))'.  */
                   3418: 
                   3419: int
                   3420: get_arm_condition_code (comparison)
                   3421:      rtx comparison;
                   3422: {
                   3423:   switch (GET_CODE (comparison))
                   3424:     {
                   3425:     case NE: return (1);
                   3426:     case EQ: return (0);
                   3427:     case GE: return (10);
                   3428:     case GT: return (12);
                   3429:     case LE: return (13);
                   3430:     case LT: return (11);
                   3431:     case GEU: return (2);
                   3432:     case GTU: return (8);
                   3433:     case LEU: return (9);
                   3434:     case LTU: return (3);
                   3435:     default: abort ();
                   3436:     }
                   3437:   /*NOTREACHED*/
                   3438:   return (42);
1.1.1.3   root     3439: }
1.1       root     3440: 
                   3441: 
                   3442: void
                   3443: final_prescan_insn (insn, opvec, noperands)
                   3444:      rtx insn;
                   3445:      rtx *opvec;
                   3446:      int noperands;
                   3447: {
                   3448:   /* BODY will hold the body of INSN.  */
                   3449:   register rtx body = PATTERN (insn);
                   3450: 
                   3451:   /* This will be 1 if trying to repeat the trick, and things need to be
                   3452:      reversed if it appears to fail.  */
                   3453:   int reverse = 0;
                   3454: 
1.1.1.2   root     3455:   /* JUMP_CLOBBERS will be one implies that the conditions if a branch is
                   3456:      taken are clobbered, even if the rtl suggests otherwise.  It also
                   3457:      means that we have to grub around within the jump expression to find
                   3458:      out what the conditions are when the jump isn't taken.  */
                   3459:   int jump_clobbers = 0;
                   3460:   
                   3461:   /* If we start with a return insn, we only succeed if we find another one. */
                   3462:   int seeking_return = 0;
                   3463:   
1.1       root     3464:   /* START_INSN will hold the insn from where we start looking.  This is the
                   3465:      first insn after the following code_label if REVERSE is true.  */
                   3466:   rtx start_insn = insn;
                   3467: 
                   3468:   /* If in state 4, check if the target branch is reached, in order to
                   3469:      change back to state 0.  */
                   3470:   if (arm_ccfsm_state == 4)
                   3471:     {
                   3472:       if (insn == arm_target_insn)
1.1.1.2   root     3473:       {
                   3474:        arm_target_insn = NULL;
1.1       root     3475:        arm_ccfsm_state = 0;
1.1.1.2   root     3476:       }
1.1       root     3477:       return;
                   3478:     }
                   3479: 
                   3480:   /* If in state 3, it is possible to repeat the trick, if this insn is an
                   3481:      unconditional branch to a label, and immediately following this branch
                   3482:      is the previous target label which is only used once, and the label this
                   3483:      branch jumps to is not too far off.  */
                   3484:   if (arm_ccfsm_state == 3)
                   3485:     {
                   3486:       if (simplejump_p (insn))
                   3487:        {
                   3488:          start_insn = next_nonnote_insn (start_insn);
                   3489:          if (GET_CODE (start_insn) == BARRIER)
                   3490:            {
                   3491:              /* XXX Isn't this always a barrier?  */
                   3492:              start_insn = next_nonnote_insn (start_insn);
                   3493:            }
                   3494:          if (GET_CODE (start_insn) == CODE_LABEL
                   3495:              && CODE_LABEL_NUMBER (start_insn) == arm_target_label
                   3496:              && LABEL_NUSES (start_insn) == 1)
                   3497:            reverse = TRUE;
                   3498:          else
                   3499:            return;
                   3500:        }
1.1.1.2   root     3501:       else if (GET_CODE (body) == RETURN)
                   3502:         {
                   3503:          start_insn = next_nonnote_insn (start_insn);
                   3504:          if (GET_CODE (start_insn) == BARRIER)
                   3505:            start_insn = next_nonnote_insn (start_insn);
                   3506:          if (GET_CODE (start_insn) == CODE_LABEL
                   3507:              && CODE_LABEL_NUMBER (start_insn) == arm_target_label
                   3508:              && LABEL_NUSES (start_insn) == 1)
                   3509:            {
                   3510:              reverse = TRUE;
                   3511:              seeking_return = 1;
                   3512:            }
                   3513:          else
                   3514:            return;
                   3515:         }
1.1       root     3516:       else
                   3517:        return;
                   3518:     }
                   3519: 
                   3520:   if (arm_ccfsm_state != 0 && !reverse)
                   3521:     abort ();
                   3522:   if (GET_CODE (insn) != JUMP_INSN)
                   3523:     return;
                   3524: 
1.1.1.4 ! root     3525:   /* This jump might be paralleled with a clobber of the condition codes 
1.1.1.2   root     3526:      the jump should always come first */
                   3527:   if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
                   3528:     body = XVECEXP (body, 0, 0);
                   3529: 
                   3530: #if 0  
                   3531:   /* If this is a conditional return then we don't want to know */
                   3532:   if (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
                   3533:       && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
                   3534:       && (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN
                   3535:           || GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN))
                   3536:     return;
                   3537: #endif
                   3538: 
1.1       root     3539:   if (reverse
                   3540:       || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
                   3541:          && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE))
                   3542:     {
                   3543:       int insns_skipped = 0, fail = FALSE, succeed = FALSE;
                   3544:       /* Flag which part of the IF_THEN_ELSE is the LABEL_REF.  */
                   3545:       int then_not_else = TRUE;
1.1.1.2   root     3546:       rtx this_insn = start_insn, label = 0;
1.1       root     3547: 
1.1.1.2   root     3548:       if (get_attr_conds (insn) == CONDS_JUMP_CLOB)
1.1.1.3   root     3549:        {
                   3550:          /* The code below is wrong for these, and I haven't time to
                   3551:             fix it now.  So we just do the safe thing and return.  This
                   3552:             whole function needs re-writing anyway.  */
                   3553:          jump_clobbers = 1;
                   3554:          return;
                   3555:        }
1.1.1.2   root     3556:       
1.1       root     3557:       /* Register the insn jumped to.  */
                   3558:       if (reverse)
1.1.1.2   root     3559:         {
                   3560:          if (!seeking_return)
                   3561:            label = XEXP (SET_SRC (body), 0);
                   3562:         }
1.1       root     3563:       else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF)
                   3564:        label = XEXP (XEXP (SET_SRC (body), 1), 0);
                   3565:       else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF)
                   3566:        {
                   3567:          label = XEXP (XEXP (SET_SRC (body), 2), 0);
                   3568:          then_not_else = FALSE;
                   3569:        }
1.1.1.2   root     3570:       else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN)
                   3571:        seeking_return = 1;
                   3572:       else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN)
                   3573:         {
                   3574:          seeking_return = 1;
                   3575:          then_not_else = FALSE;
                   3576:         }
1.1       root     3577:       else
                   3578:        abort ();
                   3579: 
                   3580:       /* See how many insns this branch skips, and what kind of insns.  If all
                   3581:         insns are okay, and the label or unconditional branch to the same
                   3582:         label is not too far away, succeed.  */
                   3583:       for (insns_skipped = 0;
                   3584:           !fail && !succeed && insns_skipped < MAX_INSNS_SKIPPED;
                   3585:           insns_skipped++)
                   3586:        {
                   3587:          rtx scanbody;
                   3588: 
                   3589:          this_insn = next_nonnote_insn (this_insn);
                   3590:          if (!this_insn)
                   3591:            break;
                   3592: 
                   3593:          scanbody = PATTERN (this_insn);
                   3594: 
                   3595:          switch (GET_CODE (this_insn))
                   3596:            {
                   3597:            case CODE_LABEL:
                   3598:              /* Succeed if it is the target label, otherwise fail since
                   3599:                 control falls in from somewhere else.  */
                   3600:              if (this_insn == label)
                   3601:                {
1.1.1.2   root     3602:                  if (jump_clobbers)
                   3603:                    {
                   3604:                      arm_ccfsm_state = 2;
                   3605:                      this_insn = next_nonnote_insn (this_insn);
                   3606:                    }
                   3607:                  else
                   3608:                    arm_ccfsm_state = 1;
1.1       root     3609:                  succeed = TRUE;
                   3610:                }
                   3611:              else
                   3612:                fail = TRUE;
                   3613:              break;
                   3614: 
1.1.1.2   root     3615:            case BARRIER:
1.1       root     3616:              /* Succeed if the following insn is the target label.
1.1.1.2   root     3617:                 Otherwise fail.  
                   3618:                 If return insns are used then the last insn in a function 
                   3619:                 will be a barrier. */
1.1       root     3620:              this_insn = next_nonnote_insn (this_insn);
1.1.1.2   root     3621:              if (this_insn && this_insn == label)
1.1       root     3622:                {
1.1.1.2   root     3623:                  if (jump_clobbers)
                   3624:                    {
                   3625:                      arm_ccfsm_state = 2;
                   3626:                      this_insn = next_nonnote_insn (this_insn);
                   3627:                    }
                   3628:                  else
                   3629:                    arm_ccfsm_state = 1;
1.1       root     3630:                  succeed = TRUE;
                   3631:                }
                   3632:              else
                   3633:                fail = TRUE;
                   3634:              break;
                   3635: 
1.1.1.2   root     3636:            case CALL_INSN:
                   3637:              /* The arm 6xx uses full 32 bit addresses so the cc is not 
                   3638:                 preserved over calls */
                   3639:              if (TARGET_6)
                   3640:                fail = TRUE;
                   3641:              break;
1.1       root     3642:            case JUMP_INSN:
                   3643:              /* If this is an unconditional branch to the same label, succeed.
                   3644:                 If it is to another label, do nothing.  If it is conditional,
                   3645:                 fail.  */
                   3646:              /* XXX Probably, the test for the SET and the PC are unnecessary. */
                   3647: 
1.1.1.2   root     3648:              if (GET_CODE (scanbody) == SET
                   3649:                  && GET_CODE (SET_DEST (scanbody)) == PC)
1.1       root     3650:                {
                   3651:                  if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF
                   3652:                      && XEXP (SET_SRC (scanbody), 0) == label && !reverse)
                   3653:                    {
                   3654:                      arm_ccfsm_state = 2;
                   3655:                      succeed = TRUE;
                   3656:                    }
                   3657:                  else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE)
                   3658:                    fail = TRUE;
                   3659:                }
1.1.1.2   root     3660:              else if (GET_CODE (scanbody) == RETURN
                   3661:                       && seeking_return)
                   3662:                {
                   3663:                  arm_ccfsm_state = 2;
                   3664:                  succeed = TRUE;
                   3665:                }
                   3666:              else if (GET_CODE (scanbody) == PARALLEL)
                   3667:                {
                   3668:                  switch (get_attr_conds (this_insn))
                   3669:                    {
                   3670:                    case CONDS_NOCOND:
                   3671:                      break;
                   3672:                    default:
                   3673:                      fail = TRUE;
                   3674:                      break;
                   3675:                    }
                   3676:                }
1.1       root     3677:              break;
                   3678: 
                   3679:            case INSN:
1.1.1.2   root     3680:              /* Instructions using or affecting the condition codes make it
                   3681:                 fail.  */
                   3682:              if ((GET_CODE (scanbody) == SET
                   3683:                   || GET_CODE (scanbody) == PARALLEL)
                   3684:                  && get_attr_conds (this_insn) != CONDS_NOCOND)
1.1       root     3685:                fail = TRUE;
                   3686:              break;
                   3687: 
                   3688:            default:
                   3689:              break;
                   3690:            }
                   3691:        }
                   3692:       if (succeed)
                   3693:        {
1.1.1.2   root     3694:          if ((!seeking_return) && (arm_ccfsm_state == 1 || reverse))
1.1       root     3695:            arm_target_label = CODE_LABEL_NUMBER (label);
1.1.1.2   root     3696:          else if (seeking_return || arm_ccfsm_state == 2)
                   3697:            {
                   3698:              while (this_insn && GET_CODE (PATTERN (this_insn)) == USE)
                   3699:                {
                   3700:                  this_insn = next_nonnote_insn (this_insn);
                   3701:                  if (this_insn && (GET_CODE (this_insn) == BARRIER
                   3702:                                    || GET_CODE (this_insn) == CODE_LABEL))
                   3703:                    abort ();
                   3704:                }
                   3705:              if (!this_insn)
                   3706:                {
                   3707:                  /* Oh, dear! we ran off the end.. give up */
                   3708:                  recog (PATTERN (insn), insn, NULL_PTR);
                   3709:                  arm_ccfsm_state = 0;
                   3710:                  arm_target_insn = NULL;
                   3711:                  return;
                   3712:                }
                   3713:              arm_target_insn = this_insn;
                   3714:            }
1.1       root     3715:          else
                   3716:            abort ();
1.1.1.2   root     3717:          if (jump_clobbers)
                   3718:            {
                   3719:              if (reverse)
                   3720:                abort ();
                   3721:              arm_current_cc = 
                   3722:                  get_arm_condition_code (XEXP (XEXP (XEXP (SET_SRC (body),
                   3723:                                                            0), 0), 1));
                   3724:              if (GET_CODE (XEXP (XEXP (SET_SRC (body), 0), 0)) == AND)
                   3725:                arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
                   3726:              if (GET_CODE (XEXP (SET_SRC (body), 0)) == NE)
                   3727:                arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
                   3728:            }
                   3729:          else
                   3730:            {
                   3731:              /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from
                   3732:                 what it was.  */
                   3733:              if (!reverse)
                   3734:                arm_current_cc = get_arm_condition_code (XEXP (SET_SRC (body),
                   3735:                                                               0));
                   3736:            }
1.1       root     3737: 
                   3738:          if (reverse || then_not_else)
                   3739:            arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
                   3740:        }
1.1.1.2   root     3741:       /* restore recog_operand (getting the attributes of other insns can
                   3742:         destroy this array, but final.c assumes that it remains intact
1.1.1.4 ! root     3743:         across this call; since the insn has been recognized already we
1.1.1.2   root     3744:         call recog direct). */
                   3745:       recog (PATTERN (insn), insn, NULL_PTR);
1.1       root     3746:     }
1.1.1.3   root     3747: }
1.1       root     3748: 
                   3749: /* EOF */

unix.superglobalmegacorp.com

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