Annotation of gcc/config/sh/sh.c, revision 1.1.1.3

1.1       root        1: /* Output routines for GCC for Hitachi Super-H
1.1.1.3 ! root        2:    Copyright (C) 1993, 1994 Free Software Foundation, Inc.
1.1       root        3: 
1.1.1.3 ! root        4:    This file is part of GNU CC.
1.1       root        5: 
1.1.1.3 ! root        6:    GNU CC is free software; you can redistribute it and/or modify
        !             7:    it under the terms of the GNU General Public License as published by
        !             8:    the Free Software Foundation; either version 2, or (at your option)
        !             9:    any later version.
        !            10: 
        !            11:    GNU CC is distributed in the hope that it will be useful,
        !            12:    but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            13:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            14:    GNU General Public License for more details.
        !            15: 
        !            16:    You should have received a copy of the GNU General Public License
        !            17:    along with GNU CC; see the file COPYING.  If not, write to
        !            18:    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
1.1       root       19: 
                     20: 
                     21: /* Contributed by Steve Chamberlain ([email protected]) */
                     22: 
                     23: #include <stdio.h>
                     24: #include "assert.h"
                     25: #include "config.h"
                     26: #include "rtl.h"
                     27: #include "regs.h"
                     28: #include "hard-reg-set.h"
                     29: #include "real.h"
                     30: #include "insn-config.h"
                     31: #include "conditions.h"
                     32: #include "insn-flags.h"
                     33: #include "tree.h"
                     34: #include "output.h"
1.1.1.3 ! root       35: 
1.1       root       36: #include "insn-attr.h"
                     37: #include "flags.h"
                     38: #include "obstack.h"
                     39: #include "expr.h"
                     40: 
1.1.1.3 ! root       41: static rtx add_constant ();
1.1       root       42: 
1.1.1.3 ! root       43: int pragma_interrupt;
        !            44: int pragma_trapa;
1.1       root       45: 
                     46: int current_function_anonymous_args;
                     47: extern int current_function_pretend_args_size;
1.1.1.2   root       48: extern char *version_string;
                     49: extern int flag_traditional;
                     50: 
1.1.1.3 ! root       51: static rtx shiftsyms[32];
        !            52: struct rtx_def *table_lab;
1.1.1.2   root       53: enum attr_cpu sh_cpu;          /* target cpu */
1.1       root       54: 
                     55: /* Global variables for machine-dependent things. */
                     56: 
                     57: /* Saved operands from the last compare to use when we generate an scc
1.1.1.3 ! root       58:    or bcc insn. */
1.1       root       59: 
                     60: rtx sh_compare_op0;
                     61: rtx sh_compare_op1;
                     62: 
                     63: /* Provides the class number of the smallest class containing
                     64:    reg number */
                     65: 
                     66: int regno_reg_class[FIRST_PSEUDO_REGISTER] =
                     67: {
                     68:   R0_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
                     69:   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
                     70:   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
                     71:   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
1.1.1.3 ! root       72:   GENERAL_REGS, PR_REGS, T_REGS, NO_REGS,
        !            73:   MAC_REGS, MAC_REGS,
1.1       root       74: };
                     75: 
                     76: /* Provide reg_class from a letter such as appears in the machine
                     77:    description. */
                     78: 
                     79: enum reg_class reg_class_from_letter[] =
                     80: {
                     81:   /* a */ NO_REGS, /* b */ NO_REGS, /* c */ NO_REGS, /* d */ NO_REGS,
                     82:   /* e */ NO_REGS, /* f */ NO_REGS, /* g */ NO_REGS, /* h */ NO_REGS,
                     83:   /* i */ NO_REGS, /* j */ NO_REGS, /* k */ NO_REGS, /* l */ PR_REGS,
                     84:   /* m */ NO_REGS, /* n */ NO_REGS, /* o */ NO_REGS, /* p */ NO_REGS,
                     85:   /* q */ NO_REGS, /* r */ NO_REGS, /* s */ NO_REGS, /* t */ T_REGS,
                     86:   /* u */ NO_REGS, /* v */ NO_REGS, /* w */ NO_REGS, /* x */ MAC_REGS,
                     87:   /* y */ NO_REGS, /* z */ R0_REGS
                     88: };
                     89: 
1.1.1.3 ! root       90: /* Value is 1 if register/mode pair is acceptable on SH.  Even
        !            91:    registers can hold DIs and DF values. The rest can only hold
        !            92:    SI's efficiently  */
        !            93: 
        !            94: 
        !            95: #define REG_ODD \
        !            96:  (  (1 << (int) QImode)  | (1 << (int) HImode) | (1 << (int) SImode)   \
        !            97:   | (1 << (int) QFmode)  | (1 << (int) HFmode) | (1 << (int) SFmode)   \
        !            98:   | (1 << (int) CQImode) | (1 << (int) CHImode)| (1<< (int)DFmode) | (1<<(int)DImode))
1.1       root       99: 
1.1.1.3 ! root      100: #define REG_EVEN \
        !           101:   (REG_ODD | (1 << (int) CSImode) | (1 << (int) SCmode))
1.1.1.2   root      102: 
1.1.1.3 ! root      103: #define SI_ONLY (1<<(int)SImode)
        !           104: 
        !           105: int hard_regno_mode_ok[] =
        !           106: {
        !           107:   REG_EVEN, REG_ODD, REG_EVEN, REG_ODD,
        !           108:   REG_EVEN, REG_ODD, REG_EVEN, REG_ODD,
        !           109:   REG_EVEN, REG_ODD, REG_EVEN, REG_ODD,
        !           110:   REG_EVEN, REG_ODD, REG_EVEN, REG_ODD,
        !           111:   REG, 0, SI_ONLY, SI_ONLY,
        !           112:   SI_ONLY, SI_ONLY
        !           113: };
1.1.1.2   root      114: 
1.1       root      115: /* Local label counter, used for constants in the pool and inside
                    116:    pattern branches.  */
                    117: static int lf = 100;
                    118: 
1.1.1.3 ! root      119: 
        !           120: /* Number of bytes pushed for anonymous args, used to pass information
        !           121:    between expand_prologue and expand_epilogue. */
        !           122: static int extra_push;
1.1       root      123: 
                    124: 
1.1.1.3 ! root      125: 
1.1.1.2   root      126: void
                    127: push (rn)
1.1.1.3 ! root      128:      int rn;
1.1       root      129: {
1.1.1.3 ! root      130:   rtx x ;
        !           131:   x=  emit_insn (gen_push (gen_rtx (REG, SImode, rn)));
        !           132:   REG_NOTES (x) = gen_rtx (EXPR_LIST, REG_INC, 
        !           133:                           gen_rtx(REG, SImode, STACK_POINTER_REGNUM), 0);
1.1       root      134: }
                    135: 
1.1.1.2   root      136: void
                    137: pop (rn)
1.1.1.3 ! root      138:      int rn;
1.1       root      139: {
1.1.1.3 ! root      140:   rtx x;
        !           141:   x =  emit_insn (gen_pop (gen_rtx (REG, SImode, rn)));
        !           142:   REG_NOTES (x) = gen_rtx (EXPR_LIST, REG_INC, 
        !           143:                           gen_rtx(REG, SImode, STACK_POINTER_REGNUM), 0);
1.1       root      144: }
                    145: 
                    146: 
1.1.1.2   root      147: /* Adjust the stack and return the number of bytes taken to do it */
1.1.1.3 ! root      148: static rtx lastreg;
        !           149: int lastval;
1.1.1.2   root      150: static void
1.1.1.3 ! root      151: output_stack_adjust (size)
1.1.1.2   root      152:      int size;
1.1       root      153: {
1.1.1.2   root      154:   if (size)
1.1       root      155:     {
1.1.1.2   root      156:       rtx val = GEN_INT (size);
                    157:       rtx insn;
1.1       root      158: 
1.1.1.3 ! root      159:       if (!CONST_OK_FOR_I (size))
1.1.1.2   root      160:        {
1.1.1.3 ! root      161:          lastreg = gen_rtx (REG, SImode, 3);
        !           162:          lastval = size;
        !           163:          emit_insn (gen_movsi (lastreg, val));
        !           164:          val = lastreg;
1.1       root      165: 
1.1.1.3 ! root      166:        }
1.1       root      167: 
1.1.1.3 ! root      168:       insn = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, val);
1.1.1.2   root      169:       emit_insn (insn);
                    170:     }
1.1       root      171: }
                    172: 
                    173: 
1.1.1.2   root      174: /* Generate code to push the regs specified in the mask, and return
                    175:    the number of bytes the insns take. */
1.1       root      176: 
                    177: static void
1.1.1.2   root      178: push_regs (mask)
                    179:      int mask;
1.1       root      180: {
                    181:   int i;
                    182: 
1.1.1.2   root      183:   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1.1       root      184:     {
1.1.1.2   root      185:       if (mask & (1 << i))
1.1       root      186:        {
1.1.1.2   root      187:          push (i);
1.1       root      188:        }
                    189:     }
                    190: }
                    191: 
                    192: 
1.1.1.3 ! root      193: /* Print an instruction which would have gone into a delay slot after
        !           194:    an instructiuon, but couldn't because the instruction expanded into a
        !           195:    sequence where putting the slot insn at the end wouldn't work. */
1.1       root      196: 
1.1.1.3 ! root      197: static void
1.1.1.2   root      198: print_slot (insn)
                    199:      rtx insn;
                    200: {
                    201:   final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file, optimize, 0, 1);
1.1       root      202: 
1.1.1.2   root      203:   INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
1.1       root      204: }
                    205: 
                    206: 
                    207: /* Work out the registers which need to be saved, both as a mask and a
1.1.1.3 ! root      208:    count.
1.1       root      209: 
1.1.1.3 ! root      210:    If doing a pragma interrupt function, then push all regs used by the function,
        !           211:    and if we call another function (we can tell by looking at PR), make sure that all the
        !           212:    regs it clobbers are safe too.
        !           213:  */
        !           214: static int
        !           215: calc_live_regs (count_ptr)
        !           216:      int *count_ptr;
1.1       root      217: {
                    218:   int reg;
                    219:   int live_regs_mask = 0;
1.1.1.3 ! root      220:   int count = 0;
1.1       root      221:   for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg++)
                    222:     {
1.1.1.3 ! root      223:       if (reg == ARG_POINTER_REGNUM)
        !           224:        continue;
        !           225:       if (reg == T_REG)
        !           226:        continue;
        !           227:       if (reg == GBR_REG)
        !           228:        continue;
        !           229: 
        !           230:       if (pragma_interrupt && !pragma_trapa)
        !           231:        {
        !           232:          /* Need to save all the regs ever live */
        !           233:          if ((regs_ever_live[reg]
        !           234:               || (call_used_regs[reg] && regs_ever_live[PR_REG]))
        !           235:              && reg != 15)
        !           236:            {
        !           237:              live_regs_mask |= 1 << reg;
        !           238:              count++;
        !           239:            }
        !           240:        }
        !           241:       else if (TARGET_SMALLCALL)
1.1       root      242:        {
1.1.1.3 ! root      243:          /* Don't need to push anthing, but count the regs which have
        !           244:             been pushed by the wrapper */
        !           245:          if (call_used_regs[reg])
        !           246:            count++;
        !           247:        }
        !           248:       else
        !           249:        {
        !           250:          /* Only push those regs which are used and need to be saved */
        !           251:          if (regs_ever_live[reg] && !call_used_regs[reg])
        !           252:            {
        !           253:              count++;
        !           254:              live_regs_mask |= (1 << reg);
        !           255:            }
1.1       root      256:        }
                    257:     }
1.1.1.3 ! root      258: 
        !           259: 
        !           260:   *count_ptr = count;
1.1       root      261:   return live_regs_mask;
                    262: }
1.1.1.2   root      263: 
1.1       root      264: 
1.1.1.2   root      265: static int
                    266: need_slot (insn)
                    267:      rtx insn;
