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

1.1     ! root        1: /* Output routines for GCC for ARM/RISCiX.
        !             2:    Copyright (C) 1991 Free Software Foundation, Inc.
        !             3:    Contributed by Pieter `Tiggr' Schoenmakers ([email protected])
        !             4:              and Martin Simmons (@harleqn.co.uk).
        !             5: 
        !             6: This file is part of GNU CC.
        !             7: 
        !             8: GNU CC is free software; you can redistribute it and/or modify
        !             9: it under the terms of the GNU General Public License as published by
        !            10: the Free Software Foundation; either version 2, or (at your option)
        !            11: any later version.
        !            12: 
        !            13: GNU CC is distributed in the hope that it will be useful,
        !            14: but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            15: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            16: GNU General Public License for more details.
        !            17: 
        !            18: You should have received a copy of the GNU General Public License
        !            19: along with GNU CC; see the file COPYING.  If not, write to
        !            20: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
        !            21: 
        !            22: #include <stdio.h>
        !            23: #include "assert.h"
        !            24: #include "config.h"
        !            25: #include "rtl.h"
        !            26: #include "regs.h"
        !            27: #include "hard-reg-set.h"
        !            28: #include "real.h"
        !            29: #include "insn-config.h"
        !            30: #include "conditions.h"
        !            31: #include "insn-flags.h"
        !            32: #include "output.h"
        !            33: #include "insn-attr.h"
        !            34: #include "flags.h"
        !            35: 
        !            36: /* The maximum number of insns skipped which will be conditionalised if
        !            37:    possible.  */
        !            38: #define MAX_INSNS_SKIPPED  5
        !            39: 
        !            40: /* Some function declarations.  */
        !            41: extern FILE *asm_out_file;
        !            42: extern char *output_multi_immediate ();
        !            43: extern char *arm_output_asm_insn ();
        !            44: extern void arm_increase_location ();
        !            45: 
        !            46: /* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we
        !            47:    must report the mode of the memory reference from PRINT_OPERAND to
        !            48:    PRINT_OPERAND_ADDRESS.  */
        !            49: int output_memory_reference_mode;
        !            50: 
        !            51: /* Nonzero if the prologue must setup `fp'.  */
        !            52: int current_function_anonymous_args;
        !            53: 
        !            54: /* Location counter of .text segment.  */
        !            55: int arm_text_location = 0;
        !            56: 
        !            57: /* A hash table is used to store text segment labels and their associated
        !            58:    offset from the start of the text segment.  */
        !            59: struct label_offset
        !            60: {
        !            61:   char *name;
        !            62:   int offset;
        !            63:   struct label_offset *cdr;
        !            64: };
        !            65: 
        !            66: #define LABEL_HASH_SIZE  257
        !            67: 
        !            68: static struct label_offset *offset_table[LABEL_HASH_SIZE];
        !            69: 
        !            70: /* For an explanation of these variables, see final_prescan_insn below.  */
        !            71: int arm_ccfsm_state;
        !            72: int arm_current_cc;
        !            73: rtx arm_target_insn;
        !            74: int arm_target_label;
        !            75: char *arm_condition_codes[];
        !            76: 
        !            77: /* Return the number of mov instructions needed to get the constant VALUE into
        !            78:    a register.  */
        !            79: 
        !            80: int
        !            81: arm_const_nmoves (value)
        !            82:      register int value;
        !            83: {
        !            84:   register int i;
        !            85: 
        !            86:   if (value == 0)
        !            87:     return (1);
        !            88:   for (i = 0; value; i++, value &= ~0xff)
        !            89:     while ((value & 3) == 0)
        !            90:       value = (value >> 2) | ((value & 3) << 30);
        !            91:   return (i);
        !            92: } /* arm_const_nmoves */
        !            93: 
        !            94: 
        !            95: /* Return TRUE if int I is a valid immediate ARM constant.  */
        !            96: 
        !            97: int
        !            98: const_ok_for_arm (i)
        !            99:      int i;
        !           100: {
        !           101:   unsigned int mask = ~0xFF;
        !           102: 
        !           103:   do
        !           104:     {
        !           105:       if ((i & mask) == 0)
        !           106:        return(TRUE);
        !           107:       mask = (mask << 2) | (mask >> (32 - 2));
        !           108:     } while (mask != ~0xFF);
        !           109: 
        !           110:   return (FALSE);
        !           111: } /* const_ok_for_arm */
        !           112: 
        !           113: /* Return TRUE if rtx X is a valid immediate FPU constant. */
        !           114: 
        !           115: int
        !           116: const_double_rtx_ok_for_fpu (x)
        !           117:      rtx x;
        !           118: {
        !           119:   double d;
        !           120:   union real_extract u;
        !           121:   u.i[0] = CONST_DOUBLE_LOW(x);
        !           122:   u.i[1] = CONST_DOUBLE_HIGH(x);
        !           123:   d = u.d;
        !           124: 
        !           125:   return (d == 0.0 || d == 1.0 || d == 2.0 || d == 3.0
        !           126:          || d == 4.0 || d == 5.0 || d == 0.5 || d == 10.0);
        !           127: } /* const_double_rtx_ok_for_fpu */
        !           128: 
        !           129: /* Predicates for `match_operand' and `match_operator'.  */
        !           130: 
        !           131: /* Return TRUE for valid operands for the rhs of an ARM instruction.  */
        !           132: 
        !           133: int
        !           134: arm_rhs_operand (op, mode)
        !           135:      rtx op;
        !           136:      enum machine_mode mode;
        !           137: {
        !           138:   return (register_operand (op, mode)
        !           139:          || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))));
        !           140: } /* arm_rhs_operand */
        !           141: 
        !           142: /* Return TRUE for valid operands for the rhs of an FPU instruction.  */
        !           143: 
        !           144: int
        !           145: fpu_rhs_operand (op, mode)
        !           146:      rtx op;
        !           147:      enum machine_mode mode;
        !           148: {
        !           149:   if (register_operand (op, mode))
        !           150:     return(TRUE);
        !           151:   else if (GET_CODE (op) == CONST_DOUBLE)
        !           152:     return (const_double_rtx_ok_for_fpu (op));
        !           153:   else return (FALSE);
        !           154: } /* fpu_rhs_operand */
        !           155: 
        !           156: /* Return nonzero if OP is a constant power of two.  */
        !           157: 
        !           158: int
        !           159: power_of_two_operand (op, mode)
        !           160:      rtx op;
        !           161:      enum machine_mode mode;
        !           162: {
        !           163:   if (GET_CODE (op) == CONST_INT)
        !           164:     {
        !           165:       int value = INTVAL(op);
        !           166:       return (value != 0  &&  (value & (value-1)) == 0);
        !           167:     }
        !           168:   return (FALSE);
        !           169: } /* power_of_two_operand */
        !           170: 
        !           171: /* Return TRUE for a valid operand of a DImode operation.
        !           172:    Either: REG, CONST_DOUBLE or MEM(offsettable).
        !           173:    Note that this disallows MEM(REG+REG).  */
        !           174: 
        !           175: int
        !           176: di_operand (op, mode)
        !           177:      rtx op;
        !           178:      enum machine_mode mode;
        !           179: {
        !           180:   if (register_operand (op, mode))
        !           181:     return (TRUE);
        !           182: 
        !           183:   switch (GET_CODE (op))
        !           184:     {
        !           185:     case CONST_DOUBLE:
        !           186:     case CONST_INT:
        !           187:       return (TRUE);
        !           188:     case MEM:
        !           189:       return (memory_address_p (DImode, XEXP (op, 0))
        !           190:              && offsettable_address_p (FALSE, DImode, XEXP (op, 0)));
        !           191:     default:
        !           192:       return (FALSE);
        !           193:     }
        !           194: } /* di_operand */
        !           195: 
        !           196: /* Return TRUE for valid index operands. */
        !           197: 
        !           198: int
        !           199: index_operand (op, mode)
        !           200:      rtx op;
        !           201:      enum machine_mode mode;
        !           202: {
        !           203:   return (register_operand(op, mode)
        !           204:          || (immediate_operand (op, mode) && abs (INTVAL (op)) < 4096));
        !           205: } /* index_operand */
        !           206: 
        !           207: /* Return TRUE for arithmetic operators which can be combined with a multiply
        !           208:    (shift).  */
        !           209: 
        !           210: int
        !           211: shiftable_operator (x, mode)
        !           212:      rtx x;
        !           213:      enum machine_mode mode;
        !           214: {
        !           215:   if (GET_MODE (x) != mode)
        !           216:     return FALSE;
        !           217:   else
        !           218:     {
        !           219:       enum rtx_code code = GET_CODE (x);
        !           220: 
        !           221:       return (code == PLUS || code == MINUS
        !           222:              || code == IOR || code == XOR || code == AND);
        !           223:     }
        !           224: } /* shiftable_operator */
        !           225: 
        !           226: /* Return TRUE for shift operators. */
        !           227: 
        !           228: int
        !           229: shift_operator (x, mode)
        !           230:      rtx x;
        !           231:      enum machine_mode mode;
        !           232: {
        !           233:   if (GET_MODE (x) != mode)
        !           234:     return FALSE;
        !           235:   else
        !           236:     {
        !           237:       enum rtx_code code = GET_CODE (x);
        !           238: 
        !           239:       return (code == ASHIFT || code == LSHIFT
        !           240:              || code == ASHIFTRT || code == LSHIFTRT);
        !           241:     }
        !           242: } /* shift_operator */
        !           243: 
        !           244: /* Routines to output assembly language.  */
        !           245: 
        !           246: /* Output the operands of a LDM/STM instruction to STREAM.
        !           247:    MASK is the ARM register set mask of which only bits 0-15 are important.
        !           248:    INSTR is the possibly suffixed base register.  HAT unequals zero if a hat
        !           249:    must follow the register list.  */
        !           250: 
        !           251: void
        !           252: print_multi_reg (stream, instr, mask, hat)
        !           253:      FILE *stream;
        !           254:      char *instr;
        !           255:      int mask, hat;
        !           256: {
        !           257:   int i;
        !           258:   int not_first = FALSE;
        !           259: 
        !           260:   fprintf (stream, "\t%s, {", instr);
        !           261:   for (i = 0; i < 16; i++)
        !           262:     if (mask & (1 << i))
        !           263:       {
        !           264:        if (not_first)
        !           265:          fprintf (stream, ", ");
        !           266:        fprintf (stream, "%s", reg_names[i]);
        !           267:        not_first = TRUE;
        !           268:       }
        !           269:   fprintf (stream, "}%s\n", hat ? "^" : "");
        !           270: } /* print_multi_reg */
        !           271: 
        !           272: /* Output a 'call' insn. */
        !           273: 
        !           274: char *
        !           275: output_call (operands)
        !           276:        rtx operands[];
        !           277: {
        !           278:   operands[0] = XEXP (operands[0], 0);
        !           279: 
        !           280:   /* Handle calls to lr using ip (which may be clobbered in subr anyway). */
        !           281: 
        !           282:   if (REGNO (operands[0]) == 14)
        !           283:     {
        !           284:       operands[0] = gen_rtx (REG, SImode, 12);
        !           285:       arm_output_asm_insn ("mov\t%0, lr", operands);
        !           286:     }
        !           287:   arm_output_asm_insn ("mov\tlr, pc", operands);
        !           288:   arm_output_asm_insn ("mov\tpc, %0", operands);
        !           289:   return ("");
        !           290: } /* output_call */
        !           291: 
        !           292: /* Output a move from arm registers to an fpu registers.
        !           293:    OPERANDS[0] is an fpu register.
        !           294:    OPERANDS[1] is the first registers of an arm register pair.  */
        !           295: 
        !           296: char *
        !           297: output_mov_double_fpu_from_arm (operands)
        !           298:      rtx operands[];
        !           299: {
        !           300:   int arm_reg0 = REGNO (operands[1]);
        !           301:   rtx ops[2];
        !           302: 
        !           303:   if (arm_reg0 == 12)
        !           304:     abort();
        !           305:   ops[0] = gen_rtx (REG, SImode, arm_reg0);
        !           306:   ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
        !           307:   arm_output_asm_insn ("stmfd\tsp!, {%0, %1}", ops);
        !           308:   arm_output_asm_insn ("ldfd\t%0, [sp], #8", operands);
        !           309:   return ("");
        !           310: } /* output_mov_double_fpu_from_arm */
        !           311: 
        !           312: /* Output a move from an fpu register to arm registers.
        !           313:    OPERANDS[0] is the first registers of an arm register pair.
        !           314:    OPERANDS[1] is an fpu register.  */
        !           315: 
        !           316: char *
        !           317: output_mov_double_arm_from_fpu (operands)
        !           318:      rtx operands[];
        !           319: {
        !           320:   int arm_reg0 = REGNO (operands[0]);
        !           321:   rtx ops[2];
        !           322: 
        !           323:   if (arm_reg0 == 12)
        !           324:     abort();
        !           325:   ops[0] = gen_rtx (REG, SImode, arm_reg0);
        !           326:   ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
        !           327:   arm_output_asm_insn ("stfd\t%1, [sp, #-8]!", operands);
        !           328:   arm_output_asm_insn ("ldmfd\tsp!, {%0, %1}", ops);
        !           329:   return("");
        !           330: } /* output_mov_double_arm_from_fpu */
        !           331: 
        !           332: /* Output a move between double words.
        !           333:    It must be REG<-REG, REG<-CONST_DOUBLE, REG<-CONST_INT, REG<-MEM
        !           334:    or MEM<-REG and all MEMs must be offsettable addresses.  */
        !           335: 
        !           336: char *
        !           337: output_move_double (operands)
        !           338:      rtx operands[];
        !           339: {
        !           340:   enum rtx_code code0 = GET_CODE (operands[0]);
        !           341:   enum rtx_code code1 = GET_CODE (operands[1]);
        !           342:   rtx otherops[2];
        !           343: 
        !           344:   if (code0 == REG)
        !           345:     {
        !           346:       int reg0 = REGNO (operands[0]);
        !           347: 
        !           348:       otherops[0] = gen_rtx (REG, SImode, 1 + reg0);
        !           349:       if (code1 == REG)
        !           350:        {
        !           351:          int reg1 = REGNO (operands[1]);
        !           352:          if (reg1 == 12)
        !           353:            abort();
        !           354:          otherops[1] = gen_rtx (REG, SImode, 1 + reg1);
        !           355: 
        !           356:          /* Ensure the second source is not overwritten */
        !           357:          if (reg0 == 1 + reg1)
        !           358:            {
        !           359:              arm_output_asm_insn("mov\t%0, %1", otherops);
        !           360:              arm_output_asm_insn("mov\t%0, %1", operands);
        !           361:            }
        !           362:          else
        !           363:            {
        !           364:              arm_output_asm_insn("mov\t%0, %1", operands);
        !           365:              arm_output_asm_insn("mov\t%0, %1", otherops);
        !           366:            }
        !           367:        }
        !           368:       else if (code1 == CONST_DOUBLE)
        !           369:        {
        !           370:          otherops[1] = gen_rtx (CONST_INT, VOIDmode,
        !           371:                                 CONST_DOUBLE_HIGH (operands[1]));
        !           372:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
        !           373:                                 CONST_DOUBLE_LOW (operands[1]));
        !           374:          arm_output_asm_insn ("mov\t%0, %1", operands);
        !           375:          arm_output_asm_insn ("mov\t%0, %1", otherops);
        !           376:        }
        !           377:       else if (code1 == CONST_INT)
        !           378:        {
        !           379:          otherops[1] = const0_rtx;
        !           380:          arm_output_asm_insn ("mov\t%0, %1", operands);
        !           381:          arm_output_asm_insn ("mov\t%0, %1", otherops);
        !           382:        }
        !           383:       else if (code1 == MEM)
        !           384:        {
        !           385:          if (GET_CODE (XEXP (operands[1], 0)) == REG)
        !           386:            {
        !           387:              /* Handle the simple case where address is [r, #0] more
        !           388:                 efficient.  */
        !           389:              operands[1] = XEXP (operands[1], 0);
        !           390:              arm_output_asm_insn ("ldmia\t%1, %M0", operands);
        !           391:            }
        !           392:          else
        !           393:            {
        !           394:              otherops[1] = adj_offsettable_operand (operands[1], 4);
        !           395:              /* Take care of overlapping base/data reg.  */
        !           396:              if (reg_mentioned_p (operands[0], operands[1]))
        !           397:                {
        !           398:                  arm_output_asm_insn ("ldr\t%0, %1", otherops);
        !           399:                  arm_output_asm_insn ("ldr\t%0, %1", operands);
        !           400:                }
        !           401:              else
        !           402:                {
        !           403:                  arm_output_asm_insn ("ldr\t%0, %1", operands);
        !           404:                  arm_output_asm_insn ("ldr\t%0, %1", otherops);
        !           405:                }
        !           406:            }
        !           407:        }
        !           408:       else abort();  /* Constraints should prevent this */
        !           409:     }
        !           410:   else if (code0 == MEM && code1 == REG)
        !           411:     {
        !           412:       if (REGNO (operands[1]) == 12)
        !           413:        abort();
        !           414: 
        !           415:       if (GET_CODE (XEXP (operands[0], 0)) == REG)
        !           416:        {
        !           417:          operands[0] = XEXP (operands[0], 0);
        !           418:          arm_output_asm_insn ("stmia\t%0, %M1", operands);
        !           419:        }
        !           420:       else
        !           421:        {
        !           422:          otherops[0] = adj_offsettable_operand (operands[0], 4);
        !           423:          otherops[1] = gen_rtx (REG, SImode, 1 + REGNO (operands[1]));
        !           424:          arm_output_asm_insn ("str\t%1, %0", operands);
        !           425:          arm_output_asm_insn ("str\t%1, %0", otherops);
        !           426:        }
        !           427:     }
        !           428:   else abort();  /* Constraints should prevent this */
        !           429: 
        !           430:   return("");
        !           431: } /* output_move_double */
        !           432: 
        !           433: 
        !           434: /* Output an arbitrary MOV reg, #n.
        !           435:    OPERANDS[0] is a register.  OPERANDS[1] is a const_int.  */
        !           436: 
        !           437: char *
        !           438: output_mov_immediate (operands)
        !           439:      rtx operands[2];
        !           440: {
        !           441:   int n = INTVAL (operands[1]);
        !           442:   int n_ones = 0;
        !           443:   int i;
        !           444: 
        !           445:   /* Try to use one MOV */
        !           446: 
        !           447:   if (const_ok_for_arm (n))
        !           448:     return (arm_output_asm_insn ("mov\t%0, %1", operands));
        !           449: 
        !           450:   /* Try to use one MVN */
        !           451: 
        !           452:   if (const_ok_for_arm(~n))
        !           453:     {
        !           454:       operands[1] = gen_rtx (CONST_INT, VOIDmode, ~n);
        !           455:       return (arm_output_asm_insn ("mvn\t%0, %1", operands));
        !           456:     }
        !           457: 
        !           458:   /* If all else fails, make it out of ORRs or BICs as appropriate. */
        !           459: 
        !           460:   for (i=0; i < 32; i++)
        !           461:     if (n & 1 << i)
        !           462:       n_ones++;
        !           463: 
        !           464:   if (n_ones > 16)  /* Shorter to use MVN with BIC in this case. */
        !           465:     output_multi_immediate(operands, "mvn\t%0, %1", "bic\t%0, %0, %1", 1, ~n);
        !           466:   else
        !           467:     output_multi_immediate(operands, "mov\t%0, %1", "orr\t%0, %0, %1", 1, n);
        !           468:   return("");
        !           469: } /* output_mov_immediate */
        !           470: 
        !           471: 
        !           472: /* Output an ADD r, s, #n where n may be too big for one instruction.  If
        !           473:    adding zero to one register, output nothing.  */
        !           474: 
        !           475: char *
        !           476: output_add_immediate (operands)
        !           477:      rtx operands[3];
        !           478: {
        !           479:   int n = INTVAL (operands[2]);
        !           480: 
        !           481:   if (n != 0 || REGNO (operands[0]) != REGNO (operands[1]))
        !           482:     {
        !           483:       if (n < 0)
        !           484:        output_multi_immediate (operands,
        !           485:                                "sub\t%0, %1, %2", "sub\t%0, %0, %2", 2, -n);
        !           486:       else
        !           487:        output_multi_immediate (operands,
        !           488:                                "add\t%0, %1, %2", "add\t%0, %0, %2", 2, n);
        !           489:     }
        !           490:   return("");
        !           491: } /* output_add_immediate */
        !           492: 
        !           493: 
        !           494: /* Output a multiple immediate operation.
        !           495:    OPERANDS is the vector of operands referred to in the output patterns.
        !           496:    INSTR1 is the output pattern to use for the first constant.
        !           497:    INSTR2 is the output pattern to use for subsequent constants.
        !           498:    IMMED_OP is the index of the constant slot in OPERANDS.
        !           499:    N is the constant value.  */
        !           500: 
        !           501: char *
        !           502: output_multi_immediate (operands, instr1, instr2, immed_op, n)
        !           503:      rtx operands[];
        !           504:      char *instr1, *instr2;
        !           505:      int immed_op, n;
        !           506: {
        !           507:   if (n == 0)
        !           508:     {
        !           509:       operands[immed_op] = const0_rtx;
        !           510:       arm_output_asm_insn (instr1, operands); /* Quick and easy output */
        !           511:     }
        !           512:   else
        !           513:     {
        !           514:       int i;
        !           515:       char *instr = instr1;
        !           516: 
        !           517:       /* Note that n is never zero here (which would give no output) */
        !           518: 
        !           519:       for (i = 0; i < 32; i += 2)
        !           520:        {
        !           521:          if (n & (3 << i))
        !           522:            {
        !           523:              operands[immed_op] = gen_rtx (CONST_INT, VOIDmode,
        !           524:                                            n & (255 << i));
        !           525:              arm_output_asm_insn (instr, operands);
        !           526:              instr = instr2;
        !           527:              i += 6;
        !           528:            }
        !           529:        }
        !           530:     }
        !           531:   return ("");
        !           532: } /* output_multi_immediate */
        !           533: 
        !           534: 
        !           535: /* Return the appropriate ARM instruction for the operation code.
        !           536:    The returned result should not be overwritten.  OP is the rtx of the
        !           537:    operation.  SHIFT_FIRST_ARG is TRUE if the first argument of the operator
        !           538:    was shifted.  */
        !           539: 
        !           540: char *
        !           541: arithmetic_instr (op, shift_first_arg)
        !           542:      rtx op;
        !           543: {
        !           544:   switch (GET_CODE(op))
        !           545:     {
        !           546:     case PLUS:
        !           547:       return ("add");
        !           548:     case MINUS:
        !           549:       if (shift_first_arg)
        !           550:        return ("rsb");
        !           551:       else
        !           552:        return ("sub");
        !           553:     case IOR:
        !           554:       return ("orr");
        !           555:     case XOR:
        !           556:       return ("eor");
        !           557:     case AND:
        !           558:       return ("and");
        !           559:     default:
        !           560:       abort();
        !           561:     }
        !           562:   return ("");                 /* stupid cc */
        !           563: } /* arithmetic_instr */
        !           564: 
        !           565: 
        !           566: /* Ensure valid constant shifts and return the appropriate shift mnemonic
        !           567:    for the operation code.  The returned result should not be overwritten.
        !           568:    OP is the rtx code of the shift.
        !           569:    SHIFT_PTR points to the shift size operand.  */
        !           570: 
        !           571: char *
        !           572: shift_instr (op, shift_ptr)
        !           573:      enum rtx_code op;
        !           574:      rtx *shift_ptr;
        !           575: {
        !           576:   int min_shift = 0;
        !           577:   int max_shift = 31;
        !           578:   char *mnem;
        !           579: 
        !           580:   switch (op)
        !           581:     {
        !           582:     case ASHIFT:
        !           583:       mnem = "asl";
        !           584:       break;
        !           585:     case LSHIFT:
        !           586:       mnem = "lsl";
        !           587:       break;
        !           588:     case ASHIFTRT:
        !           589:       mnem = "asr";
        !           590:       max_shift = 32;
        !           591:       break;
        !           592:     case LSHIFTRT:
        !           593:       mnem = "lsr";
        !           594:       max_shift = 32;
        !           595:       break;
        !           596:     default:
        !           597:       abort();
        !           598:     }
        !           599: 
        !           600:   if (GET_CODE (*shift_ptr) == CONST_INT)
        !           601:     {
        !           602:       int shift = INTVAL (*shift_ptr);
        !           603: 
        !           604:       if (shift < min_shift)
        !           605:        *shift_ptr = gen_rtx (CONST_INT, VOIDmode, 0);
        !           606:       else if (shift > max_shift)
        !           607:        *shift_ptr = gen_rtx (CONST_INT, VOIDmode, max_shift);
        !           608:     }
        !           609:   return (mnem);
        !           610: } /* shift_instr */
        !           611: 
        !           612: 
        !           613: /* Obtain the shift from the POWER of two. */
        !           614: 
        !           615: int
        !           616: int_log2 (power)
        !           617:      unsigned int power;
        !           618: {
        !           619:   int shift = 0;
        !           620: 
        !           621:   while (((1 << shift) & power) == 0)
        !           622:     {
        !           623:       if (shift > 31)
        !           624:        abort();
        !           625:       shift++;
        !           626:     }
        !           627:   return (shift);
        !           628: } /* int_log2 */
        !           629: 
        !           630: 
        !           631: /* Output an arithmetic instruction which may set the condition code.
        !           632:    OPERANDS[0] is the destination register.
        !           633:    OPERANDS[1] is the arithmetic operator expression.
        !           634:    OPERANDS[2] is the left hand argument.
        !           635:    OPERANDS[3] is the right hand argument.
        !           636:    CONST_FIRST_ARG is TRUE if the first argument of the operator was constant.
        !           637:    SET_COND is TRUE when the condition code should be set.  */
        !           638: 
        !           639: char *
        !           640: output_arithmetic (operands, const_first_arg, set_cond)
        !           641:      rtx operands[4];
        !           642:      int const_first_arg;
        !           643:      int set_cond;
        !           644: {
        !           645:   char mnemonic[80];
        !           646:   char *instr = arithmetic_instr (operands[1], const_first_arg);
        !           647: 
        !           648:   sprintf (mnemonic, "%s%s\t%%0, %%2, %%3", instr, set_cond ? "s" : "");
        !           649:   return (arm_output_asm_insn (mnemonic, operands));
        !           650: } /* output_arithmetic */
        !           651: 
        !           652: 
        !           653: /* Output an arithmetic instruction with a shift.
        !           654:    OPERANDS[0] is the destination register.
        !           655:    OPERANDS[1] is the arithmetic operator expression.
        !           656:    OPERANDS[2] is the unshifted register.
        !           657:    OPERANDS[3] is the shift operator expression.
        !           658:    OPERANDS[4] is the shifted register.
        !           659:    OPERANDS[5] is the shift constant or register.
        !           660:    SHIFT_FIRST_ARG is TRUE if the first argument of the operator was shifted.
        !           661:    SET_COND is TRUE when the condition code should be set.  */
        !           662: 
        !           663: char *
        !           664: output_arithmetic_with_shift (operands, shift_first_arg, set_cond)
        !           665:      rtx operands[6];
        !           666:      int shift_first_arg;
        !           667:      int set_cond;
        !           668: {
        !           669:   char mnemonic[80];
        !           670:   char *instr = arithmetic_instr (operands[1], shift_first_arg);
        !           671:   char *condbit = set_cond ? "s" : "";
        !           672:   char *shift = shift_instr (GET_CODE (operands[3]), &operands[5]);
        !           673: 
        !           674:   sprintf (mnemonic, "%s%s\t%%0, %%2, %%4, %s %%5", instr, condbit, shift);
        !           675:   return (arm_output_asm_insn (mnemonic, operands));
        !           676: } /* output_arithmetic_with_shift */
        !           677: 
        !           678: 
        !           679: /* Output an arithmetic instruction with a power of two multiplication.
        !           680:    OPERANDS[0] is the destination register.
        !           681:    OPERANDS[1] is the arithmetic operator expression.
        !           682:    OPERANDS[2] is the unmultiplied register.
        !           683:    OPERANDS[3] is the multiplied register.
        !           684:    OPERANDS[4] is the constant multiple (power of two).
        !           685:    SHIFT_FIRST_ARG is TRUE if the first arg of the operator was multiplied.  */
        !           686: 
        !           687: char *
        !           688: output_arithmetic_with_immediate_multiply (operands, shift_first_arg)
        !           689:      rtx operands[5];
        !           690:      int shift_first_arg;
        !           691: {
        !           692:   char mnemonic[80];
        !           693:   char *instr = arithmetic_instr (operands[1], shift_first_arg);
        !           694:   int shift = int_log2 (INTVAL (operands[4]));
        !           695: 
        !           696:   sprintf (mnemonic, "%s\t%%0, %%2, %%3, asl#%d", instr, shift);
        !           697:   return (arm_output_asm_insn (mnemonic, operands));
        !           698: } /* output_arithmetic_with_immediate_multiply */
        !           699: 
        !           700: 
        !           701: /* Output a move with a shift.
        !           702:    OP is the shift rtx code.
        !           703:    OPERANDS[0] = destination register.
        !           704:    OPERANDS[1] = source register.
        !           705:    OPERANDS[2] = shift constant or register.  */
        !           706: 
        !           707: char *
        !           708: output_shifted_move (op, operands)
        !           709:      enum rtx_code op;
        !           710:      rtx operands[2];
        !           711: {
        !           712:   char mnemonic[80];
        !           713: 
        !           714:   if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0)
        !           715:     sprintf (mnemonic, "mov\t%%0, %%1");
        !           716:   else
        !           717:     sprintf (mnemonic, "mov\t%%0, %%1, %s %%2",
        !           718:             shift_instr (op, &operands[2]));
        !           719:   return (arm_output_asm_insn (mnemonic, operands));
        !           720: } /* output_shifted_move */
        !           721: 
        !           722: 
        !           723: /* Output a .ascii pseudo-op, keeping track of lengths.  This is because
        !           724:    /bin/as is horribly restrictive.  */
        !           725: 
        !           726: void
        !           727: output_ascii_pseudo_op (stream, p, len)
        !           728:      FILE *stream;
        !           729:      char *p;
        !           730:      int len;
        !           731: {
        !           732:   int i;
        !           733:   int len_so_far = 1000;
        !           734:   int chars_so_far = 0;
        !           735: 
        !           736:   for (i = 0; i < len; i++)
        !           737:     {
        !           738:       register int c = p[i];
        !           739: 
        !           740:       if (len_so_far > 50)
        !           741:        {
        !           742:          if (chars_so_far)
        !           743:            fputs ("\"\n", stream);
        !           744:          fputs ("\t.ascii\t\"", stream);
        !           745:          len_so_far = 0;
        !           746:          arm_increase_location (chars_so_far);
        !           747:          chars_so_far = 0;
        !           748:        }
        !           749: 
        !           750:       if (c == '\"' || c == '\\')
        !           751:        {
        !           752:          putc('\\', stream);
        !           753:          len_so_far++;
        !           754:        }
        !           755:       if (c >= ' ' && c < 0177)
        !           756:        {
        !           757:          putc (c, stream);
        !           758:          len_so_far++;
        !           759:        }
        !           760:       else
        !           761:        {
        !           762:          fprintf (stream, "\\%03o", c);
        !           763:          len_so_far +=4;
        !           764:        }
        !           765:       chars_so_far++;
        !           766:     }
        !           767:   fputs ("\"\n", stream);
        !           768:   arm_increase_location (chars_so_far);
        !           769: } /* output_ascii_pseudo_op */
        !           770: 
        !           771: void
        !           772: output_prologue (f, frame_size)
        !           773:      FILE *f;
        !           774:      int frame_size;
        !           775: {
        !           776: 
        !           777:   int reg, live_regs_mask = 0, code_size = 0;
        !           778:   rtx operands[3];
        !           779: 
        !           780:   /* Nonzero if the `fp' (argument pointer) register is needed.  */
        !           781:   int fp_needed = 0;
        !           782: 
        !           783:   /* Nonzero if we must stuff some register arguments onto the stack as if
        !           784:      they were passed there.  */
        !           785:   int store_arg_regs = 0;
        !           786: 
        !           787:   fprintf (f, "\t@ args = %d, pretend = %d, frame = %d\n",
        !           788:           current_function_args_size, current_function_pretend_args_size, frame_size);
        !           789:   fprintf (f, "\t@ frame_pointer_needed = %d, current_function_anonymous_args = %d\n",
        !           790:           frame_pointer_needed, current_function_anonymous_args);
        !           791: 
        !           792:   if (current_function_pretend_args_size || current_function_args_size
        !           793:       || frame_pointer_needed || current_function_anonymous_args || TARGET_APCS)
        !           794:     fp_needed = 1;
        !           795: 
        !           796:   if (current_function_anonymous_args && current_function_pretend_args_size)
        !           797:     store_arg_regs = 1;
        !           798: 
        !           799:   for (reg = 4; reg < 10; reg++)
        !           800:     if (regs_ever_live[reg])
        !           801:       live_regs_mask |= (1 << reg);
        !           802: 
        !           803:   if (fp_needed)
        !           804:     {
        !           805:       live_regs_mask |= 0xD800;
        !           806:       /* The following statement is probably redundant now
        !           807:         because the frame pointer is recorded in regs_ever_live.  */
        !           808:       if (frame_pointer_needed)
        !           809:        live_regs_mask |= (1 << FRAME_POINTER_REGNUM);
        !           810:       fputs ("\tmov\tip, sp\n", f);
        !           811:       code_size += 4;
        !           812:     }
        !           813:   else if (regs_ever_live[14])
        !           814:     live_regs_mask |= 0x4000;
        !           815: 
        !           816:   /* If CURRENT_FUNCTION_PRETEND_ARGS_SIZE, adjust the stack pointer to make
        !           817:      room.  If also STORE_ARG_REGS store the argument registers involved in
        !           818:      the created slot (this is for stdarg and varargs).  */
        !           819:   if (current_function_pretend_args_size)
        !           820:     {
        !           821:       if (store_arg_regs)
        !           822:        {
        !           823:          int arg_size, mask = 0;
        !           824: 
        !           825:          assert (current_function_pretend_args_size <= 16);
        !           826:          for (reg = 3, arg_size = current_function_pretend_args_size;
        !           827:               arg_size > 0; reg--, arg_size -= 4)
        !           828:            mask |= (1 << reg);
        !           829:          print_multi_reg (f, "stmfd\tsp!", mask, FALSE);
        !           830:        }
        !           831:       else
        !           832:        {
        !           833:          operands[0] = operands[1] = stack_pointer_rtx;
        !           834:          operands[2] = gen_rtx (CONST_INT, VOIDmode,
        !           835:                                 -current_function_pretend_args_size);
        !           836:          output_add_immediate (operands);
        !           837:        }
        !           838:     }
        !           839: 
        !           840:   if (live_regs_mask)
        !           841:     {
        !           842:       print_multi_reg (f, "stmfd\tsp!", live_regs_mask, FALSE);
        !           843:       code_size += 4;
        !           844:     }
        !           845: 
        !           846:   for (reg = 23; reg > 19; reg--)
        !           847:     if (regs_ever_live[reg])
        !           848:       {
        !           849:        fprintf (f, "\tstfe\t%s, [sp, #-12]!\n", reg_names[reg]);
        !           850:        code_size += 4;
        !           851:       }
        !           852: 
        !           853:   if (fp_needed)
        !           854:     {
        !           855:       /* Make `fp' point to saved value of `pc'. */
        !           856: 
        !           857:       operands[0] = arg_pointer_rtx;
        !           858:       operands[1] = gen_rtx (REG, SImode, 12);
        !           859:       operands[2] = gen_rtx (CONST_INT, VOIDmode,
        !           860:                             - (4 + current_function_pretend_args_size));
        !           861:       output_add_immediate (operands);
        !           862:     }
        !           863: 
        !           864:   if (frame_pointer_needed)
        !           865:     {
        !           866:       fprintf (f, "\tmov\trfp, sp\n");
        !           867:       code_size += 4;
        !           868:     }
        !           869: 
        !           870:   if (frame_size)
        !           871:     {
        !           872:       operands[0] = operands[1] = stack_pointer_rtx;
        !           873:       operands[2] = gen_rtx (CONST_INT, VOIDmode, -frame_size);
        !           874:       output_add_immediate (operands);
        !           875:     }
        !           876: 
        !           877:   arm_increase_location (code_size);
        !           878: } /* output_prologue */
        !           879: 
        !           880: 
        !           881: void
        !           882: output_epilogue (f, frame_size)
        !           883:      FILE *f;
        !           884:      int frame_size;
        !           885: {
        !           886:   int reg, live_regs_mask = 0, code_size = 0, fp_needed = 0;
        !           887:   rtx operands[3];
        !           888: 
        !           889:   if (current_function_pretend_args_size || current_function_args_size
        !           890:       || frame_pointer_needed || current_function_anonymous_args || TARGET_APCS)
        !           891:     fp_needed = 1;
        !           892: 
        !           893:   for (reg = 4; reg < 10; reg++)
        !           894:     if (regs_ever_live[reg])
        !           895:       live_regs_mask |= (1 << reg);
        !           896: 
        !           897:   if (fp_needed)
        !           898:     {
        !           899:       live_regs_mask |= 0xA800;
        !           900:       if (frame_pointer_needed)
        !           901:         live_regs_mask |= (1 << FRAME_POINTER_REGNUM);
        !           902:     }
        !           903:   else if (regs_ever_live[14])
        !           904:     live_regs_mask |= 0x4000;
        !           905: 
        !           906:   for (reg = 20; reg < 24; reg++)
        !           907:     if (regs_ever_live[reg])
        !           908:       {
        !           909:        fprintf (f, "\tldfe\t%s, [%s], #12\n", reg_names[reg],
        !           910:                 frame_pointer_needed ? "rfp" : "sp");
        !           911:        code_size += 4;
        !           912:       }
        !           913: 
        !           914:   if (fp_needed)
        !           915:     {
        !           916:       print_multi_reg (f, "ldmea\tfp", live_regs_mask, TRUE);
        !           917:       code_size += 4;
        !           918:     }
        !           919:   else
        !           920:     {
        !           921:       /* Restore stack pointer if necessary.  */
        !           922:       if (frame_size)
        !           923:        {
        !           924:          operands[0] = operands[1] = stack_pointer_rtx;
        !           925:          operands[2] = gen_rtx (CONST_INT, VOIDmode, frame_size);
        !           926:          output_add_immediate (operands);
        !           927:        }
        !           928: 
        !           929:       if (current_function_pretend_args_size == 0 && regs_ever_live[14])
        !           930:        {
        !           931:          print_multi_reg (f, "ldmfd\tsp!",
        !           932:                           (live_regs_mask & ~0x4000) | 0x8000, TRUE);
        !           933:          code_size += 4;
        !           934:        }
        !           935:       else
        !           936:        {
        !           937:          if (live_regs_mask)
        !           938:            {
        !           939:              print_multi_reg (f, "ldmfd\tsp!", live_regs_mask, FALSE);
        !           940:              code_size += 4;
        !           941:            }
        !           942:          if (current_function_pretend_args_size)
        !           943:            {
        !           944:              operands[0] = operands[1] = stack_pointer_rtx;
        !           945:              operands[2] = gen_rtx (CONST_INT, VOIDmode,
        !           946:                                     current_function_pretend_args_size);
        !           947:              output_add_immediate (operands);
        !           948:            }
        !           949:          fputs ("\tmovs\tpc, lr\n", f);
        !           950:          code_size += 4;
        !           951:        }
        !           952:     }
        !           953:   arm_increase_location (code_size);
        !           954:   current_function_anonymous_args = 0;
        !           955: } /* output_epilogue */
        !           956: 
        !           957: /* Increase the `arm_text_location' by AMOUNT if we're in the text
        !           958:    segment.  */
        !           959: 
        !           960: void
        !           961: arm_increase_location (amount)
        !           962:      int amount;
        !           963: {
        !           964:   if (in_text_section ())
        !           965:     arm_text_location += amount;
        !           966: } /* arm_increase_location */
        !           967: 
        !           968: 
        !           969: /* Like output_asm_insn (), but also increases the arm_text_location (if in
        !           970:    the .text segment, of course, even though this will always be true).
        !           971:    Returns the empty string.  */
        !           972: 
        !           973: char *
        !           974: arm_output_asm_insn (template, operands)
        !           975:      char *template;
        !           976:      rtx *operands;
        !           977: {
        !           978:   extern FILE *asm_out_file;
        !           979: 
        !           980:   output_asm_insn (template, operands);
        !           981:   if (in_text_section ())
        !           982:     arm_text_location += 4;
        !           983:   fflush (asm_out_file);
        !           984:   return ("");
        !           985: } /* arm_output_asm_insn */
        !           986: 
        !           987: 
        !           988: /* Output a label definition.  If this label is within the .text segment, it
        !           989:    is stored in OFFSET_TABLE, to be used when building `llc' instructions.
        !           990:    Maybe GCC remembers names not starting with a `*' for a long time, but this
        !           991:    is a minority anyway, so we just make a copy.  Do not store the leading `*'
        !           992:    if the name starts with one.  */
        !           993: 
        !           994: void
        !           995: arm_asm_output_label (stream, name)
        !           996:      FILE *stream;
        !           997:      char *name;
        !           998: {
        !           999:   char *real_name, *s;
        !          1000:   struct label_offset *cur;
        !          1001:   int hash = 0;
        !          1002: 
        !          1003:   assemble_name (stream, name);
        !          1004:   fputs (":\n", stream);
        !          1005:   if (! in_text_section ())
        !          1006:     return;
        !          1007: 
        !          1008:   if (name[0] == '*')
        !          1009:     {
        !          1010:       real_name = xmalloc (1 + strlen (&name[1]));
        !          1011:       strcpy (real_name, &name[1]);
        !          1012:     }
        !          1013:   else
        !          1014:     {
        !          1015:       real_name = xmalloc (2 + strlen (name));
        !          1016:       strcpy (real_name, "_");
        !          1017:       strcat (real_name, name);
        !          1018:     }
        !          1019:   for (s = real_name; *s; s++)
        !          1020:     hash += *s;
        !          1021:   hash = hash % LABEL_HASH_SIZE;
        !          1022:   cur = (struct label_offset *) xmalloc (sizeof (struct label_offset));
        !          1023:   cur->name = real_name;
        !          1024:   cur->offset = arm_text_location;
        !          1025:   cur->cdr = offset_table[hash];
        !          1026:   offset_table[hash] = cur;
        !          1027: } /* arm_asm_output_label */
        !          1028: 
        !          1029: 
        !          1030: /* Output the instructions needed to perform what Martin's /bin/as called
        !          1031:    llc: load an SImode thing from the function's constant pool.
        !          1032: 
        !          1033:    XXX This could be enhanced in that we do not really need a pointer in the
        !          1034:    constant pool pointing to the real thing.  If we can address this pointer,
        !          1035:    we can also address what it is pointing at, in fact, anything in the text
        !          1036:    segment which has been defined already within this .s file.  */
        !          1037: 
        !          1038: char *
        !          1039: arm_output_llc (operands)
        !          1040:      rtx *operands;
        !          1041: {
        !          1042:   char *s, *name = XSTR (XEXP (operands[1], 0), 0);
        !          1043:   struct label_offset *he;
        !          1044:   int hash = 0, conditional = (arm_ccfsm_state == 3 || arm_ccfsm_state == 4);
        !          1045: 
        !          1046:   if (*name != '*')
        !          1047:     abort ();
        !          1048: 
        !          1049:   for (s = &name[1]; *s; s++)
        !          1050:     hash += *s;
        !          1051:   hash = hash % LABEL_HASH_SIZE;
        !          1052:   he = offset_table[hash];
        !          1053:   while (he && strcmp (he->name, &name[1]))
        !          1054:     he = he->cdr;
        !          1055: 
        !          1056:   if (!he)
        !          1057:     abort ();
        !          1058: 
        !          1059:   if (arm_text_location + 8 - he->offset < 4095)
        !          1060:     {
        !          1061:       fprintf (asm_out_file, "\tldr%s\t%s, [pc, #%s - . - 8]\n",
        !          1062:               conditional ? arm_condition_codes[arm_current_cc] : "",
        !          1063:               reg_names[REGNO (operands[0])], &name[1]);
        !          1064:       arm_increase_location (4);
        !          1065:       return ("");
        !          1066:     }
        !          1067:   else
        !          1068:     {
        !          1069:       int offset = - (arm_text_location + 8 - he->offset);
        !          1070:       char *reg_name = reg_names[REGNO (operands[0])];
        !          1071: 
        !          1072:       /* ??? This is a hack, assuming the constant pool never is more than
        !          1073:         (1 + 255) * 4096 == 1Meg away from the PC.  */
        !          1074: 
        !          1075:       if (offset > 1000000)
        !          1076:        abort ();
        !          1077: 
        !          1078:       fprintf (asm_out_file, "\tsub%s\t%s, pc, #(8 + . - %s) & ~4095\n",
        !          1079:               conditional ? arm_condition_codes[arm_current_cc] : "",
        !          1080:               reg_name, &name[1]);
        !          1081:       fprintf (asm_out_file, "\tldr%s\t%s, [%s, #- ((4 + . - %s) & 4095)]\n",
        !          1082:               conditional ? arm_condition_codes[arm_current_cc] : "",
        !          1083:               reg_name, reg_name, &name[1]);
        !          1084:       arm_increase_location (8);
        !          1085:     }
        !          1086:   return ("");
        !          1087: } /* arm_output_llc */
        !          1088: 
        !          1089: 
        !          1090: /* Output code resembling an .lcomm directive.  /bin/as doesn't have this
        !          1091:    directive hence this hack, which works by reserving some `.space' in the
        !          1092:    bss segment directly.
        !          1093: 
        !          1094:    XXX This is a severe hack, which is guaranteed NOT to work since it doesn't
        !          1095:    define STATIC COMMON space but merely STATIC BSS space.  */
        !          1096: 
        !          1097: void
        !          1098: output_lcomm_directive (stream, name, size, rounded)
        !          1099:      FILE *stream;
        !          1100:      char *name;
        !          1101:      int size, rounded;
        !          1102: {
        !          1103:   fputs ("\n\t.bss\t@ .lcomm\n", stream);
        !          1104:   assemble_name (stream, name);
        !          1105:   fprintf (stream, ":\t.space\t%d\n", rounded);
        !          1106:   if (in_text_section ())
        !          1107:     fputs ("\n\t.text\n", stream);
        !          1108:   else
        !          1109:     fputs ("\n\t.data\n", stream);
        !          1110: } /* output_lcomm_directive */
        !          1111: 
        !          1112: /* A finite state machine takes care of noticing whether or not instructions
        !          1113:    can be conditionally executed, and thus decrease execution time and code
        !          1114:    size by deleting branch instructions.  The fsm is controlled by
        !          1115:    final_prescan_insn, and controls the actions of ASM_OUTPUT_OPCODE.  */
        !          1116: 
        !          1117: /* The state of the fsm controlling condition codes are:
        !          1118:    0: normal, do nothing special
        !          1119:    1: make ASM_OUTPUT_OPCODE not output this instruction
        !          1120:    2: make ASM_OUTPUT_OPCODE not output this instruction
        !          1121:    3: make instructions conditional
        !          1122:    4: make instructions conditional
        !          1123: 
        !          1124:    State transitions (state->state by whom under condition):
        !          1125:    0 -> 1 final_prescan_insn if the `target' is a label
        !          1126:    0 -> 2 final_prescan_insn if the `target' is an unconditional branch
        !          1127:    1 -> 3 ASM_OUTPUT_OPCODE after not having output the conditional branch
        !          1128:    2 -> 4 ASM_OUTPUT_OPCODE after not having output the conditional branch
        !          1129:    3 -> 0 ASM_OUTPUT_INTERNAL_LABEL if the `target' label is reached
        !          1130:           (the target label has CODE_LABEL_NUMBER equal to arm_target_label).
        !          1131:    4 -> 0 final_prescan_insn if the `target' unconditional branch is reached
        !          1132:           (the target insn is arm_target_insn).
        !          1133: 
        !          1134:    XXX In case the `target' is an unconditional branch, this conditionalising
        !          1135:    of the instructions always reduces code size, but not always execution
        !          1136:    time.  But then, I want to reduce the code size to somewhere near what
        !          1137:    /bin/cc produces.  */
        !          1138: 
        !          1139: /* The condition codes of the ARM, and the inverse function.  */
        !          1140: char *arm_condition_codes[] =
        !          1141: {
        !          1142:   "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
        !          1143:   "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
        !          1144: };
        !          1145: 
        !          1146: #define ARM_INVERSE_CONDITION_CODE(X)  ((X) ^ 1)
        !          1147: 
        !          1148: /* Returns the index of the ARM condition code string in
        !          1149:    `arm_condition_codes'.  COMPARISON should be an rtx like
        !          1150:    `(eq (...) (...))'.  */
        !          1151: 
        !          1152: int
        !          1153: get_arm_condition_code (comparison)
        !          1154:      rtx comparison;
        !          1155: {
        !          1156:   switch (GET_CODE (comparison))
        !          1157:     {
        !          1158:     case NE: return (1);
        !          1159:     case EQ: return (0);
        !          1160:     case GE: return (10);
        !          1161:     case GT: return (12);
        !          1162:     case LE: return (13);
        !          1163:     case LT: return (11);
        !          1164:     case GEU: return (2);
        !          1165:     case GTU: return (8);
        !          1166:     case LEU: return (9);
        !          1167:     case LTU: return (3);
        !          1168:     default: abort ();
        !          1169:     }
        !          1170:   /*NOTREACHED*/
        !          1171:   return (42);
        !          1172: } /* get_arm_condition_code */
        !          1173: 
        !          1174: 
        !          1175: void
        !          1176: final_prescan_insn (insn, opvec, noperands)
        !          1177:      rtx insn;
        !          1178:      rtx *opvec;
        !          1179:      int noperands;
        !          1180: {
        !          1181:   /* BODY will hold the body of INSN.  */
        !          1182:   register rtx body = PATTERN (insn);
        !          1183: 
        !          1184:   /* This will be 1 if trying to repeat the trick, and things need to be
        !          1185:      reversed if it appears to fail.  */
        !          1186:   int reverse = 0;
        !          1187: 
        !          1188:   /* START_INSN will hold the insn from where we start looking.  This is the
        !          1189:      first insn after the following code_label if REVERSE is true.  */
        !          1190:   rtx start_insn = insn;
        !          1191: 
        !          1192:   /* If in state 4, check if the target branch is reached, in order to
        !          1193:      change back to state 0.  */
        !          1194:   if (arm_ccfsm_state == 4)
        !          1195:     {
        !          1196:       if (insn == arm_target_insn)
        !          1197:        arm_ccfsm_state = 0;
        !          1198:       return;
        !          1199:     }
        !          1200: 
        !          1201:   /* If in state 3, it is possible to repeat the trick, if this insn is an
        !          1202:      unconditional branch to a label, and immediately following this branch
        !          1203:      is the previous target label which is only used once, and the label this
        !          1204:      branch jumps to is not too far off.  */
        !          1205:   if (arm_ccfsm_state == 3)
        !          1206:     {
        !          1207:       if (simplejump_p (insn))
        !          1208:        {
        !          1209:          start_insn = next_nonnote_insn (start_insn);
        !          1210:          if (GET_CODE (start_insn) == BARRIER)
        !          1211:            {
        !          1212:              /* XXX Isn't this always a barrier?  */
        !          1213:              start_insn = next_nonnote_insn (start_insn);
        !          1214:            }
        !          1215:          if (GET_CODE (start_insn) == CODE_LABEL
        !          1216:              && CODE_LABEL_NUMBER (start_insn) == arm_target_label
        !          1217:              && LABEL_NUSES (start_insn) == 1)
        !          1218:            reverse = TRUE;
        !          1219:          else
        !          1220:            return;
        !          1221:        }
        !          1222:       else
        !          1223:        return;
        !          1224:     }
        !          1225: 
        !          1226:   if (arm_ccfsm_state != 0 && !reverse)
        !          1227:     abort ();
        !          1228:   if (GET_CODE (insn) != JUMP_INSN)
        !          1229:     return;
        !          1230: 
        !          1231:   if (reverse
        !          1232:       || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
        !          1233:          && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE))
        !          1234:     {
        !          1235:       int insns_skipped = 0, fail = FALSE, succeed = FALSE;
        !          1236:       /* Flag which part of the IF_THEN_ELSE is the LABEL_REF.  */
        !          1237:       int then_not_else = TRUE;
        !          1238:       rtx this_insn = start_insn, label;
        !          1239: 
        !          1240:       /* Register the insn jumped to.  */
        !          1241:       if (reverse)
        !          1242:        label = XEXP (SET_SRC (body), 0);
        !          1243:       else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF)
        !          1244:        label = XEXP (XEXP (SET_SRC (body), 1), 0);
        !          1245:       else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF)
        !          1246:        {
        !          1247:          label = XEXP (XEXP (SET_SRC (body), 2), 0);
        !          1248:          then_not_else = FALSE;
        !          1249:        }
        !          1250:       else
        !          1251:        abort ();
        !          1252: 
        !          1253:       /* See how many insns this branch skips, and what kind of insns.  If all
        !          1254:         insns are okay, and the label or unconditional branch to the same
        !          1255:         label is not too far away, succeed.  */
        !          1256:       for (insns_skipped = 0;
        !          1257:           !fail && !succeed && insns_skipped < MAX_INSNS_SKIPPED;
        !          1258:           insns_skipped++)
        !          1259:        {
        !          1260:          rtx scanbody;
        !          1261: 
        !          1262:          this_insn = next_nonnote_insn (this_insn);
        !          1263:          if (!this_insn)
        !          1264:            break;
        !          1265: 
        !          1266:          scanbody = PATTERN (this_insn);
        !          1267: 
        !          1268:          switch (GET_CODE (this_insn))
        !          1269:            {
        !          1270:            case CODE_LABEL:
        !          1271:              /* Succeed if it is the target label, otherwise fail since
        !          1272:                 control falls in from somewhere else.  */
        !          1273:              if (this_insn == label)
        !          1274:                {
        !          1275:                  arm_ccfsm_state = 1;
        !          1276:                  succeed = TRUE;
        !          1277:                }
        !          1278:              else
        !          1279:                fail = TRUE;
        !          1280:              break;
        !          1281: 
        !          1282:            case BARRIER:       /* XXX Is this case necessary?  */
        !          1283:              /* Succeed if the following insn is the target label.
        !          1284:                 Otherwise fail.  */
        !          1285:              this_insn = next_nonnote_insn (this_insn);
        !          1286:              if (this_insn == label)
        !          1287:                {
        !          1288:                  arm_ccfsm_state = 1;
        !          1289:                  succeed = TRUE;
        !          1290:                }
        !          1291:              else
        !          1292:                fail = TRUE;
        !          1293:              break;
        !          1294: 
        !          1295:            case JUMP_INSN:
        !          1296:              /* If this is an unconditional branch to the same label, succeed.
        !          1297:                 If it is to another label, do nothing.  If it is conditional,
        !          1298:                 fail.  */
        !          1299:              /* XXX Probably, the test for the SET and the PC are unnecessary. */
        !          1300: 
        !          1301:              if (GET_CODE (scanbody) == SET && GET_CODE (SET_DEST (scanbody)) == PC)
        !          1302:                {
        !          1303:                  if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF
        !          1304:                      && XEXP (SET_SRC (scanbody), 0) == label && !reverse)
        !          1305:                    {
        !          1306:                      arm_ccfsm_state = 2;
        !          1307:                      succeed = TRUE;
        !          1308:                    }
        !          1309:                  else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE)
        !          1310:                    fail = TRUE;
        !          1311:                }
        !          1312:              break;
        !          1313: 
        !          1314:            case INSN:
        !          1315:              /* Instructions affecting the condition codes make it fail.  */
        !          1316:              if (sets_cc0_p (scanbody))
        !          1317:                fail = TRUE;
        !          1318:              break;
        !          1319: 
        !          1320:            default:
        !          1321:              break;
        !          1322:            }
        !          1323:        }
        !          1324:       if (succeed)
        !          1325:        {
        !          1326:          if (arm_ccfsm_state == 1 || reverse)
        !          1327:            arm_target_label = CODE_LABEL_NUMBER (label);
        !          1328:          else if (arm_ccfsm_state == 2)
        !          1329:            arm_target_insn = this_insn;
        !          1330:          else
        !          1331:            abort ();
        !          1332: 
        !          1333:          /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from what
        !          1334:             it was.  */
        !          1335:          if (!reverse)
        !          1336:            arm_current_cc = get_arm_condition_code (XEXP (SET_SRC (body), 0));
        !          1337:          if (reverse || then_not_else)
        !          1338:            arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
        !          1339:        }
        !          1340:     }
        !          1341: } /* final_prescan_insn */
        !          1342: 
        !          1343: /* EOF */

unix.superglobalmegacorp.com

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