1.1       root      268: {
1.1.1.2   root      269:   return (insn && !INSN_ANNULLED_BRANCH_P (XVECEXP (insn, 0, 0)));
1.1       root      270: }
1.1.1.2   root      271: 
1.1       root      272: /* Print the operand address in x to the stream */
                    273: 
                    274: void
                    275: print_operand_address (stream, x)
                    276:      FILE *stream;
                    277:      rtx x;
                    278: {
                    279:   switch (GET_CODE (x))
                    280:     {
                    281:     case REG:
                    282:       fprintf (stream, "@%s", reg_names[REGNO (x)]);
                    283:       break;
                    284:     case PLUS:
                    285:       {
                    286:        rtx base = XEXP (x, 0);
                    287:        rtx index = XEXP (x, 1);
                    288: 
                    289:        if (GET_CODE (base) != REG)
                    290:          {
                    291:            /* Ensure that BASE is a register (one of them must be). */
                    292:            rtx temp = base;
                    293:            base = index;
                    294:            index = temp;
                    295:          }
                    296: 
                    297:        switch (GET_CODE (index))
                    298:          {
                    299:          case CONST_INT:
                    300:            fprintf (stream, "@(%d,%s)",
                    301:                     INTVAL (index),
                    302:                     reg_names[REGNO (base)]);
                    303:            break;
                    304: 
                    305:          case REG:
1.1.1.2   root      306:            fprintf (stream, "@(r0,%s)",
                    307:                     reg_names[MAX (REGNO (base), REGNO (index))]);
                    308: 
1.1       root      309:            break;
                    310: 
                    311:          default:
1.1.1.2   root      312:            debug_rtx (x);
1.1       root      313:            abort ();
                    314:          }
                    315:       }
                    316: 
                    317:       break;
                    318:     case PRE_DEC:
                    319:       fprintf (stream, "@-%s", reg_names[REGNO (XEXP (x, 0))]);
                    320:       break;
                    321: 
                    322:     case POST_INC:
                    323:       fprintf (stream, "@%s+", reg_names[REGNO (XEXP (x, 0))]);
                    324:       break;
                    325: 
                    326:     default:
                    327:       output_addr_const (stream, x);
                    328:       break;
                    329:     }
                    330: }
                    331: 
                    332: /* Print operand x (an rtx) in assembler syntax to file stream
                    333:    according to modifier code.
                    334: 
1.1.1.2   root      335:    '.'  print a .s if insn needs delay slot
                    336:    '*'  print a local label
                    337:    '^'  increment the local label number
                    338:    '!'  dump the constant table
                    339:    '#'  output a nop if there is nothing to put in the delay slot
1.1.1.3 ! root      340:    '@'  print rte or rts depending upon pragma interruptness
1.1.1.2   root      341:    'R'  print the next register or memory location along, ie the lsw in
                    342:    a double word value
                    343:    'O'  print a constant without the #
                    344:    'M'  print a constant as its negative
1.1.1.3 ! root      345:    'N'  print insides of a @++ or @-- o */
1.1       root      346: 
                    347: void
                    348: print_operand (stream, x, code)
                    349:      FILE *stream;
                    350:      rtx x;
                    351:      int code;
                    352: {
                    353:   switch (code)
                    354:     {
1.1.1.2   root      355:     case '.':
                    356:       if (need_slot (final_sequence))
                    357:        fprintf (stream, ".s");
                    358:       break;
1.1       root      359:     case '*':
                    360:       fprintf (stream, "LF%d", lf);
                    361:       break;
                    362:     case '^':
                    363:       lf++;
                    364:       break;
1.1.1.3 ! root      365:     case '@':
        !           366:       if (pragma_interrupt)
        !           367:        fprintf (stream, "rte");
        !           368:       else
        !           369:        fprintf (stream, "rts");
        !           370:       break;
1.1       root      371:     case '#':
                    372:       /* Output a nop if there's nothing in the delay slot */
                    373:       if (dbr_sequence_length () == 0)
                    374:        {
1.1.1.3 ! root      375:          fprintf (stream, "\n\tnop");
1.1       root      376:        }
                    377:       break;
1.1.1.2   root      378:     case 'O':
1.1.1.3 ! root      379:       output_addr_const (stream, x);
1.1       root      380:       break;
1.1.1.2   root      381:     case 'M':
                    382:       fprintf (asm_out_file, "#%d", -INTVAL (x));
                    383:       break;
1.1.1.3 ! root      384:     case 'N':
        !           385:       fputs (reg_names[REGNO (XEXP (XEXP (x, 0), 0))], (stream));
        !           386:       break;
1.1       root      387:     case 'R':
1.1.1.3 ! root      388:       /* Next location along in memory or register */
1.1       root      389:       switch (GET_CODE (x))
                    390:        {
                    391:        case REG:
                    392:          fputs (reg_names[REGNO (x) + 1], (stream));
                    393:          break;
                    394:        case MEM:
1.1.1.3 ! root      395:          print_operand_address (stream, XEXP (adj_offsettable_operand (x, 4), 0));
1.1       root      396:          break;
                    397:        }
                    398:       break;
                    399:     default:
                    400:       switch (GET_CODE (x))
                    401:        {
                    402:        case REG:
                    403:          fputs (reg_names[REGNO (x)], (stream));
                    404:          break;
                    405:        case MEM:
                    406:          output_address (XEXP (x, 0));
                    407:          break;
                    408:        default:
                    409:          fputc ('#', stream);
                    410:          output_addr_const (stream, x);
                    411:          break;
                    412:        }
                    413:       break;
                    414:     }
                    415: }
                    416: 
                    417: 
1.1.1.3 ! root      418: static int
        !           419: sextb (x)
        !           420:   int x;
        !           421: {
        !           422:   x &= 0xff;
        !           423:   if (x > 127)
        !           424:     {
        !           425:       x = -256 + x;
        !           426:     }
        !           427:   return x;
        !           428: }
        !           429: 
1.1.1.2   root      430: 
1.1       root      431: 
1.1.1.3 ! root      432: /* Take a move with integer constant source in OPERANDS, see if it can be generated by
        !           433:    devious shifting.  If so, generate the instruction sequence and return 1, otherwise
        !           434:    return 0.
        !           435: 
        !           436:     OPERANDS[0] Destination register
        !           437:     OPERANDS[1] Source constant
        !           438: 
        !           439:    00000000 00000000 00000000 0NNNNNNNN simple load
        !           440:    00000000 00000000 00000000 NNNNNNNN0 load and shift by 1
        !           441:    00000000 00000000 0000000N NNNNNNN00 load and shift by 2
        !           442:    00000000 00000000 0NNNNNNN 000000000 load and shift by 8
        !           443:    00000000 0NNNNNNN 00000000 000000000 load and shift by 16
        !           444:    N0000000 00000000 00000000 00NNNNNNN load and rotate right
        !           445: 
        !           446:    11111111 11111111 11111111 1NNNNNNNN simple load
        !           447:    11111111 11111111 11111111 NNNNNNNN0 load and shift by 1
        !           448:    11111111 11111111 1111111N NNNNNNN00 load and shift by 2
        !           449:    11111111 11111111 1NNNNNNN 000000000 load and shift by 8
        !           450:    11111111 1NNNNNNN 00000000 000000000 load and shift by 16
        !           451:    N1111111 11111111 11111111 11NNNNNNN load and rotate right
        !           452: 
        !           453:    00000000 00000000 00000000 1NNNNNNNN load and zero extend byte
        !           454:    00000000 00000000 11111111 1NNNNNNNN load and zero extend word
        !           455: 
        !           456: 
        !           457: */
        !           458: 
        !           459: static int
        !           460: synth_constant (operands, mode)
        !           461:      rtx operands[];
        !           462:      enum machine_mode mode;
1.1       root      463: {
1.1.1.3 ! root      464:   rtx dst;
        !           465:   int i = INTVAL (operands[1]) & 0xffffffff;
        !           466:     
        !           467:   if (CONST_OK_FOR_I (i))
        !           468:     return 0;
1.1       root      469: 
1.1.1.3 ! root      470:   if (TARGET_CLEN0 && mode != QImode)
        !           471:     return 0;
1.1       root      472: 
1.1.1.3 ! root      473:   if (mode != SImode)
        !           474:     {
        !           475:       if (reload_in_progress)
        !           476:        return 0;
        !           477:       dst = gen_reg_rtx (SImode);
        !           478:     }
        !           479:   else
1.1       root      480:     {
1.1.1.3 ! root      481:       dst = operands[0];
1.1       root      482:     }
                    483: 
1.1.1.3 ! root      484: 
        !           485:   /*  00000000 00000000 11111111 1NNNNNNNN load and zero extend word      */
        !           486:   if ((i & 0xffffff80) == 0x0000ff80)
1.1       root      487:     {
1.1.1.3 ! root      488:       emit_move_insn (dst, GEN_INT (sextb (i)));
        !           489:       emit_insn (gen_and_ffff (dst, dst));
        !           490:     }
        !           491:   /*    00000000 00000000 00000000 1NNNNNNNN load and zero extend byte */
        !           492:   else if ((i & 0xffffff80) == 0x00000080)
        !           493:     {
        !           494:       emit_move_insn (dst, GEN_INT (sextb (i)));
        !           495:       emit_insn (gen_and_ff (dst, dst));
        !           496:     }
        !           497:   /*   00000000 00000000 00000000 NNNNNNNN0 load and shift by 1
        !           498:        11111111 11111111 11111111 NNNNNNNN0 load and shift by 1 */
        !           499:   else if ((i & 0xffffff01) == 0
        !           500:           || (i & 0xffffff01) == 0xffffff00)
        !           501:     {
        !           502:       emit_move_insn (dst, GEN_INT (sextb (i >> 1)));
        !           503:       emit_insn (gen_ashlsi3_n (dst, dst, GEN_INT (1)));
        !           504:     }
        !           505:   /*   00000000 00000000 0000000N NNNNNNN00 load and shift by 2
        !           506:        11111111 11111111 1111111N NNNNNNN00 load and shift by 2*/
        !           507:   else if ((i & 0xfffffe03) == 0
        !           508:           || (i & 0xfffffe03) == 0xfffffe00)
        !           509:     {
        !           510:       emit_move_insn (dst, GEN_INT (sextb (i >> 2)));
        !           511:       emit_insn (gen_ashlsi3_n (dst, dst, GEN_INT (2)));
1.1       root      512:     }
1.1.1.3 ! root      513:   /*   00000000 00000000 0NNNNNNN 000000000 load and shift by 8
        !           514:        11111111 11111111 1NNNNNNN 000000000 load and shift by 8 */
1.1       root      515: 
1.1.1.3 ! root      516:   else if ((i & 0xffff80ff) == 0
        !           517:           || (i & 0xffff80ff) == 0xffff8000)
        !           518:     {
        !           519:       emit_move_insn (dst, GEN_INT (sextb (i >> 8)));
        !           520:       emit_insn (gen_ashlsi3_n (dst, dst, GEN_INT (8)));
        !           521:     }
        !           522:   /*     00000000 0NNNNNNN 00000000 000000000 load and shift by 16
        !           523:         11111111 1NNNNNNN 00000000 000000000 load and shift by 16 */
        !           524:   else if ((i & 0xff80ffff) == 0x00000000
        !           525:           || (i & 0xff80ffff) == 0xff800000)
        !           526:     {
        !           527:       emit_move_insn (dst, GEN_INT (sextb (i >> 16)));
        !           528:       emit_insn (gen_ashlsi3_n (dst, dst, GEN_INT (16)));
        !           529:     }
        !           530:   /*   00000000 00000000 0NNNNNNN 0NNNNNNNN load shift 8 and add */
        !           531:   else if ((i & 0xffff8080) == 0 && TARGET_CLEN3)
1.1       root      532:     {
1.1.1.3 ! root      533:       emit_move_insn (dst, GEN_INT (sextb (i >> 8)));
        !           534:       emit_insn (gen_ashlsi3_n (dst, dst, GEN_INT (8)));
        !           535:       emit_insn (gen_addsi3 (dst, dst, GEN_INT (i & 0x7f)));
1.1       root      536:     }
1.1.1.3 ! root      537:   else
        !           538:     return 0;
        !           539: 
        !           540:   if (mode == DImode)
        !           541:     {
        !           542:       /* Moving from SI to DI, we've got to zero out the high part */
        !           543: 
        !           544:       emit_insn (gen_rtx (SET, VOIDmode, 
        !           545:                          gen_rtx (SUBREG, SImode, operands[0], 0),
        !           546:                          dst));
        !           547:       emit_insn (gen_rtx (SET, VOIDmode,
        !           548:                          gen_rtx (SUBREG, SImode, operands[0], 1),
        !           549:                          const0_rtx));
        !           550: 
        !           551:     }
        !           552:   else if (mode != SImode)
        !           553:     {
        !           554:       emit_insn (gen_rtx (SET, VOIDmode, operands[0],
        !           555:                          gen_rtx (SUBREG, mode, dst, 0)));
        !           556: 
        !           557:     }
        !           558:   return 1;
1.1       root      559: }
                    560: 
                    561: 
1.1.1.3 ! root      562: /* Emit code to perform a block move.  Choose the best method.
        !           563: 
        !           564:    OPERANDS[0] is the destination.
        !           565:    OPERANDS[1] is the source.
        !           566:    OPERANDS[2] is the size.
        !           567:    OPERANDS[3] is the alignment safe to use.  */
        !           568: 
        !           569: 
        !           570: int
        !           571: expand_block_move (operands)
        !           572:      rtx *operands;
        !           573: {
        !           574:   int align = INTVAL (operands[3]);
        !           575:   int constp = (GET_CODE (operands[2]) == CONST_INT);
        !           576:   int bytes = (constp ? INTVAL (operands[2]) : 0);
        !           577:   enum machine_mode mode;
        !           578: 
        !           579:   /* IF odd then fail */
        !           580:   if (!constp || bytes <= 0)
        !           581:     return 0;
        !           582: 
        !           583:   /* Don't expand if we'd make the code bigger and we don't want big code */
        !           584: 
        !           585:   if (bytes > 8 && TARGET_SMALLCODE)
        !           586:     return 0;
        !           587: 
        !           588:   switch (align)
        !           589:     {
        !           590:     case 1:
        !           591:       mode = QImode;
        !           592:       break;
        !           593:     case 2:
        !           594:       mode = HImode;
        !           595:       break;
        !           596:     default:
        !           597:       mode = SImode;
        !           598:       align = 4;
        !           599:     }
        !           600: 
        !           601:   if (mode == SImode && constp && bytes < 64 && (bytes % 4 == 0))
        !           602:     {
        !           603:       char entry[30];
        !           604:       tree entry_name;
        !           605:       rtx func_addr_rtx;
        !           606:       rtx r4 = gen_rtx (REG, SImode, 4);
        !           607:       rtx r5 = gen_rtx (REG, SImode, 5);
        !           608:       sprintf (entry, "__movstr%s%d", GET_MODE_NAME (mode), bytes);
        !           609:       entry_name = get_identifier (entry);
        !           610: 
        !           611:       func_addr_rtx = copy_to_mode_reg (Pmode,
        !           612:              gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (entry_name)));
        !           613:       emit_insn (gen_move_insn (r4, XEXP (operands[0], 0)));
        !           614:       emit_insn (gen_move_insn (r5, XEXP (operands[1], 0)));
        !           615:       emit_insn (gen_block_move_real (func_addr_rtx));
        !           616:       return 1;
        !           617:     }
        !           618:   if (mode == SImode && constp && (bytes % 4 == 0))
        !           619:     {
        !           620:       tree entry_name;
        !           621:       rtx func_addr_rtx;
        !           622:       rtx r4 = gen_rtx (REG, SImode, 4);
        !           623:       rtx r5 = gen_rtx (REG, SImode, 5);
        !           624:       rtx r6 = gen_rtx (REG, SImode, 6);
        !           625:       entry_name = get_identifier ("__movstr");
        !           626: 
        !           627:       func_addr_rtx = copy_to_mode_reg (Pmode,
        !           628:                                        gen_rtx (SYMBOL_REF, Pmode,
        !           629:                                          IDENTIFIER_POINTER (entry_name)));
        !           630:       emit_insn (gen_move_insn (r4, XEXP (operands[0], 0)));
        !           631:       emit_insn (gen_move_insn (r5, XEXP (operands[1], 0)));
        !           632: 
        !           633:       /* r6 controls the size of the move, 16 is decremented from it
        !           634:         for each 64 bytes moved, then the -ve bit is used as an index into a
        !           635:         list of move instructions like this:
        !           636:        
        !           637:         {
        !           638:         do {
        !           639:         *dst++ = *src++;
        !           640:         *dst++ = *src++;
        !           641:         *dst++ = *src++;
        !           642:         ..etc.. 16 in all
        !           643:         *dst++ = *src++;
        !           644:         *dst++ = *src++;
        !           645:         size -= 16;
        !           646:         } while (size > 0);
        !           647:        
        !           648:         switch (size)
        !           649:         {
        !           650:         case -15:
        !           651:         *dst++ = *src++;
        !           652:         case -14:
        !           653:         *dst++ = *src++;
        !           654:         .. etc.. ;
        !           655:         case -2:
        !           656:         *dst++ = *src++;
        !           657:         case -1:
        !           658:         *dst++ = *src++;
        !           659:         case 0:
        !           660:         ;
        !           661:         }
        !           662:         }
        !           663:        
        !           664:         eg, a 72 byte move would be set up with size(r6) = 14, for one
        !           665:         iteration through the big while loop, and a switch of -2 for the last part  */
        !           666: 
        !           667:       {
        !           668:        int final_switch = 16 - ((bytes / 4) % 16);
        !           669:        int while_loop = ((bytes / 4) / 16 - 1) * 16;
        !           670:        emit_insn (gen_move_insn (r6, GEN_INT (while_loop + final_switch)));
        !           671:        emit_insn (gen_block_lump_real (func_addr_rtx));
        !           672:        return 1;
        !           673:       }
        !           674:     }
        !           675: 
        !           676:   return 0;
        !           677: }
        !           678: 
1.1       root      679: /* Prepare operands for a move define_expand; specifically, one of the
1.1.1.2   root      680:    operands must be in a register.  Take this chance to remove
                    681:    addressing modes which can't be coped with very well. */
1.1       root      682: 
1.1.1.2   root      683: int
1.1       root      684: prepare_move_operands (operands, mode)
                    685:      rtx operands[];
                    686:      enum machine_mode mode;
                    687: {
1.1.1.3 ! root      688:   if (!(reload_in_progress || reload_completed)
        !           689:       && ((!register_operand (operands[0], mode)
        !           690:           && !register_operand (operands[1], mode))
        !           691:          || GET_CODE (operands[1]) == PLUS))
1.1       root      692:     {
                    693:       /* copy the source to a register */
                    694:       operands[1] = copy_to_mode_reg (mode, operands[1]);
                    695:     }
1.1.1.3 ! root      696:   if ((mode == SImode || mode == HImode || mode == QImode)
        !           697:       && GET_CODE (operands[1]) == CONST_INT)
        !           698:     {
        !           699:       return synth_constant (operands, mode);
        !           700:     }
        !           701:   if (mode == DFmode || mode == DImode)
1.1.1.2   root      702:     {
1.1.1.3 ! root      703:       rtx src = operands[1];
        !           704:       rtx dst = operands[0];
        !           705:       rtx insns;
1.1.1.2   root      706: 
1.1.1.3 ! root      707:       if (src == dst)
1.1.1.2   root      708:        {
1.1.1.3 ! root      709:          emit_insn (gen_rtx (SET, VOIDmode, dst, src));
        !           710:          return 1;
        !           711:        }
1.1.1.2   root      712: 
1.1.1.3 ! root      713:       if (GET_CODE (src) == REG &&
        !           714:          REGNO (src) >= FIRST_PSEUDO_REGISTER)
        !           715:        return 0;
        !           716: 
        !           717:       if (GET_CODE (dst) == REG &&
        !           718:          REGNO (dst) >= FIRST_PSEUDO_REGISTER)
        !           719:        return 0;
        !           720: 
        !           721:       if (push_operand (dst, mode))
        !           722:        return 0;
        !           723: 
        !           724:       if (GET_CODE (src) == CONST_DOUBLE)
        !           725:        src = force_const_mem (DFmode, src);
        !           726: 
        !           727:       if (reload_in_progress)
        !           728:        {
        !           729:          if (!(offsettable_memref_p (src) || register_operand (src, mode)))
        !           730:            return 0;
        !           731:          if (!(offsettable_memref_p (dst) || register_operand (dst,
        !           732:                                                                mode)))
        !           733:            return 0;
        !           734:        }
        !           735:       start_sequence ();
        !           736:       if (GET_CODE (operands[0]) != REG
        !           737:          || !refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1, operands[1], 0))
        !           738:        {
        !           739:          emit_move_insn (operand_subword (dst, 0, 1, mode),
        !           740:                          operand_subword_force (src, 0, mode));
        !           741:          emit_move_insn (operand_subword (dst, 1, 1, mode),
        !           742:                          operand_subword_force (src, 1, mode));
        !           743:        }
        !           744:       else
        !           745:        {
        !           746:          emit_move_insn (operand_subword (dst, 1, 1, mode),
        !           747:                          operand_subword_force (src, 1, mode));
        !           748:          emit_move_insn (operand_subword (dst, 0, 1, mode),
        !           749:                          operand_subword_force (src, 0, mode));
1.1.1.2   root      750:        }
1.1.1.3 ! root      751: 
        !           752:       insns = get_insns ();
        !           753:       end_sequence ();
        !           754: 
        !           755:       emit_no_conflict_block (insns, dst, src, 0, src);
        !           756:       return 1;
1.1.1.2   root      757:     }
1.1.1.3 ! root      758: 
1.1.1.2   root      759:   return 0;
1.1       root      760: }
                    761: 
                    762: /* Prepare the operands for an scc instruction; make sure that the
                    763:    compare has been done.  */
                    764: rtx
                    765: prepare_scc_operands (code)
1.1.1.3 ! root      766:      int code;
1.1       root      767: {
1.1.1.2   root      768:   if (GET_CODE (sh_compare_op0) != REG
                    769:       || REGNO (sh_compare_op0) != T_REG)
1.1       root      770:     {
1.1.1.3 ! root      771:       int newcode = code;
1.1       root      772:       /* First need a compare insn */
1.1.1.3 ! root      773:       switch (code)
        !           774:        {
        !           775:        case NE:
        !           776:          newcode = EQ;
        !           777:          break;
        !           778:        case LT:
        !           779:          newcode = GT;
        !           780:          break;
        !           781:        case LE:
        !           782:          newcode = GE;
        !           783:          break;
        !           784:        case LTU:
        !           785:          newcode = GTU;
        !           786:          break;
        !           787:        case LEU:
        !           788:          newcode = GEU;
        !           789:          break;
        !           790:        }
        !           791:       if (newcode != code)
        !           792:        {
        !           793:          rtx tmp = sh_compare_op0;
        !           794:          sh_compare_op0 = sh_compare_op1;
        !           795:          sh_compare_op1 = tmp;
        !           796:          code = newcode;
        !           797:        }
        !           798: 
        !           799:       sh_compare_op0 = force_reg (SImode, sh_compare_op0);
        !           800:       emit_insn (gen_rtx (SET, VOIDmode,
1.1       root      801:                          gen_rtx (REG, SImode, T_REG),
1.1.1.3 ! root      802:                   gen_rtx (code, SImode, sh_compare_op0, sh_compare_op1)));
1.1       root      803:     }
1.1.1.2   root      804:   return gen_rtx (REG, SImode, T_REG);
1.1       root      805: }
                    806: 
1.1.1.2   root      807: 
1.1.1.3 ! root      808: /* Functions to output assembly code. */
1.1       root      809: 
1.1.1.2   root      810: /* Return a sequence of instructions to perform DI or DF move.
1.1       root      811: 
1.1.1.2   root      812:    Since the SH cannot move a DI or DF in one instruction, we have
                    813:    to take care when we see overlapping source and dest registers.
                    814: 
                    815:  */
1.1.1.3 ! root      816: 
1.1       root      817: char *
1.1.1.3 ! root      818: output_movedouble (insn, operands, mode)
        !           819:      rtx insn;
1.1       root      820:      rtx operands[];
                    821:      enum machine_mode mode;
                    822: {
1.1.1.2   root      823:   rtx dst = operands[0];
                    824:   rtx src = operands[1];
                    825: 
1.1.1.3 ! root      826: /*   fprintf (asm_out_file, "! move double \n");
        !           827:   fprintf (asm_out_file, "! pc %04x\n", insn_addresses[INSN_UID (insn)]);*/
        !           828:   if (GET_CODE (dst) == MEM
        !           829:       && GET_CODE (XEXP (dst, 0)) == POST_INC)
        !           830:     {
        !           831:       operands[0] = XEXP (XEXP (dst, 0), 0);
        !           832:       return "mov.l    %R1,@(4,%0)\n\tmov.l    %1,@%0\n\tadd   #8,%0";
        !           833:     }
1.1.1.2   root      834:   if (register_operand (dst, mode)
                    835:       && register_operand (src, mode))
1.1       root      836:     {
1.1.1.2   root      837:       if (REGNO (src) == MACH_REG)
1.1       root      838:        return "sts     mach,%0\n\tsts  macl,%R0";
                    839: 
1.1.1.2   root      840:       /*
1.1.1.3 ! root      841:          when mov.d r1,r2 do r2->r3 then r1->r2
        !           842:          when mov.d r1,r0 do r1->r0 then r2->r1
        !           843:        */
1.1.1.2   root      844: 
                    845:       if (REGNO (src) + 1 == REGNO (dst))
1.1.1.3 ! root      846:        return "mov     %R1,%R0\n\tmov  %1,%0 ! cra";
1.1.1.2   root      847:       else
1.1.1.3 ! root      848:        return "mov     %1,%0\n\tmov    %R1,%R0 ! crb";
1.1.1.2   root      849:     }
                    850:   else if (GET_CODE (src) == CONST_INT)
1.1       root      851:     {
1.1.1.3 ! root      852:       HOST_WIDE_INT val = INTVAL (src);
        !           853:       int rn = REGNO (operands[0]);
        !           854:       if (val < 0)
        !           855:        {
        !           856:          fprintf (asm_out_file, "\tmov #-1,r%d\n", rn);
        !           857:        }
1.1       root      858:       else
1.1.1.3 ! root      859:        {
        !           860:          fprintf (asm_out_file, "\tmov #0,r%d\n", rn);
        !           861:        }
1.1       root      862: 
1.1.1.3 ! root      863:       fprintf (asm_out_file, "\tmov    #%d,r%d\n", val, rn + 1);
        !           864:       return "";
        !           865:     }
1.1.1.2   root      866:   else if (GET_CODE (src) == MEM)
1.1       root      867:     {
1.1.1.2   root      868:       int ptrreg1 = -1;
                    869:       int ptrreg2 = -1;
                    870:       int dreg = REGNO (dst);
                    871:       rtx inside = XEXP (src, 0);
1.1       root      872: 
                    873:       if (GET_CODE (inside) == REG)
1.1.1.2   root      874:        {
                    875:          ptrreg1 = REGNO (inside);
                    876:        }
1.1       root      877:       else if (GET_CODE (inside) == PLUS)
                    878:        {
                    879:          rtx lhs = XEXP (inside, 0);
                    880:          rtx rhs = XEXP (inside, 1);
                    881:          if (GET_CODE (lhs) == REG)
1.1.1.2   root      882:            ptrreg1 = REGNO (lhs);
                    883:          if (GET_CODE (rhs) == REG)
                    884:            ptrreg2 = REGNO (rhs);
1.1       root      885:        }
1.1.1.3 ! root      886:       else if (GET_CODE (inside) == LABEL_REF)
        !           887:        {
        !           888:          return "mov.l %1,%0\n\tmov.l  %1+4,%R0";
        !           889:        }
        !           890:       else if (GET_CODE (inside) == POST_INC)
        !           891:        {
        !           892:          return "mov.l %1,%0\n\tmov.l  %1,%R0 !mdi\n";
        !           893:        }
1.1       root      894:       else
                    895:        abort ();
                    896: 
1.1.1.2   root      897:       if ((ptrreg1 >= 0 && ptrreg2 >= 0)
                    898:          && (dreg == ptrreg1
                    899:              || dreg == ptrreg2
                    900:              || dreg + 1 == ptrreg1
                    901:              || dreg + 1 == ptrreg2))
                    902:        {
                    903:          /* This move clobbers both index registers,
                    904:             calculate the sum in one register.  */
                    905:          fprintf (asm_out_file, "      add     %s,%s ! special fix\n",
                    906:                   reg_names[ptrreg2], reg_names[ptrreg1]);
                    907: 
                    908:          if (dreg == ptrreg1)
                    909:            {
                    910:              /* Copy into dreg+1 first.  */
                    911:              fprintf (asm_out_file, "  mov.l   @(4,%s),%s\n",
                    912:                       reg_names[ptrreg1],
                    913:                       reg_names[dreg + 1]);
                    914: 
                    915:              fprintf (asm_out_file, "  mov.l   @(%s),%s\n",
                    916:                       reg_names[ptrreg1],
                    917:                       reg_names[dreg]);
                    918:            }
                    919:          else
                    920:            {
                    921:              /* Copy into dreg first. */
                    922:              fprintf (asm_out_file, "  mov.l   @(%s),%s\n",
                    923:                       reg_names[ptrreg1],
                    924:                       reg_names[dreg]);
                    925: 
                    926:              fprintf (asm_out_file, "  mov.l   @(4,%s),%s\n",
                    927:                       reg_names[ptrreg1],
                    928:                       reg_names[dreg + 1]);
                    929: 
                    930:            }
                    931:          warning ("generated complex amode");
                    932:          return "";
                    933:        }
                    934: 
                    935:       /* Work out the safe way to copy */
                    936:       if (dreg == ptrreg1)
1.1       root      937:        {
1.1.1.2   root      938:          /* Copy into the second half first */
                    939:          return "mov.l %R1,%R0\n\tmov.l        %1,%0 ! cr";
1.1       root      940:        }
                    941:     }
                    942: 
1.1.1.2   root      943:   return "mov.l        %1,%0\n\tmov.l  %R1,%R0";
1.1       root      944: }
                    945: 
                    946: /* Emit assembly to shift reg by k bits */
                    947: 
                    948: char *
1.1.1.2   root      949: output_shift (string, reg, k, code)
1.1       root      950:      char *string;
                    951:      rtx reg;
                    952:      rtx k;
1.1.1.2   root      953:      int code;
                    954: 
1.1       root      955: {
                    956:   int s = INTVAL (k);
1.1.1.3 ! root      957:   if (s < 0)
        !           958:     {
        !           959:       s = -s;
        !           960:       switch (code)
        !           961:        {
        !           962:        case LSHIFTRT:
        !           963:        case ASHIFTRT:
        !           964:          code = ASHIFT;
        !           965:          break;
        !           966:        case ASHIFT:
        !           967:          code = ASHIFTRT;
        !           968:          break;
        !           969:        default:
        !           970:          abort ();
        !           971:        }
        !           972:     }
1.1.1.2   root      973:   if (code == ASHIFT && s == 31)
                    974:     {
                    975:       /* Shift left by 31 moving into the t bit, clearing and rotating the other way */
                    976: 
                    977:       fprintf (asm_out_file, "\trotr   r%d\n", REGNO (reg));
                    978:       fprintf (asm_out_file, "\tmov    #0,r%d\n", REGNO (reg));
                    979:       fprintf (asm_out_file, "\trotcr  r%d\n", REGNO (reg));
                    980:       s = 0;
                    981:     }
                    982: 
                    983:   if (code == LSHIFTRT && s == 31)
                    984:     {
                    985:       fprintf (asm_out_file, "\trotl   r%d\n", REGNO (reg));
                    986:       fprintf (asm_out_file, "\tmov    #0,r%d\n", REGNO (reg));
                    987:       fprintf (asm_out_file, "\trotcl  r%d\n", REGNO (reg));
                    988:       s = 0;
                    989:     }
                    990: 
1.1       root      991:   while (s)
                    992:     {
                    993:       char *out;
                    994:       int d;
                    995: 
                    996:       if (s >= 16)
                    997:        {
                    998:          d = 16;
                    999:          out = "16";
                   1000:        }
                   1001:       else if (s >= 8)
                   1002:        {
                   1003:          d = 8;
                   1004:          out = "8";
                   1005:        }
                   1006:       else if (s >= 2)
                   1007:        {
                   1008:          d = 2;
                   1009:          out = "2";
                   1010:        }
                   1011:       else
                   1012:        {
                   1013:          d = 1;
                   1014:          out = "";
                   1015:        }
                   1016:       fprintf (asm_out_file, "\t%s%s\tr%d\n", string, out, REGNO (reg));
                   1017:       s -= d;
                   1018:     }
                   1019:   return "";
                   1020: }
                   1021: 
1.1.1.3 ! root     1022: 
        !          1023: void
        !          1024: function_epilogue (stream, size)
        !          1025:      FILE *stream;
        !          1026:      int size;
        !          1027: {
        !          1028:   pragma_interrupt = pragma_trapa = 0;
        !          1029: }
        !          1030: 
        !          1031: 
1.1       root     1032: /* Return the text of the branch instruction which matches its length
1.1.1.2   root     1033:    attribute.
                   1034: 
                   1035:    This gets tricky if we have an insn in the delay slot of a branch
1.1.1.3 ! root     1036:    and the branch needs more than 1 insn to complete. */
        !          1037: 
        !          1038: int pending_const_table;
        !          1039: 
        !          1040:  /* We can't tell if we need a register as a scratch for the jump
        !          1041:     until after branch shortening, and then it's too late to allocate a
        !          1042:     register the 'proper' way.  These instruction sequences are rare
        !          1043:     anyway, so to avoid always using a reg up from our limited set, we'll
        !          1044:     grab one when we need one on output. */
        !          1045: 
        !          1046: char *
        !          1047: output_far_jump (insn, op)
        !          1048:      rtx insn;
        !          1049:      rtx op;
        !          1050: {
        !          1051:   rtx thislab = gen_label_rtx ();
        !          1052: 
        !          1053:   if (dbr_sequence_length ())
        !          1054:     {
        !          1055:       /* Something to go in what would have been the delay
        !          1056:         slot if this had been a short branch. Make sure the
        !          1057:         reg we use to generate the branch target address
        !          1058:         doesn't conflict */
1.1.1.2   root     1059: 
1.1.1.3 ! root     1060:       int i;
        !          1061:       rtx vec[2];
        !          1062:       vec[0] = thislab;
        !          1063: 
        !          1064:       for (i = 0; i < 8; i++)
        !          1065:        {
        !          1066:          vec[1] = gen_rtx (REG, SImode, i);
        !          1067:          if (!reg_referenced_p (vec[1],
        !          1068:                                 PATTERN (XVECEXP (final_sequence, 0, 1))))
        !          1069:            break;
        !          1070:        }
        !          1071: 
        !          1072: 
        !          1073:       print_slot (final_sequence);
        !          1074:       output_asm_insn ("mov.l  %1,@-r15", vec);
        !          1075:       output_asm_insn ("mov.l  %O0,%1", vec);
        !          1076: 
        !          1077:       output_asm_insn ("jmp    @%1 ! 32 xcond", vec);
        !          1078:       output_asm_insn ("mov.l  @r15+,%1", vec);
        !          1079:     }
        !          1080:   else
        !          1081:     {
        !          1082:       output_asm_insn ("mov.l  r13,@-r15", 0);
        !          1083:       output_asm_insn ("mov.l  %O0,r13", &thislab);
        !          1084:       output_asm_insn ("jmp    @r13 ! 32 zcond", 0);
        !          1085:       output_asm_insn ("mov.l  @r15+,r13", 0);
        !          1086:     }
1.1.1.2   root     1087: 
1.1.1.3 ! root     1088:   output_asm_insn (".align     2", 0);
        !          1089:   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (thislab));
        !          1090:   output_asm_insn (".long      %O0", &op);
        !          1091:   return "";
        !          1092: }
1.1       root     1093: 
                   1094: char *
                   1095: output_branch (logic, insn)
                   1096:      int logic;
1.1.1.2   root     1097:      rtx insn;
1.1       root     1098: {
                   1099:   extern rtx recog_operand[];
                   1100:   int label = lf++;
1.1.1.3 ! root     1101: 
        !          1102:   /*  fprintf (asm_out_file, "! pc %04x\n", insn_addresses[INSN_UID (insn)]);*/
1.1.1.2   root     1103: 
1.1       root     1104:   switch (get_attr_length (insn))
                   1105:     {
                   1106:     case 2:
                   1107:       /* Simple branch in range -200..+200 bytes */
1.1.1.2   root     1108:       return logic ? "bt%.     %l0" : "bf%.    %l0";
1.1       root     1109: 
                   1110:     case 6:
                   1111:       /* Branch in range -4000..+4000 bytes */
1.1.1.2   root     1112:       {
                   1113:        rtx oldop = recog_operand[0];
                   1114: 
                   1115: 
                   1116:        if (need_slot (final_sequence))
                   1117:          {
                   1118:            fprintf (asm_out_file, "\tb%c.s\tLF%d\n", logic ? 'f' : 't',
                   1119:                     label);
                   1120: 
                   1121:            print_slot (final_sequence);
                   1122:          }
                   1123: 
                   1124:        else
                   1125:          {
                   1126:            fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't',
                   1127:                     label);
                   1128:          }
                   1129:        recog_operand[0] = oldop;
                   1130: 
                   1131:        output_asm_insn ("bra   %l0     ! 12 bit cond ", recog_operand);
                   1132:        fprintf (asm_out_file, "\tor    r0,r0\n");
                   1133:        fprintf (asm_out_file, "LF%d:\n", label);
                   1134:       }
1.1       root     1135:       return "";
1.1.1.2   root     1136: 
1.1.1.3 ! root     1137:     case 16:
1.1.1.2   root     1138:       /* Branches a long way away */
                   1139:       {
                   1140:        rtx oldop = recog_operand[0];
                   1141: 
                   1142:        if (need_slot (final_sequence))
                   1143:          {
                   1144:            fprintf (asm_out_file, "\tb%c.s\tLF%d\n", logic ? 'f' : 't', label);
                   1145:            print_slot (final_sequence);
                   1146: 
                   1147:          }
                   1148:        else
                   1149:          {
                   1150:            fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't', label);
                   1151:          }
                   1152: 
1.1.1.3 ! root     1153:        output_far_jump (insn, oldop);
1.1.1.2   root     1154:        fprintf (asm_out_file, "LF%d:\n", label);
                   1155:        return "";
                   1156:       }
1.1       root     1157:     }
                   1158:   return "bad";
                   1159: }
                   1160: 
1.1.1.2   root     1161: 
1.1.1.3 ! root     1162: /* The SH cannot load a large constant into a register, constants have to
        !          1163:    come from a pc relative load.  The reference of a pc relative load
        !          1164:    instruction must be less than 1k infront of the instruction.  This
        !          1165:    means that we often have to dump a constant inside a function, and
        !          1166:    generate code to branch around it.
1.1       root     1167: 
1.1.1.3 ! root     1168:    It is important to minimize this, since the branches will slow things
        !          1169:    down and make things bigger.
1.1.1.2   root     1170: 
1.1.1.3 ! root     1171:    Worst case code looks like:
1.1       root     1172: 
1.1.1.3 ! root     1173:    mov.l L1,rn
        !          1174:    bra   L2
        !          1175:    nop
        !          1176:    align
        !          1177:    L1:   .long value
        !          1178:    L2:
        !          1179:    ..
1.1       root     1180: 
1.1.1.3 ! root     1181:    mov.l L3,rn
        !          1182:    bra   L4
        !          1183:    nop
        !          1184:    align
        !          1185:    L3:   .long value
        !          1186:    L4:
        !          1187:    ..
1.1       root     1188: 
1.1.1.3 ! root     1189:    We fix this by performing a scan before scheduling, which notices which
        !          1190:    instructions need to have their operands fetched from the constant table
        !          1191:    and builds the table.
1.1       root     1192: 
                   1193: 
1.1.1.3 ! root     1194:    The algorithm is:
1.1       root     1195: 
1.1.1.3 ! root     1196:    scan, find an instruction which needs a pcrel move.  Look forward, find the
        !          1197:    last barrier which is within MAX_COUNT bytes of the requirement.
        !          1198:    If there isn't one, make one.  Process all the instructions between
        !          1199:    the find and the barrier.
1.1       root     1200: 
                   1201:    In the above example, we can tell that L3 is within 1k of L1, so
                   1202:    the first move can be shrunk from the 3 insn+constant sequence into
                   1203:    just 1 insn, and the constant moved to L3 to make:
                   1204: 
1.1.1.3 ! root     1205:    mov.l        L1,rn
1.1       root     1206:    ..
1.1.1.3 ! root     1207:    mov.l        L3,rn
        !          1208:    bra          L4
1.1       root     1209:    nop
                   1210:    align
1.1.1.3 ! root     1211:    L3:.long value
        !          1212:    L4:.long value
1.1       root     1213: 
                   1214:    Then the second move becomes the target for the shortening process.
                   1215: 
1.1.1.3 ! root     1216:  */
1.1       root     1217: 
                   1218: typedef struct
                   1219: {
1.1.1.3 ! root     1220:   rtx value;                   /* Value in table */
        !          1221:   rtx label;                   /* Label of value */
        !          1222:   enum machine_mode mode;      /* Mode of value */
        !          1223: }
        !          1224: 
        !          1225: pool_node;
1.1       root     1226: 
                   1227: /* The maximum number of constants that can fit into one pool, since
                   1228:    the pc relative range is 0...1020 bytes and constants are at least 4
                   1229:    bytes long */
                   1230: 
                   1231: #define MAX_POOL_SIZE (1020/4)
                   1232: static pool_node pool_vector[MAX_POOL_SIZE];
                   1233: static int pool_size;
                   1234: 
1.1.1.3 ! root     1235: /* Add a constant to the pool and return its label.  */
1.1       root     1236: 
1.1.1.3 ! root     1237: static rtx
1.1       root     1238: add_constant (x, mode)
                   1239:      rtx x;
                   1240:      enum machine_mode mode;
                   1241: {
                   1242:   int i;
1.1.1.3 ! root     1243:   rtx lab;
1.1       root     1244:   /* First see if we've already got it */
                   1245: 
                   1246:   for (i = 0; i < pool_size; i++)
                   1247:     {
                   1248:       if (x->code == pool_vector[i].value->code
                   1249:          && mode == pool_vector[i].mode)
                   1250:        {
                   1251:          if (x->code == CODE_LABEL)
                   1252:            {
                   1253:              if (XINT (x, 3) != XINT (pool_vector[i].value, 3))
                   1254:                continue;
                   1255:            }
1.1.1.3 ! root     1256:          if (rtx_equal_p (x, pool_vector[i].value))
        !          1257:            return pool_vector[i].label;
1.1       root     1258:        }
                   1259:     }
1.1.1.2   root     1260: 
1.1.1.3 ! root     1261:   /* Need a new one */
1.1       root     1262: 
                   1263:   pool_vector[pool_size].value = x;
1.1.1.3 ! root     1264:   lab = gen_label_rtx ();
1.1       root     1265:   pool_vector[pool_size].mode = mode;
1.1.1.3 ! root     1266:   pool_vector[pool_size].label = lab;
1.1       root     1267:   pool_size++;
1.1.1.3 ! root     1268:   return lab;
1.1       root     1269: }
                   1270: 
1.1.1.3 ! root     1271: /* Dump out interesting debug info */
1.1       root     1272: 
1.1.1.3 ! root     1273: void
        !          1274: final_prescan_insn (insn, opvec, noperands)
1.1       root     1275:      rtx insn;
1.1.1.3 ! root     1276:      rtx *opvec;
        !          1277:      int noperands;
1.1       root     1278: {
1.1.1.3 ! root     1279:   if (target_flags & ISIZE_BIT)
1.1       root     1280:     {
1.1.1.3 ! root     1281:       extern int *insn_addresses;
        !          1282:       fprintf (asm_out_file, "\n! at %04x\n",
        !          1283:               insn_addresses[INSN_UID (insn)]);
1.1       root     1284:     }
                   1285: }
1.1.1.3 ! root     1286: 
1.1       root     1287: 
                   1288: 
                   1289: 
1.1.1.3 ! root     1290: /* Stuff taken from m88k.c */
1.1.1.2   root     1291: 
1.1.1.3 ! root     1292: /* Output to FILE the start of the assembler file.  */
1.1       root     1293: 
1.1.1.3 ! root     1294: struct option
1.1       root     1295: {
1.1.1.3 ! root     1296:   char *string;
        !          1297:   int *variable;
        !          1298:   int on_value;
        !          1299: };
1.1.1.2   root     1300: 
1.1.1.3 ! root     1301: static int
        !          1302: output_option (file, sep, type, name, indent, pos, max)
        !          1303:      FILE *file;
        !          1304:      char *sep;
        !          1305:      char *type;
        !          1306:      char *name;
        !          1307:      char *indent;
        !          1308:      int pos;
        !          1309:      int max;
        !          1310: {
        !          1311:   if (strlen (sep) + strlen (type) + strlen (name) + pos > max)
1.1       root     1312:     {
1.1.1.3 ! root     1313:       fprintf (file, indent);
        !          1314:       return fprintf (file, "%s%s", type, name);
1.1.1.2   root     1315:     }
1.1.1.3 ! root     1316:   return pos + fprintf (file, "%s%s%s", sep, type, name);
        !          1317: }
1.1       root     1318: 
1.1.1.3 ! root     1319: static struct
        !          1320: {
        !          1321:   char *name;
        !          1322:   int value;
        !          1323: }
1.1       root     1324: 
1.1.1.3 ! root     1325: m_options[] = TARGET_SWITCHES;
1.1       root     1326: 
1.1.1.3 ! root     1327: static void
        !          1328: output_options (file, f_options, f_len, W_options, W_len,
        !          1329:                pos, max, sep, indent, term)
        !          1330:      FILE *file;
        !          1331:      struct option *f_options;
        !          1332:      struct option *W_options;
        !          1333:      int f_len, W_len;
        !          1334:      int pos;
        !          1335:      int max;
        !          1336:      char *sep;
        !          1337:      char *indent;
        !          1338:      char *term;
        !          1339: {
        !          1340:   register int j;
1.1       root     1341: 
                   1342: 
1.1.1.3 ! root     1343:   if (optimize)
        !          1344:     pos = output_option (file, sep, "-O", "", indent, pos, max);
        !          1345:   if (write_symbols != NO_DEBUG)
        !          1346:     pos = output_option (file, sep, "-g", "", indent, pos, max);
        !          1347:   if (flag_traditional)
        !          1348:     pos = output_option (file, sep, "-traditional", "", indent, pos, max);
        !          1349:   if (profile_flag)
        !          1350:     pos = output_option (file, sep, "-p", "", indent, pos, max);
        !          1351:   if (profile_block_flag)
        !          1352:     pos = output_option (file, sep, "-a", "", indent, pos, max);
1.1       root     1353: 
1.1.1.3 ! root     1354:   for (j = 0; j < f_len; j++)
        !          1355:     if (*f_options[j].variable == f_options[j].on_value)
        !          1356:       pos = output_option (file, sep, "-f", f_options[j].string,
        !          1357:                           indent, pos, max);
1.1       root     1358: 
1.1.1.3 ! root     1359:   for (j = 0; j < W_len; j++)
        !          1360:     if (*W_options[j].variable == W_options[j].on_value)
        !          1361:       pos = output_option (file, sep, "-W", W_options[j].string,
        !          1362:                           indent, pos, max);
1.1       root     1363: 
1.1.1.3 ! root     1364:   for (j = 0; j < sizeof m_options / sizeof m_options[0]; j++)
        !          1365:     if (m_options[j].name[0] != '\0'
        !          1366:        && m_options[j].value > 0
        !          1367:        && ((m_options[j].value & target_flags)
        !          1368:            == m_options[j].value))
        !          1369:       pos = output_option (file, sep, "-m", m_options[j].name,
        !          1370:                           indent, pos, max);
1.1       root     1371: 
                   1372: 
1.1.1.3 ! root     1373:   fprintf (file, term);
        !          1374:   fprintf (file, "! %d %d\n", max_count_si, max_count_hi);
        !          1375: }
        !          1376: 
        !          1377: void
        !          1378: output_file_start (file, f_options, f_len, W_options, W_len)
        !          1379:      FILE *file;
        !          1380:      struct option *f_options;
        !          1381:      struct option *W_options;
        !          1382:      int f_len, W_len;
        !          1383: {
        !          1384:   register int pos;
        !          1385: 
        !          1386:   output_file_directive (file, main_input_filename);
        !          1387: 
        !          1388:   /* Switch to the data section so that the coffsem symbol and the
        !          1389:      gcc2_compiled. symbol aren't in the text section.  */
        !          1390:   data_section ();
        !          1391: 
        !          1392: 
        !          1393:   pos = fprintf (file, "\n! Hitachi SH cc1 (%s) (release I-1) arguments:", version_string);
        !          1394:   output_options (file, f_options, f_len, W_options, W_len,
        !          1395:                  pos, 75, " ", "\n! ", "\n\n");
        !          1396: }
        !          1397: 
        !          1398: 
        !          1399: 
        !          1400: /* Return the cost of a shift */
        !          1401: 
        !          1402: int
        !          1403: shiftcosts (RTX)
        !          1404:      rtx RTX;
        !          1405: {
        !          1406:   /* If shift by a non constant, then this will be expensive. */
        !          1407:   if (GET_CODE (XEXP (RTX, 1)) != CONST_INT)
        !          1408:     return 20;
        !          1409: 
        !          1410:   /* otherwise, it will be very cheap if by one of the constants
        !          1411:      we can cope with. */
        !          1412:   if (CONST_OK_FOR_K (INTVAL (XEXP (RTX, 1))))
        !          1413:     return 1;
        !          1414: 
        !          1415:   /* otherwise it will be several insns, but we pretend that it will be more than
        !          1416:      just the components, so that combine doesn't glue together a load of shifts into
        !          1417:      one shift which has to be emitted as a bunch anyway - breaking scheduling */
        !          1418:   return 1;
        !          1419: }
1.1.1.2   root     1420: 
                   1421: int
1.1.1.3 ! root     1422: andcosts (RTX)
        !          1423:      rtx RTX;
1.1       root     1424: {
                   1425:   int i;
1.1.1.3 ! root     1426:   if (GET_CODE (XEXP (RTX, 1)) != CONST_INT)
        !          1427:     return 2;
        !          1428:   i = INTVAL (XEXP (RTX, 1));
        !          1429:   /* And can use the extend insns cheaply */
        !          1430:   if (i == 0xff || i == 0xffff)
        !          1431:     return 2;
        !          1432:   /* Any small constant is reasonably cheap - but requires r0 */
        !          1433:   if (CONST_OK_FOR_I (i))
        !          1434:     return 3;
        !          1435:   return 5;
        !          1436: }
1.1.1.2   root     1437: 
1.1.1.3 ! root     1438: int 
        !          1439: howshift (i)
        !          1440:      int i;
        !          1441: {
        !          1442:   int total = 0;
        !          1443:   while (i > 0)
1.1       root     1444:     {
1.1.1.3 ! root     1445:       if (i >= 16)
        !          1446:        {
        !          1447:          total++;
        !          1448:          i -= 16;
        !          1449:        }
        !          1450:       else if (i >= 8)
        !          1451:        {
        !          1452:          total++;
        !          1453:          i -= 8;
        !          1454:        }
        !          1455:       else if (i >= 2)
        !          1456:        {
        !          1457:          total++;
        !          1458:          i -= 2;
        !          1459:        }
        !          1460:       else if (i >= 1)
        !          1461:        {
        !          1462:          total++;
        !          1463:          i--;
        !          1464:        }
        !          1465:     }
        !          1466:   return total;
        !          1467: }
1.1.1.2   root     1468: 
1.1.1.3 ! root     1469: /* Return the cost of a multiply */
        !          1470: int
        !          1471: multcosts (RTX)
        !          1472:      rtx RTX;
        !          1473: {
        !          1474:   /* If mult by a power of 2 then work out how we'd shift to make it */
        !          1475:   int insn_cost = 0;
        !          1476: 
        !          1477:   if (GET_CODE (XEXP (RTX, 1)) == CONST_INT)
        !          1478:     {
        !          1479:       int i = exact_log2 (INTVAL (XEXP (RTX, 1)));
        !          1480:       if (i >= 0)
        !          1481:        insn_cost = howshift (i);
        !          1482:       else
        !          1483:        insn_cost = 100000;
        !          1484:     }
        !          1485:   if (TARGET_SH2)
        !          1486:     {
        !          1487:       /* We have a mul insn, so we can never take more than the mul and the
        !          1488:         read of the mac reg, but count more because of the latency and extra reg
        !          1489:         usage */
        !          1490:       if (TARGET_SMALLCODE)
        !          1491:        return 2;
        !          1492:       if (insn_cost > 5)
        !          1493:        return 5;
        !          1494:       return insn_cost;
        !          1495:     }
        !          1496: 
        !          1497:   /* If we we're aiming at small code, then just count the number of
        !          1498:      insns in a multiply call sequence */
        !          1499: 
        !          1500:   if (TARGET_SMALLCODE)
        !          1501:     {
        !          1502:       if (insn_cost > 6)
        !          1503:        return 6;
        !          1504:       return insn_cost;
        !          1505:     }
        !          1506: 
        !          1507:   /* Otherwise count all the insns in the routine we'd be calling too */
        !          1508:   return 20;
        !          1509: }
        !          1510: 
        !          1511: /* Code to expand a shift */
        !          1512: 
        !          1513: void
        !          1514: gen_ashift (type, n, reg)
        !          1515:      int type;
        !          1516:      int n;
        !          1517:      rtx reg;
        !          1518: {
        !          1519:   switch (type)
        !          1520:     {
        !          1521:     case ASHIFTRT:
        !          1522:       emit_insn (gen_ashrsi3_k (reg, reg, GEN_INT (n)));
        !          1523:       break;
        !          1524:     case LSHIFTRT:
        !          1525:       emit_insn (gen_lshrsi3_k (reg, reg, GEN_INT (n)));
        !          1526:       break;
        !          1527:     case ASHIFT:
        !          1528:       if (n == 1)
        !          1529:        emit_insn (gen_addsi3 (reg, reg, reg));
        !          1530:       else
        !          1531:        emit_insn (gen_ashlsi3_k (reg, reg, GEN_INT (n)));
        !          1532:       break;
        !          1533:     }
        !          1534: }
        !          1535: 
        !          1536: int
        !          1537: gen_shifty_op (code, operands)
        !          1538:      int code;
        !          1539:      rtx *operands;
        !          1540: {
        !          1541:   rtx wrk = gen_reg_rtx (SImode);
        !          1542:   rtx t;
        !          1543:   char *func;
        !          1544:   if (GET_CODE (operands[2]) == CONST_INT)
        !          1545:     {
        !          1546:       int value = INTVAL (operands[2]);
        !          1547:     top:
        !          1548:       switch (code)
1.1.1.2   root     1549:        {
1.1.1.3 ! root     1550:        case ASHIFTRT:
        !          1551:          if (value < 0)
        !          1552:            {
        !          1553:              code = ASHIFT;
        !          1554:              value = -value;
        !          1555:              goto top;
        !          1556:            }
        !          1557: 
        !          1558:          /* Expand a short sequence inline, longer call a magic routine */
        !          1559:          if (value <= 5)
        !          1560:            {
        !          1561:              emit_move_insn (wrk, operands[1]);
        !          1562:              while (value--)
        !          1563:                {
        !          1564:                  gen_ashift (ASHIFTRT, 1, wrk);
        !          1565:                }
        !          1566:              emit_move_insn (operands[0], wrk);
        !          1567:              return 1;
        !          1568:            }
        !          1569:          t = gen_reg_rtx (Pmode);
        !          1570:          /*  Load the value into an arg reg and call a helper */
        !          1571:          emit_move_insn (gen_rtx (REG, SImode, 4), operands[1]);
        !          1572:          if (!shiftsyms[value])
        !          1573:            {
        !          1574:              func = xmalloc (18);
        !          1575:              sprintf (func, "__ashiftrt_r4_%d", value);
        !          1576:              shiftsyms[value] = gen_rtx (SYMBOL_REF, Pmode, func);
        !          1577:            }
        !          1578:          emit_move_insn (t, shiftsyms[value]);
        !          1579:          emit_insn (gen_ashrsi3_n (GEN_INT (value), t));
        !          1580:          emit_move_insn (operands[0], gen_rtx (REG, SImode, 4));
        !          1581:          return 1;
1.1.1.2   root     1582: 
1.1.1.3 ! root     1583:        case ASHIFT:
        !          1584:          if (value < 0)
        !          1585:            {
        !          1586:              code = LSHIFTRT;
        !          1587:              value = -value;
        !          1588:              goto top;
        !          1589:            }
        !          1590:          /* Fall through */
        !          1591:        case LSHIFTRT:
1.1.1.2   root     1592: 
1.1.1.3 ! root     1593:          if (value < 0)
1.1.1.2   root     1594:            {
1.1.1.3 ! root     1595:              code = ASHIFT;
        !          1596:              value = -value;
        !          1597:              goto top;
1.1.1.2   root     1598:            }
                   1599: 
1.1.1.3 ! root     1600:          emit_move_insn (wrk, operands[1]);
        !          1601:          while (value)
1.1.1.2   root     1602:            {
1.1.1.3 ! root     1603:              if (value >= 16)
        !          1604:                {
        !          1605:                  gen_ashift (code, 16, wrk);
        !          1606:                  value -= 16;
        !          1607:                }
        !          1608:              else if (value >= 8)
        !          1609:                {
        !          1610:                  gen_ashift (code, 8, wrk);
        !          1611:                  value -= 8;
        !          1612:                }
        !          1613:              else if (value >= 2)
        !          1614:                {
        !          1615:                  gen_ashift (code, 2, wrk);
        !          1616:                  value -= 2;
        !          1617:                }
        !          1618:              else
        !          1619:                {
        !          1620:                  gen_ashift (code, 1, wrk);
        !          1621:                  value--;
        !          1622:                }
1.1.1.2   root     1623:            }
1.1.1.3 ! root     1624:          emit_move_insn (operands[0], wrk);
        !          1625:          return 1;
1.1.1.2   root     1626: 
1.1       root     1627:        }
                   1628:     }
1.1.1.3 ! root     1629:   return 0;
        !          1630: }
1.1.1.2   root     1631: 
1.1.1.3 ! root     1632: /* Dump out any constants accumulated in the final pass -
        !          1633:    which will only be labels */
        !          1634: char *
        !          1635: output_jump_label_table ()
        !          1636: {
        !          1637:   int i;
        !          1638:   if (pool_size)
        !          1639:     {
        !          1640:       fprintf (asm_out_file, "\t.align 2\n");
        !          1641:       for (i = 0; i < pool_size; i++)
        !          1642:        {
        !          1643:          pool_node *p = pool_vector + i;
1.1.1.2   root     1644: 
1.1.1.3 ! root     1645:          ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (p->label));
        !          1646:          output_asm_insn (".long       %O0", &p->value);
        !          1647:        }
        !          1648:       pool_size = 0;
        !          1649:     }
1.1.1.2   root     1650: 
1.1.1.3 ! root     1651:   return "";
1.1       root     1652: }
1.1.1.3 ! root     1653: /* Output the literal table */
1.1       root     1654: 
1.1.1.3 ! root     1655: static void
        !          1656: dump_table (scan)
        !          1657:      rtx scan;
        !          1658: {
        !          1659:   int i;
        !          1660:   int need_align = 1;
1.1       root     1661: 
                   1662: 
1.1.1.3 ! root     1663:   /* Do two passes, first time dump out the HI sized constants */
1.1       root     1664: 
1.1.1.3 ! root     1665:   for (i = 0; i < pool_size; i++)
        !          1666:     {
        !          1667:       pool_node *p = pool_vector + i;
        !          1668:       if (p->mode == HImode)
        !          1669:        {
        !          1670:          if (need_align)
        !          1671:            {
        !          1672:              scan = emit_insn_after (gen_align_2 (), scan);
        !          1673:              need_align = 0;
        !          1674:            }
        !          1675:          scan = emit_label_after (p->label, scan);
        !          1676:          scan = emit_insn_after (gen_consttable_2 (p->value), scan);
        !          1677:        }
        !          1678:     }
        !          1679:   need_align = 1;
1.1       root     1680: 
1.1.1.3 ! root     1681:   for (i = 0; i < pool_size; i++)
1.1       root     1682:     {
1.1.1.3 ! root     1683:       pool_node *p = pool_vector + i;
1.1       root     1684: 
1.1.1.3 ! root     1685:       switch (p->mode)
        !          1686:        {
        !          1687:        case HImode:
        !          1688:          break;
        !          1689:        case SImode:
        !          1690:          if (need_align)
        !          1691:            {
        !          1692:              need_align = 0;
        !          1693:              scan = emit_label_after (gen_label_rtx (), scan);
        !          1694:              scan = emit_insn_after (gen_align_4 (), scan);
        !          1695:            }
        !          1696:          scan = emit_label_after (p->label, scan);
        !          1697:          scan = emit_insn_after (gen_consttable_4 (p->value), scan);
        !          1698:          break;
        !          1699:        case DImode:
        !          1700:          if (need_align)
        !          1701:            {
        !          1702:              need_align = 0;
        !          1703:              scan = emit_label_after (gen_label_rtx (), scan);
        !          1704:              scan = emit_insn_after (gen_align_4 (), scan);
        !          1705:            }
        !          1706:          scan = emit_label_after (p->label, scan);
        !          1707:          scan = emit_insn_after (gen_consttable_8 (p->value), scan);
        !          1708:          break;
        !          1709:        default:
        !          1710:          abort ();
        !          1711:          break;
        !          1712:        }
1.1.1.2   root     1713:     }
                   1714: 
1.1.1.3 ! root     1715:   scan = emit_insn_after (gen_consttable_end (), scan);
        !          1716:   scan = emit_barrier_after (scan);
        !          1717:   pool_size = 0;
        !          1718: }
        !          1719: 
1.1.1.2   root     1720: 
                   1721: 
1.1.1.3 ! root     1722: /* Non zero if the src operand needs to be fixed up */
        !          1723: static
        !          1724: int
        !          1725: fixit (src, mode)
        !          1726:      rtx src;
        !          1727:      enum machine_mode mode;
        !          1728: {
        !          1729:   if (mode == QImode)
        !          1730:     return 0;                  /* QIs never need to be fixed */
        !          1731:   if (GET_CODE (src) == CONST)
        !          1732:     return 1;
1.1.1.2   root     1733: 
1.1.1.3 ! root     1734:   if (GET_CODE (src) == SYMBOL_REF)
1.1       root     1735:     {
1.1.1.3 ! root     1736:       return 1;
1.1       root     1737:     }
1.1.1.3 ! root     1738:   if (GET_CODE (src) == LABEL_REF)
        !          1739:     {
        !          1740:       return 1;
        !          1741:     }
        !          1742:   if (GET_CODE (src) == CONST_INT)
        !          1743:     {
        !          1744:       /* All QI insns are ok */
        !          1745:       if (mode == QImode)
        !          1746:        return 1;
        !          1747:       /* The rest may need to be fixed */
        !          1748:       return !CONST_OK_FOR_I (INTVAL (src));
        !          1749:     }
        !          1750:   return 0;
1.1       root     1751: }
                   1752: 
1.1.1.3 ! root     1753: /* Return Non-zero if constant would be an ok source for a
        !          1754:    mov.w instead of a mov.l */
        !          1755: int
        !          1756: hi_const (src)
        !          1757:      rtx src;
1.1       root     1758: {
1.1.1.3 ! root     1759:   if (GET_CODE (src) == CONST
        !          1760:       && GET_CODE (XEXP (src, 0)) == SIGN_EXTEND
        !          1761:       && GET_CODE (XEXP (XEXP (src, 0), 0)) == SYMBOL_REF)
        !          1762:     return 1;
1.1       root     1763: 
1.1.1.3 ! root     1764:   if (TARGET_SHORTADDR
        !          1765:       && GET_CODE (src) == SYMBOL_REF)
        !          1766:     return 1;
1.1       root     1767: 
1.1.1.3 ! root     1768:   return (GET_CODE (src) == CONST_INT
        !          1769:          && INTVAL (src) >= -32768
        !          1770:          && INTVAL (src) <= 32767);
        !          1771: }
1.1       root     1772: 
1.1.1.3 ! root     1773: /* Find the last barrier less than MAX_COUNT bytes from FROM, or create one.
        !          1774:    If an HI move is found, then make sure that MAX_COUNT_HI isn't broken from that one. */
1.1       root     1775: 
1.1.1.3 ! root     1776: static
        !          1777: rtx
        !          1778: find_barrier (from)
        !          1779:      rtx from;
        !          1780: {
        !          1781:   int count_si = 0;
        !          1782:   int count_hi = 0;
        !          1783:   int found_hi = 0;
        !          1784:   int found_si = 0;
        !          1785:   rtx found_barrier = 0;
        !          1786:   while (from
        !          1787:         && count_si < max_count_si
        !          1788:         && count_hi < max_count_hi)
        !          1789:     {
        !          1790:       int inc;
        !          1791:       if (GET_CODE (from) == BARRIER)
        !          1792:        {
        !          1793:          found_barrier = from;
        !          1794:        }
        !          1795:       /* Count the length of this insn - we assume that all moves will
        !          1796:         be 2 bytes long, except the DIs */
        !          1797: 
        !          1798:       if (GET_CODE (from) == INSN &&
        !          1799:          GET_CODE (PATTERN (from)) == SET)
        !          1800:        {
        !          1801:          rtx src = SET_SRC (PATTERN (from));
        !          1802:          if (hi_const (src))
        !          1803:            found_hi = 1;
        !          1804:          else
        !          1805:            found_si = 1;
        !          1806:          inc = (GET_MODE_SIZE (GET_MODE (src)) > 4) ? 4 : 2;
        !          1807:        }
        !          1808:       else
        !          1809:        {
        !          1810:          inc = get_attr_length (from);
        !          1811:        }
        !          1812:       if (found_si)
        !          1813:        count_si += inc;
        !          1814:       if (found_hi)
        !          1815:        count_hi += inc;
        !          1816:       from = NEXT_INSN (from);
1.1       root     1817:     }
                   1818: 
1.1.1.3 ! root     1819:   if (!found_barrier)
1.1       root     1820:     {
1.1.1.3 ! root     1821:       /* We didn't find a barrier in time to 
        !          1822:         dump our stuff, so we'll make one */
        !          1823:       rtx label = gen_label_rtx ();
        !          1824:       /* Walk back to be just before any jump */
        !          1825:       from = PREV_INSN (from);
        !          1826:       while (GET_CODE (from) == JUMP_INSN
        !          1827:             || GET_CODE (from) == NOTE
        !          1828:             || GET_CODE (from) == CODE_LABEL)
        !          1829:        {
        !          1830:          from = PREV_INSN (from);
        !          1831:        }
        !          1832:       from = emit_jump_insn_after (gen_jump (label), from);
        !          1833:       JUMP_LABEL (from) = label;
        !          1834:       found_barrier = emit_barrier_after (from);
        !          1835:       emit_label_after (label, found_barrier);
        !          1836:       return found_barrier;
1.1       root     1837:     }
1.1.1.3 ! root     1838:   return found_barrier;
1.1       root     1839: }
                   1840: 
1.1.1.3 ! root     1841: /* Non zero if the insn is a move instruction which needs to be fixed. */
1.1       root     1842: 
1.1.1.3 ! root     1843: static
        !          1844: int
        !          1845: broken_move (insn)
        !          1846:      rtx insn;
1.1.1.2   root     1847: {
1.1.1.3 ! root     1848:   if (!INSN_DELETED_P (insn)
        !          1849:       && GET_CODE (insn) == INSN
        !          1850:       && GET_CODE (PATTERN (insn)) == SET)
        !          1851:     {
        !          1852:       rtx pat = PATTERN (insn);
        !          1853:       rtx src = SET_SRC (pat);
        !          1854:       rtx dst = SET_DEST (pat);
        !          1855:       enum machine_mode mode = GET_MODE (dst);
        !          1856:       if (dst == pc_rtx)
        !          1857:        return 0;
        !          1858:       return fixit (src, mode);
        !          1859:     }
        !          1860:   return 0;
        !          1861: }
1.1.1.2   root     1862: 
                   1863: 
1.1.1.3 ! root     1864: /* Exported to toplev.c
1.1.1.2   root     1865: 
1.1.1.3 ! root     1866:    Scan the function looking for move instructions which have to be changed to
        !          1867:    pcrel loads and insert the literal tables. */
1.1.1.2   root     1868: 
1.1.1.3 ! root     1869: void
        !          1870: machine_dependent_reorg (first)
        !          1871:      rtx first;
        !          1872: {
        !          1873:   rtx insn;
        !          1874:   for (insn = first; insn; insn = NEXT_INSN (insn))
1.1.1.2   root     1875:     {
1.1.1.3 ! root     1876:       if (broken_move (insn))
1.1.1.2   root     1877:        {
1.1.1.3 ! root     1878:          /* This is a broken move instruction, scan ahead looking for
        !          1879:             a barrier to stick the constant table behind */
        !          1880:          rtx scan;
        !          1881:          rtx barrier = find_barrier (insn);
        !          1882: 
        !          1883:          /* Now find all the moves between the points and modify them */
        !          1884:          for (scan = insn; scan != barrier; scan = NEXT_INSN (scan))
1.1.1.2   root     1885:            {
1.1.1.3 ! root     1886:              if (broken_move (scan))
        !          1887:                {
        !          1888:                  rtx pat = PATTERN (scan);
        !          1889:                  rtx src = SET_SRC (pat);
        !          1890:                  rtx dst = SET_DEST (pat);
        !          1891:                  enum machine_mode mode = GET_MODE (dst);
        !          1892:                  rtx lab;
        !          1893:                  rtx newinsn;
        !          1894:                  rtx newsrc;
        !          1895:                  /* This is a broken move instruction, add it to the pool */
        !          1896: 
        !          1897:                  if (mode == SImode && hi_const (src))
        !          1898:                    {
        !          1899:                      /* This is an HI source, clobber the dest to get the mode right too */
        !          1900:                      mode = HImode;
        !          1901:                      while (GET_CODE (dst) == SUBREG)
        !          1902:                        dst = SUBREG_REG (dst);
        !          1903:                      dst = gen_rtx (REG, HImode, REGNO (dst));
        !          1904:                    }
        !          1905:                  lab = add_constant (src, mode);
        !          1906:                  newsrc = gen_rtx (MEM, mode,
        !          1907:                                    gen_rtx (LABEL_REF, VOIDmode, lab));
        !          1908: 
        !          1909:                  /* Build a jump insn wrapper around the move instead
        !          1910:                     of an ordinary insn, because we want to have room for
        !          1911:                     the target label rtx in fld[7], which an ordinary
        !          1912:                     insn doesn't have. */
        !          1913:                  newinsn = emit_jump_insn_after (gen_rtx (SET, VOIDmode,
        !          1914:                                                        dst, newsrc), scan);
        !          1915:                  JUMP_LABEL (newinsn) = lab;
        !          1916: 
        !          1917:                  /* But it's still an ordinary insn */
        !          1918:                  PUT_CODE (newinsn, INSN);
        !          1919: 
        !          1920:                  /* Kill old insn */
        !          1921:                  delete_insn (scan);
        !          1922:                  scan = newinsn;
        !          1923:                }
1.1.1.2   root     1924:            }
1.1.1.3 ! root     1925:          dump_table (barrier);
1.1.1.2   root     1926:        }
                   1927:     }
                   1928: }
                   1929: 
1.1.1.3 ! root     1930: /* Called from the md file, set up the operands of a compare instruction */
        !          1931: 
1.1.1.2   root     1932: void
1.1.1.3 ! root     1933: from_compare (operands, code)
1.1.1.2   root     1934:      rtx *operands;
1.1.1.3 ! root     1935:      int code;
1.1.1.2   root     1936: {
1.1.1.3 ! root     1937:   if (code != EQ && code != NE)
1.1.1.2   root     1938:     {
1.1.1.3 ! root     1939:       /* Force args into regs, since we can't use constants here */
        !          1940:       sh_compare_op0 = force_reg (SImode, sh_compare_op0);
        !          1941:       if (sh_compare_op1 != const0_rtx)
        !          1942:        sh_compare_op1 = force_reg (SImode, sh_compare_op1);
1.1.1.2   root     1943:     }
1.1.1.3 ! root     1944:   operands[1] = sh_compare_op0;
        !          1945:   operands[2] = sh_compare_op1;
1.1.1.2   root     1946: }
                   1947: 
1.1.1.3 ! root     1948: /* Non-zero if x is EQ or NE */
1.1.1.2   root     1949: 
1.1.1.3 ! root     1950: int
        !          1951: equality_operator (x, mode)
        !          1952:      rtx x;
        !          1953:      enum machine_mode mode;
1.1.1.2   root     1954: {
1.1.1.3 ! root     1955:   enum rtx_code code = GET_CODE (x);
        !          1956:   return (code == EQ || code == NE);
1.1.1.2   root     1957: }
                   1958: 
                   1959: 
1.1.1.3 ! root     1960: /* Add this function to the list of ones seen - temporary
        !          1961:    gross hack to try out bsrs. */
        !          1962: struct flist
1.1.1.2   root     1963: {
1.1.1.3 ! root     1964:   char *name;
        !          1965:   struct flist *next;
1.1.1.2   root     1966: };
1.1.1.3 ! root     1967: struct flist *head;
1.1.1.2   root     1968: 
1.1.1.3 ! root     1969: static void
        !          1970: add_function (name)
1.1.1.2   root     1971:      char *name;
                   1972: {
1.1.1.3 ! root     1973:   struct flist *n = (struct flist *) xmalloc (sizeof (struct flist));
        !          1974:   int l = strlen (name) + 1;
        !          1975:   n->name = xmalloc (l);
        !          1976:   memcpy (n->name, name, l);
        !          1977:   n->next = head;
        !          1978:   head = n;
1.1.1.2   root     1979: }
                   1980: 
1.1.1.3 ! root     1981: static int
        !          1982: seen_function (name)
        !          1983:      char *name;
1.1.1.2   root     1984: {
1.1.1.3 ! root     1985:   struct flist *p = head;
        !          1986:   for (p = head; p; p = p->next)
        !          1987:     {
        !          1988:       if (strcmp (p->name, name) == 0)
        !          1989:        return 1;
        !          1990:     }
        !          1991:   return 0;
1.1.1.2   root     1992: }
                   1993: 
1.1.1.3 ! root     1994:  /* Framefull frame looks like:
1.1.1.2   root     1995: 
1.1.1.3 ! root     1996:     arg-5
        !          1997:     arg-4
        !          1998:     [ if current_function_anonymous_args
        !          1999:     arg-3
        !          2000:     arg-2
        !          2001:     arg-1
        !          2002:     arg-0 ]
        !          2003:     saved-fp
        !          2004:     saved-r10
        !          2005:     saved-r11
        !          2006:     saved-r12
        !          2007:     saved-pr
        !          2008:     local-n
        !          2009:     ..
        !          2010:     local-1
        !          2011:     local-0        <- fp points here
        !          2012: 
        !          2013: 
        !          2014:     If TARGET_SMALLCALL, then the preserved registers are pushed by a
        !          2015:     wrapper before the routine is entered, so the regs are always pushed
        !          2016:     and there are two pr's on the stack - the caller and the wrapper.
        !          2017:   */
1.1.1.2   root     2018: 
                   2019: 
1.1.1.3 ! root     2020:  /* Code to generate prologue and epilogue sequences */
1.1.1.2   root     2021: 
                   2022: 
                   2023: void
                   2024: sh_expand_prologue ()
                   2025: {
                   2026:   int live_regs_mask;
                   2027:   int d;
1.1.1.3 ! root     2028:   extern tree current_function_decl;
1.1.1.2   root     2029:   live_regs_mask = calc_live_regs (&d);
                   2030: 
1.1.1.3 ! root     2031:   /* We have pretend args if we had an object sent partially in registers
        !          2032:      and partially on the stack - eg a large structure */
        !          2033:   output_stack_adjust (-current_function_pretend_args_size);
1.1.1.2   root     2034: 
                   2035:   if (current_function_anonymous_args)
                   2036:     {
                   2037:       /* Push arg regs as if they'd been provided by caller in stack */
                   2038:       int i;
                   2039:       for (i = 0; i < NPARM_REGS; i++)
                   2040:        {
                   2041:          int rn = NPARM_REGS + FIRST_PARM_REG - i - 1;
                   2042:          if (i > NPARM_REGS - current_function_args_info)
                   2043:            break;
                   2044:          push (rn);
                   2045:          extra_push += 4;
                   2046:        }
                   2047:     }
1.1.1.3 ! root     2048:   push_regs (live_regs_mask);
        !          2049:   output_stack_adjust (-get_frame_size ());
1.1.1.2   root     2050: 
                   2051:   if (frame_pointer_needed)
                   2052:     {
                   2053:       emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
                   2054:     }
1.1.1.3 ! root     2055:   if (TARGET_BSR)
1.1.1.2   root     2056:     {
1.1.1.3 ! root     2057:       add_function (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)));
1.1.1.2   root     2058:     }
                   2059: 
1.1.1.3 ! root     2060: 
1.1.1.2   root     2061: }
                   2062: 
                   2063: void
                   2064: sh_expand_epilogue ()
                   2065: {
                   2066:   int live_regs_mask;
                   2067:   int d;
                   2068:   int i;
                   2069: 
                   2070:   live_regs_mask = calc_live_regs (&d);
                   2071: 
1.1.1.3 ! root     2072:   
1.1.1.2   root     2073:   if (frame_pointer_needed)
                   2074:     {
                   2075:       emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx));
                   2076:     }
1.1.1.3 ! root     2077:   output_stack_adjust (get_frame_size ());
1.1.1.2   root     2078: 
                   2079:   /* Pop all the registers */
1.1.1.3 ! root     2080: 
1.1.1.2   root     2081:   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
                   2082:     {
                   2083:       int j = (FIRST_PSEUDO_REGISTER - 1) - i;
                   2084:       if (live_regs_mask & (1 << j))
                   2085:        {
                   2086:          pop (j);
                   2087:        }
                   2088:     }
                   2089: 
1.1.1.3 ! root     2090:   output_stack_adjust (extra_push + current_function_pretend_args_size);
1.1.1.2   root     2091: 
1.1.1.3 ! root     2092:   extra_push = 0;
        !          2093:   current_function_pretend_args_size = 0;
1.1.1.2   root     2094:   current_function_anonymous_args = 0;
1.1.1.3 ! root     2095:   for (i = 0; i < 32; i++)
        !          2096:     shiftsyms[i] = 0;
        !          2097: 
1.1.1.2   root     2098: }
                   2099: 
1.1.1.3 ! root     2100: /* Define the offset between two registers, one to be eliminated, and
        !          2101:    the other its replacement, at the start of a routine.  */
1.1.1.2   root     2102: 
1.1.1.3 ! root     2103: int
        !          2104: initial_elimination_offset (from, to)
        !          2105:      int from;
        !          2106:      int to;
        !          2107: {
        !          2108:   int regs_saved;
        !          2109:   int total_saved_regs_space;
        !          2110:   int total_auto_space = get_frame_size ();
        !          2111: 
        !          2112:   calc_live_regs (&regs_saved);
        !          2113:   total_saved_regs_space = (regs_saved) * 4;
        !          2114: 
        !          2115:   if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
        !          2116:     {
        !          2117:       return total_saved_regs_space + total_auto_space;
        !          2118:     }
        !          2119:   if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
        !          2120:     {
        !          2121:       return total_saved_regs_space + total_auto_space;
        !          2122:     }
        !          2123:   if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
        !          2124:     {
        !          2125:       /* Initial gap between fp and sp is 0 */
        !          2126:       return 0;
        !          2127:     }
        !          2128:   abort ();
        !          2129: }
        !          2130: 
        !          2131: /* Handle machine specific pragmas to be semi-compatible with Hitachi
        !          2132:    compiler  */
1.1.1.2   root     2133: 
                   2134: int
1.1.1.3 ! root     2135: handle_pragma (file)
        !          2136:      FILE *file;
1.1.1.2   root     2137: {
1.1.1.3 ! root     2138:   int c;
        !          2139:   char pbuf[200];
        !          2140:   int psize = 0;
1.1.1.2   root     2141: 
1.1.1.3 ! root     2142:   c = getc (file);
        !          2143:   while (c == ' ' || c == '\t')
        !          2144:     c = getc (file);
        !          2145: 
        !          2146:   if (c == '\n' || c == EOF)
        !          2147:     return c;
        !          2148: 
        !          2149:   while (psize < sizeof (pbuf) - 1 && c != '\n')
        !          2150:     {
        !          2151:       pbuf[psize++] = c;
        !          2152:       if (psize == 9 && strncmp (pbuf, "interrupt", 9) == 0)
        !          2153:        {
        !          2154:          pragma_interrupt = 1;
        !          2155:          return ' ';
        !          2156:        }
        !          2157:       if (psize == 5 && strncmp (pbuf, "trapa", 5) == 0)
        !          2158:        {
        !          2159:          pragma_interrupt = pragma_trapa = 1;
        !          2160:          return ' ';
        !          2161:        }
        !          2162:       c = getc (file);
        !          2163:     }
        !          2164:   return c;
        !          2165: }
        !          2166: 
        !          2167: /* insn expand helpers */
        !          2168: 
        !          2169: /* Emit insns to perform a call.
        !          2170:    If TARGET_SHORTADDR then use a bsr. If TARGET_SMALLCALL, then load the
        !          2171:    target address into r1 and call __saveargs, otherwise
        !          2172:    perform the standard call sequence */
        !          2173: 
        !          2174: void
        !          2175: expand_acall (isa_retval, operands)
        !          2176:      int isa_retval;
        !          2177:      rtx *operands;
        !          2178: {
        !          2179:   rtx call;
        !          2180:   rtx ret = operands[0];
        !          2181:   rtx call_target = operands[isa_retval + 0];
        !          2182:   rtx numargs = operands[isa_retval + 1];
        !          2183: 
        !          2184:   if (TARGET_BSR && bsr_operand (call_target, VOIDmode))
        !          2185:     {
        !          2186:       call = gen_rtx (CALL, VOIDmode, call_target, numargs);
        !          2187:     }
        !          2188:   else
        !          2189:     {
        !          2190:       if (GET_CODE (call_target) == MEM)
        !          2191:        {
        !          2192:          call_target = force_reg (Pmode,
        !          2193:                                   XEXP (call_target, 0));
        !          2194:        }
        !          2195:       if (TARGET_SMALLCALL)
        !          2196:        {
        !          2197:          rtx tmp = gen_reg_rtx (SImode);
        !          2198:          rtx r1 = gen_rtx (REG, SImode, 1);
        !          2199:          emit_move_insn (tmp, gen_rtx (SYMBOL_REF, SImode, "__saveargs"));
        !          2200:          emit_move_insn (r1, call_target);
        !          2201:          emit_insn (gen_rtx (USE, VOIDmode, r1));
        !          2202:          call_target = tmp;
        !          2203:        }
        !          2204: 
        !          2205:       call = gen_rtx (CALL, VOIDmode, gen_rtx (MEM, SImode, call_target), numargs);
        !          2206:     }
        !          2207:   if (isa_retval)
        !          2208:     {
        !          2209:       call = gen_rtx (SET, VOIDmode, ret, call);
        !          2210:     }
        !          2211: 
        !          2212:   emit_call_insn (gen_rtx (PARALLEL, VOIDmode,
        !          2213:                           gen_rtvec (2,
        !          2214:                                      call,
        !          2215:                  gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 17)))));
        !          2216: 
        !          2217: }
        !          2218: 
        !          2219: 
        !          2220: /* Predicates used by the templates */
        !          2221: 
        !          2222: 
        !          2223: /* Returns 1 if OP can be source of a simple move operation.
        !          2224:    Same as general_operand, but a LABEL_REF is valid, PRE_DEC is
        !          2225:    invalid as are subregs of system registers. */
        !          2226: 
        !          2227: int
        !          2228: general_movsrc_operand (op, mode)
        !          2229:      rtx op;
        !          2230:      enum machine_mode mode;
        !          2231: {
        !          2232:   /* Any MEM(label_ref) is ok, that's a pcrel load */
        !          2233:   if (GET_CODE (op) == MEM
        !          2234:       && GET_CODE (XEXP (op, 0)) == LABEL_REF)
1.1.1.2   root     2235:     return 1;
                   2236: 
1.1.1.3 ! root     2237:   if (GET_CODE (op) == MEM)
        !          2238:     {
        !          2239:       rtx inside = XEXP (op, 0);
        !          2240:       if (GET_CODE (inside) == CONST)
        !          2241:        inside = XEXP (inside, 0);
        !          2242: 
        !          2243:       if (GET_CODE (inside) == LABEL_REF)
        !          2244:        return 1;
        !          2245: 
        !          2246:       if (GET_CODE (inside) == PLUS
        !          2247:          && GET_CODE (XEXP (inside,0)) == LABEL_REF
        !          2248:          && GET_CODE (XEXP (inside,1)) == CONST_INT)
        !          2249:        return 1;
        !          2250:       
        !          2251:       /* No post inc allowed */
        !          2252:       if (GET_CODE (inside) == POST_DEC
        !          2253:          || GET_CODE (inside) == PRE_INC
        !          2254:          || GET_CODE (inside) == PRE_DEC)
        !          2255:        return 0;
        !          2256: 
        !          2257:       /* Can't do that with large modes */
        !          2258:       if (GET_CODE (inside) == POST_INC
        !          2259:          && GET_MODE_SIZE (mode) > 4)
        !          2260:        return 0;
        !          2261:     }
        !          2262: 
        !          2263:   if ((mode == QImode || mode == HImode)
        !          2264:       && (GET_CODE (op) == SUBREG
        !          2265:          && GET_CODE (XEXP (op, 0)) == REG
        !          2266:          && system_reg_operand (XEXP (op, 0), mode)))
        !          2267:     return 0;
        !          2268: 
        !          2269:   if (GET_CODE (op) == CONST_INT)
        !          2270:     {
        !          2271:       int i = INTVAL (op);
        !          2272:       return CONST_OK_FOR_I (i);
        !          2273:     }
        !          2274:   return general_operand (op, mode);
1.1.1.2   root     2275: }
                   2276: 
1.1.1.3 ! root     2277: 
        !          2278: /* Returns 1 if OP can be a destination of a move.
        !          2279:    Same as general_operand, but no preinc allowed.  */
        !          2280: 
1.1.1.2   root     2281: int
1.1.1.3 ! root     2282: general_movdst_operand (op, mode)
        !          2283:      rtx op;
        !          2284:      enum machine_mode mode;
1.1.1.2   root     2285: {
1.1.1.3 ! root     2286:   /* No pre dec allowed */
        !          2287:   if (GET_CODE (op) == MEM
        !          2288:       && (GET_CODE (XEXP (op, 0)) == PRE_INC
        !          2289:          || GET_CODE (XEXP (op, 0)) == POST_INC
        !          2290:          || GET_CODE (XEXP (op, 0)) == POST_DEC))
        !          2291:     return 0;
        !          2292: 
        !          2293:   if (GET_CODE (op) == MEM
        !          2294:       && GET_CODE (XEXP (op, 0)) == PRE_DEC
        !          2295:       && GET_MODE_SIZE (mode) > 4)
        !          2296:     return 0;
        !          2297: 
        !          2298:   return general_operand (op, mode);
        !          2299: }
        !          2300: 
        !          2301: 
        !          2302: 
        !          2303: /* Returns 1 if OP is valid destination for a bsr.  */
        !          2304: 
        !          2305: int
        !          2306: bsr_operand (op, mode)
        !          2307:      rtx op;
        !          2308:      enum machine_mode mode;
        !          2309: {
        !          2310:   if (TARGET_BSR)
        !          2311:     {
        !          2312:       if (GET_CODE (op) == SYMBOL_REF)
        !          2313:        {
        !          2314:          if (!strcmp (XSTR (op, 0),
        !          2315:                      IDENTIFIER_POINTER (DECL_NAME (current_function_decl))))
        !          2316:            return 1;
        !          2317:          return (seen_function (XSTR (op, 0)));
        !          2318:        }
        !          2319:     }
        !          2320:   return 0;
        !          2321: }
        !          2322: 
        !          2323: /* Returns 1 if OP is an immediate ok for a byte index.  */
        !          2324: 
        !          2325: int
        !          2326: byte_index_operand (op, mode)
        !          2327:      rtx op;
        !          2328:      enum machine_mode mode;
        !          2329: {
        !          2330:   return (GET_CODE (op) == CONST_INT
        !          2331:          && INTVAL (op) >= 0
        !          2332:          && INTVAL (op) <= 15);
        !          2333: }
        !          2334: 
        !          2335: /* Returns 1 if OP is a pop operand.   */
        !          2336: 
        !          2337: int
        !          2338: pop_operand (op, mode)
        !          2339:      rtx op;
        !          2340:      enum machine_mode mode;
        !          2341: {
        !          2342:   if (GET_CODE (op) != MEM)
        !          2343:     return 0;
        !          2344: 
        !          2345:   if (GET_MODE (op) != mode)
        !          2346:     return 0;
        !          2347: 
        !          2348:   op = XEXP (op, 0);
        !          2349: 
        !          2350:   if (GET_CODE (op) != POST_INC)
        !          2351:     return 0;
        !          2352: 
        !          2353:   return XEXP (op, 0) == stack_pointer_rtx;
        !          2354: }
        !          2355: 
        !          2356: 
        !          2357: /* Returns 1 if OP is a normal arithmetic register.  */
        !          2358: 
        !          2359: int
        !          2360: arith_reg_operand (op, mode)
        !          2361:      rtx op;
        !          2362:      enum machine_mode mode;
        !          2363: {
        !          2364:   if (register_operand (op, mode))
        !          2365:     {
        !          2366:       if (GET_CODE (op) == REG)
        !          2367:        return (REGNO (op) != T_REG
        !          2368:                && REGNO (op) != PR_REG);
        !          2369:       return 1;
        !          2370:     }
        !          2371:   return 0;
        !          2372: }
        !          2373: 
        !          2374: /* Returns 1 if OP is MACL, MACH or PR.  */
        !          2375: 
        !          2376: int
        !          2377: system_reg_operand (op, mode)
        !          2378:      rtx op;
        !          2379:      enum machine_mode mode;
        !          2380: {
        !          2381:   if (GET_CODE (op) == REG)
        !          2382:     {
        !          2383:       switch (REGNO (op))
        !          2384:        {
        !          2385:        case PR_REG:
        !          2386:        case MACL_REG:
        !          2387:        case MACH_REG:
        !          2388:          return 1;
        !          2389:        }
        !          2390:     }
        !          2391:   return 0;
        !          2392: }
        !          2393: 
        !          2394: 
        !          2395: /* Returns 1 if OP is a valid source operand for an arithmetic insn.  */
        !          2396: 
        !          2397: int
        !          2398: arith_operand (op, mode)
        !          2399:      rtx op;
        !          2400:      enum machine_mode mode;
        !          2401: {
        !          2402:   if (arith_reg_operand (op, mode))
        !          2403:     return 1;
        !          2404: 
        !          2405:   if (GET_CODE (op) == CONST_INT)
        !          2406:     {
        !          2407:       if (CONST_OK_FOR_I (INTVAL (op)))
        !          2408:        return 1;
        !          2409:     }
        !          2410:   return 0;
        !          2411: }
        !          2412: 
        !          2413: 
        !          2414: /* Returns 1 if OP is a valid source operand for a logical operation. */
        !          2415: 
        !          2416: int
        !          2417: logical_operand (op, mode)
        !          2418:      rtx op;
        !          2419:      enum machine_mode mode;
        !          2420: {
        !          2421:   if (arith_reg_operand (op, mode))
        !          2422:     return 1;
        !          2423: 
        !          2424:   if (GET_CODE (op) == CONST_INT)
        !          2425:     {
        !          2426:       if (CONST_OK_FOR_L (INTVAL (op)))
        !          2427:        return 1;
        !          2428:     }
        !          2429:   return 0;
        !          2430: }
        !          2431: 
        !          2432: /* Returns 1 if OP is a valid operand for a MAC instruction,
        !          2433:    either a register or indirect memory.  For now we don't
        !          2434:    try and recognise a mac insn */
        !          2435: 
        !          2436: int
        !          2437: mac_operand (op, mode)
        !          2438:      rtx op;
        !          2439:      enum machine_mode mode;
        !          2440: {
        !          2441:   if (arith_reg_operand (op, mode))
        !          2442:     return 1;
        !          2443: #if 0
        !          2444:   Turned off till mac is understood
        !          2445:   if (GET_CODE (op) == MEM)
        !          2446:     return 1;
        !          2447: #endif
        !          2448:   return 0;
        !          2449: }
        !          2450: 
        !          2451: /* Determine where to put an argument to a function.
        !          2452:    Value is zero to push the argument on the stack,
        !          2453:    or a hard register in which to store the argument.
        !          2454: 
        !          2455:    MODE is the argument's machine mode.
        !          2456:    TYPE is the data type of the argument (as a tree).
        !          2457:     This is null for libcalls where that information may
        !          2458:     not be available.
        !          2459:    CUM is a variable of type CUMULATIVE_ARGS which gives info about
        !          2460:     the preceding args and about the function being called.
        !          2461:    NAMED is nonzero if this argument is a named parameter
        !          2462:     (otherwise it is an extra parameter matching an ellipsis).  */
        !          2463: 
        !          2464: rtx
        !          2465: sh_function_arg (cum, mode, type, named)
        !          2466:      CUMULATIVE_ARGS cum;
        !          2467:      enum machine_mode mode;
        !          2468:      tree type;
        !          2469:      int named;
        !          2470: {
        !          2471:   if (named)
        !          2472:     {
        !          2473:       int rr = (ROUND_REG ((cum), (mode)));
        !          2474: 
        !          2475:       if (rr < NPARM_REGS)
        !          2476:        {
        !          2477:          return (((type) == 0 || !TREE_ADDRESSABLE ((tree) (type)))
        !          2478:                  && ((type) == 0 || (mode) != BLKmode
        !          2479:                      || (TYPE_ALIGN ((type)) % PARM_BOUNDARY == 0))
        !          2480:                  ? gen_rtx (REG, (mode),
        !          2481:                             (FIRST_PARM_REG + rr)) 
        !          2482:                  : 0);
        !          2483: 
        !          2484:        }
        !          2485:     }
        !          2486:   return 0;
        !          2487: }
        !          2488: 
        !          2489: /* For an arg passed partly in registers and partly in memory,
        !          2490:    this is the number of registers used.
        !          2491:    For args passed entirely in registers or entirely in memory, zero.
        !          2492:    Any arg that starts in the first 4 regs but won't entirely fit in them
        !          2493:    needs partial registers on the SH.  */
        !          2494: 
        !          2495: int
        !          2496: sh_function_arg_partial_nregs (CUM, MODE, TYPE, NAMED)
        !          2497:      CUMULATIVE_ARGS CUM;
        !          2498:      enum machine_mode MODE;
        !          2499:      tree TYPE;
        !          2500:      int NAMED;
        !          2501: {
        !          2502:   if ((CUM) < NPARM_REGS)
        !          2503:     {
        !          2504:       if (((TYPE) == 0 || !TREE_ADDRESSABLE ((tree) (TYPE)))
        !          2505:          && ((TYPE) == 0 || (TYPE_ALIGN ((TYPE)) % PARM_BOUNDARY == 0))
        !          2506:          && ((CUM) + ((MODE) == BLKmode
        !          2507:                       ? ROUND_ADVANCE (int_size_in_bytes (TYPE))
        !          2508:                  : ROUND_ADVANCE (GET_MODE_SIZE (MODE))) - NPARM_REGS > 0))
        !          2509:        {
        !          2510:          return NPARM_REGS - CUM;
        !          2511:        }
        !          2512:     }
        !          2513:   return 0;
        !          2514: }
        !          2515: 
        !          2516: /* Turn this on to recognise shift insns which aren't supported in the
        !          2517:    hardware.  This will allow the combiner to notice more patterns,
        !          2518:    but the down side is that the asm outputter will have to emit
        !          2519:    several instructions for each shift which isn't possible in the
        !          2520:    hardware, this makes scheduling perform badly .*/ 
        !          2521: 
        !          2522: int fake_shift()
        !          2523: {
        !          2524:   return 0;
1.1.1.2   root     2525: }

unix.superglobalmegacorp.com

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