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

1.1     ! root        1: /* Output routines for GCC for Hitachi Super-H
        !             2:    Copyright (C) 1993 Free Software Foundation, Inc.
        !             3: 
        !             4: This file is part of GNU CC.
        !             5: 
        !             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.  */
        !            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"
        !            35: #include "insn-attr.h"
        !            36: #include "flags.h"
        !            37: #include "obstack.h"
        !            38: #include "expr.h"
        !            39: 
        !            40: 
        !            41: static int add_constant ();
        !            42: static int dump_constants ();
        !            43: 
        !            44: int current_function_anonymous_args;
        !            45: extern int current_function_pretend_args_size;
        !            46: 
        !            47: /* Global variables for machine-dependent things. */
        !            48: 
        !            49: /* Saved operands from the last compare to use when we generate an scc
        !            50:   or bcc insn. */
        !            51: 
        !            52: rtx sh_compare_op0;
        !            53: rtx sh_compare_op1;
        !            54: 
        !            55: /* Provides the class number of the smallest class containing
        !            56:    reg number */
        !            57: 
        !            58: int regno_reg_class[FIRST_PSEUDO_REGISTER] =
        !            59: {
        !            60:   R0_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
        !            61:   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
        !            62:   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
        !            63:   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
        !            64:   GENERAL_REGS, PR_REGS, T_REGS, NO_REGS, MAC_REGS,
        !            65:   MAC_REGS,
        !            66: };
        !            67: 
        !            68: /* Provide reg_class from a letter such as appears in the machine
        !            69:    description. */
        !            70: 
        !            71: enum reg_class reg_class_from_letter[] =
        !            72: {
        !            73:   /* a */ NO_REGS, /* b */ NO_REGS, /* c */ NO_REGS, /* d */ NO_REGS,
        !            74:   /* e */ NO_REGS, /* f */ NO_REGS, /* g */ NO_REGS, /* h */ NO_REGS,
        !            75:   /* i */ NO_REGS, /* j */ NO_REGS, /* k */ NO_REGS, /* l */ PR_REGS,
        !            76:   /* m */ NO_REGS, /* n */ NO_REGS, /* o */ NO_REGS, /* p */ NO_REGS,
        !            77:   /* q */ NO_REGS, /* r */ NO_REGS, /* s */ NO_REGS, /* t */ T_REGS,
        !            78:   /* u */ NO_REGS, /* v */ NO_REGS, /* w */ NO_REGS, /* x */ MAC_REGS,
        !            79:   /* y */ NO_REGS, /* z */ R0_REGS
        !            80: };
        !            81: 
        !            82: 
        !            83: /* Local label counter, used for constants in the pool and inside
        !            84:    pattern branches.  */
        !            85: 
        !            86: static int lf = 100;
        !            87: 
        !            88: /* Used to work out sizes of instructions */
        !            89: static int first_pc;
        !            90: static int pc;
        !            91: #define MAYBE_DUMP_LEVEL 900
        !            92: #define MUST_DUMP_LEVEL 1000
        !            93: static int dumpnext;
        !            94: 
        !            95: /* Functions for generating procedure prologue and epilogue code */
        !            96: 
        !            97: /* Adjust the stack and return the number of bytes taken to do it */
        !            98: 
        !            99: static int
        !           100: output_stack_adjust (file, direction, size)
        !           101:      FILE *file;
        !           102:      int direction;
        !           103:      int size;
        !           104: {
        !           105:   int code_size;
        !           106: 
        !           107:   if (size > 127)
        !           108:     {
        !           109:       fprintf (file, "\tmov.l  LK%d,r13\n",
        !           110:               add_constant (GEN_INT (size * direction), SImode));
        !           111: 
        !           112:       fprintf (file, "\tadd    r13,r15\n");
        !           113:       code_size += 4;
        !           114:     }
        !           115:   else if (size)
        !           116:     {
        !           117:       fprintf (file, "\tadd    #%d,r15\n", direction * size);
        !           118:       code_size += 2;
        !           119:     }
        !           120:   return code_size;
        !           121: }
        !           122: 
        !           123: /* Generate code to push the regs specified in the mask, and return
        !           124:    the number of bytes the insns take. */
        !           125: 
        !           126: static int
        !           127: push_regs (f, mask)
        !           128:      FILE *f;
        !           129:      int mask;
        !           130: {
        !           131:   int i;
        !           132:   int size = 0;
        !           133: 
        !           134:   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        !           135:     {
        !           136:       if (mask & (1 << i))
        !           137:        {
        !           138:          fprintf (f, "\tmov.l  r%d,@-r15\n", i);
        !           139:          size += 2;
        !           140:        }
        !           141:     }
        !           142:   return size;
        !           143: }
        !           144: 
        !           145: 
        !           146: /* Working out the right code to use for an epilogue can get quite
        !           147:    hairy, since there are only certain insns which can go in the delay
        !           148:    slot, and there may or may not be a delay insn provided already.
        !           149: 
        !           150:    We generate a canonical list of the instructions to use to perform
        !           151:    the exit, massage that and output from that list */
        !           152: 
        !           153: 
        !           154: /* The structure of a canonical element. */
        !           155: 
        !           156: typedef struct
        !           157: {
        !           158:   enum epi_type
        !           159:     {
        !           160:       STACK_ADJUST,            /* add i to stack pointer       */
        !           161:       POP,                     /* pop into register i          */
        !           162:       RTS,                     /* rts instruction              */
        !           163:       DELAY,                   /* delay slot instruction       */
        !           164:       NOP,                     /* a nop                        */
        !           165:       DELETED,
        !           166:     } type;
        !           167:   int i;
        !           168: }
        !           169: 
        !           170: epilogue_insn;
        !           171: 
        !           172: static epilogue_insn epilogue_vec[20];
        !           173: static int epilogue_vec_len;
        !           174: 
        !           175: static void
        !           176: set_epilogue_insn (type, l)
        !           177:      enum epi_type type;
        !           178:      int l;
        !           179: {
        !           180:   epilogue_vec[epilogue_vec_len].type = type;
        !           181:   epilogue_vec[epilogue_vec_len].i = l;
        !           182:   epilogue_vec_len++;
        !           183: }
        !           184: 
        !           185: /* Delete an insn from the epilogue list. */
        !           186: 
        !           187: static void
        !           188: delete_epilogue_insn (n)
        !           189:      int n;
        !           190: {
        !           191:   int j;
        !           192: 
        !           193:   for (j = n; j < epilogue_vec_len; j++)
        !           194:     epilogue_vec[j] = epilogue_vec[j + 1];
        !           195: 
        !           196:   epilogue_vec_len--;
        !           197: }
        !           198: 
        !           199: /* Run through the epilogue list and optimize it. */
        !           200: 
        !           201: static void
        !           202: optimize_epilogue_vec ()
        !           203: {
        !           204:   int i;
        !           205: 
        !           206:   /* Turn two adds in a row into one add and kill empty adds */
        !           207:   for (i = 0; i < epilogue_vec_len - 1; i++)
        !           208:     {
        !           209:       if (epilogue_vec[i].type == STACK_ADJUST
        !           210:          && epilogue_vec[i + 1].type == STACK_ADJUST)
        !           211:        {
        !           212:          epilogue_vec[i].i += epilogue_vec[i + 1].i;
        !           213:          delete_epilogue_insn (i + 1);
        !           214:        }
        !           215:       if (epilogue_vec[i].type == STACK_ADJUST
        !           216:          && epilogue_vec[i].i == 0)
        !           217:        delete_epilogue_insn (i);
        !           218:     }
        !           219: 
        !           220:   /* If the instruction after the RTS is a nop, see if it can be
        !           221:      changed */
        !           222: 
        !           223:   for (i = 1; i < epilogue_vec_len - 1; i++)
        !           224:     {
        !           225:       if (epilogue_vec[i].type == RTS
        !           226:          && epilogue_vec[i + 1].type == NOP)
        !           227:        {
        !           228:          epilogue_vec[i + 1] = epilogue_vec[i - 1];
        !           229:          delete_epilogue_insn (i - 1);
        !           230:        }
        !           231:     }
        !           232: 
        !           233:   /* Delete all the instructions after the rts's delay slot */
        !           234:   for (i = 0; i < epilogue_vec_len; i++)
        !           235:     {
        !           236:       if (epilogue_vec[i].type == RTS)
        !           237:        {
        !           238:          int j;
        !           239: 
        !           240:          for (j = i + 2; j < epilogue_vec_len; j++)
        !           241:            epilogue_vec[j].type = DELETED;
        !           242:          return;
        !           243:        }
        !           244:     }
        !           245: }
        !           246: 
        !           247: /* Dump out the insns in epilogue vector. */
        !           248: 
        !           249: static void
        !           250: output_epilogue_vec ()
        !           251: {
        !           252:   int i;
        !           253: 
        !           254:   for (i = 0; i < epilogue_vec_len; i++)
        !           255:     {
        !           256:       switch (epilogue_vec[i].type)
        !           257:        {
        !           258:        case STACK_ADJUST:
        !           259:          fprintf (asm_out_file, "\tadd #%d,r15\n", epilogue_vec[i].i);
        !           260:          break;
        !           261: 
        !           262:        case NOP:
        !           263:          fprintf (asm_out_file, "\tor  r0,r0\n");
        !           264:          break;
        !           265: 
        !           266:        case DELAY:
        !           267:          final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
        !           268:                           asm_out_file, 1, 0, 1);
        !           269:          break;
        !           270: 
        !           271:        case DELETED:
        !           272:          fprintf (asm_out_file, "\t!delete_epilogue_insnd\n");
        !           273:          break;
        !           274: 
        !           275:        case RTS:
        !           276:          fprintf (asm_out_file, "\trts\n");
        !           277:          break;
        !           278: 
        !           279:        case POP:
        !           280:          fprintf (asm_out_file, "\tmov.l       @r15+,r%d\n",
        !           281:                   epilogue_vec[i].i);
        !           282:          break;
        !           283:        }
        !           284:     }
        !           285:   epilogue_vec_len = 0;
        !           286: }
        !           287: 
        !           288: /* Number of bytes pushed for anonymous args */
        !           289: 
        !           290: static int extra_push;
        !           291: 
        !           292: /* Work out the registers which need to be saved, both as a mask and a
        !           293:    count */
        !           294: 
        !           295: int
        !           296: calc_live_regs (count)
        !           297:      int *count;
        !           298: {
        !           299:   int reg;
        !           300:   int live_regs_mask = 0;
        !           301:   *count = 0;
        !           302: 
        !           303:   for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg++)
        !           304:     {
        !           305:       if (regs_ever_live[reg] && !call_used_regs[reg])
        !           306:        {
        !           307:          (*count)++;
        !           308:          live_regs_mask |= (1 << reg);
        !           309:        }
        !           310:     }
        !           311:   return live_regs_mask;
        !           312: }
        !           313: 
        !           314: /* Generate a procedure prologue.  */
        !           315: 
        !           316: void
        !           317: output_prologue (f, frame_size)
        !           318:      FILE *f;
        !           319:      int frame_size;
        !           320: {
        !           321:   int live_regs_mask;
        !           322:   int d;
        !           323: 
        !           324:   pc = 0;
        !           325: 
        !           326:   /* This only happens when an arg has been split, part in
        !           327:      registers, part in memory.  Allocate the stack space so there is
        !           328:      somewhere to put the value */
        !           329: 
        !           330:   output_stack_adjust (f, -1, current_function_pretend_args_size);
        !           331: 
        !           332:   live_regs_mask = calc_live_regs (&d);
        !           333: 
        !           334:   extra_push = 0;
        !           335: 
        !           336:   if (current_function_anonymous_args)
        !           337:     {
        !           338:       /* Push arg regs as if they'd been provided by caller in stack */
        !           339:       int i;
        !           340:       for (i = 0; i < NPARM_REGS; i++)
        !           341:        {
        !           342:          int rn = NPARM_REGS + FIRST_PARM_REG - i - 1;
        !           343:          if (i > NPARM_REGS - current_function_args_info)
        !           344:            break;
        !           345:          fprintf (f, "\tmov.l  r%d,@-r15\n", rn);
        !           346:          extra_push += 4;
        !           347:          pc += 2;
        !           348:        }
        !           349:     }
        !           350: 
        !           351:   if (frame_pointer_needed)
        !           352:     {
        !           353:       /* Don't need to push the fp with the rest of the registers. */
        !           354:       live_regs_mask &= ~(1 << FRAME_POINTER_REGNUM);
        !           355:       pc += push_regs (f, live_regs_mask);
        !           356:       if (regs_ever_live[PR_REG])
        !           357:        {
        !           358: 
        !           359:          fprintf (f, "\tsts.l  pr,@-r15\n");
        !           360:          pc += 2;
        !           361:        }
        !           362: 
        !           363:       fprintf (f, "\tmov.l     r14,@-r15\n");
        !           364:       fprintf (f, "\tmov       r15,r14\n");
        !           365:       pc += 4;
        !           366:       pc += output_stack_adjust (f, -1, frame_size);
        !           367:     }
        !           368:   else
        !           369:     {
        !           370:       pc += push_regs (f, live_regs_mask);
        !           371: 
        !           372:       if (regs_ever_live[PR_REG])
        !           373:        {
        !           374: 
        !           375:          fprintf (f, "\tsts.l  pr,@-r15\n");
        !           376:          pc += 2;
        !           377:        }
        !           378:       pc += output_stack_adjust (f, -1, frame_size);
        !           379:     }
        !           380: }
        !           381: 
        !           382: 
        !           383: /* Generate a procedure epilogue. */
        !           384: 
        !           385: void
        !           386: output_epilogue (f, frame_size)
        !           387:      FILE *f;
        !           388:      int frame_size;
        !           389: {
        !           390:   int live_regs_mask = 0;
        !           391:   int d;
        !           392:   int i;
        !           393:   rtx delay_insn;
        !           394:   
        !           395:   live_regs_mask = calc_live_regs (&d);
        !           396: 
        !           397: 
        !           398:   /* See if the delay insn is really ok for the slot. */
        !           399:   if (current_function_epilogue_delay_list) {
        !           400:     delay_insn = PATTERN (XEXP (current_function_epilogue_delay_list, 0));
        !           401: 
        !           402:   if (GET_CODE (delay_insn) == SET
        !           403:       && SET_DEST (delay_insn) == stack_pointer_rtx)
        !           404:     {
        !           405:       /* Can not use this instruction in the delay slot because
        !           406:         it changes the stack pointer, so emit it now.  */
        !           407:       final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
        !           408:                       asm_out_file, 1, 0, 1);
        !           409:       current_function_epilogue_delay_list = 0;
        !           410:     }
        !           411:   }
        !           412:   
        !           413: 
        !           414:   /* Reclaim the room for the automatics. */
        !           415: 
        !           416:   output_stack_adjust (f, 1, frame_size);
        !           417: 
        !           418:   /* Make the frame pointer. */
        !           419: 
        !           420:   if (frame_pointer_needed)
        !           421:     {
        !           422:       fprintf (f, "\tmov       r14,r15\n");
        !           423:       fprintf (f, "\tmov.l     @r15+,r14\n");
        !           424:       live_regs_mask &= ~(1 << FRAME_POINTER_REGNUM);
        !           425:     }
        !           426: 
        !           427:   /* Get the PR register if it was clobbered in the function. */
        !           428: 
        !           429:   if (regs_ever_live[PR_REG])
        !           430:     fprintf (f, "\tlds.l       @r15+,pr\n");
        !           431: 
        !           432:   /* Pop all the registers */
        !           433:   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        !           434:     {
        !           435:       int j = (FIRST_PSEUDO_REGISTER - 1) - i;
        !           436:       if (live_regs_mask & (1 << j))
        !           437:        {
        !           438:          set_epilogue_insn (POP, j);
        !           439:        }
        !           440:     }
        !           441: 
        !           442:   /* Need to adjust the stack by some amount of bytes since we've pushed
        !           443:      some of the args which normally come in registers */
        !           444: 
        !           445:   set_epilogue_insn (STACK_ADJUST, extra_push);
        !           446: 
        !           447:   /* Need to adjust the stack by some amount of bytes if there
        !           448:      an arg has been split part register and part stack */
        !           449: 
        !           450:   set_epilogue_insn (STACK_ADJUST, current_function_pretend_args_size);
        !           451: 
        !           452:   set_epilogue_insn (RTS, 0);
        !           453: 
        !           454:   /* Got here without dumping a register pop into the delay slot */
        !           455:   if (current_function_epilogue_delay_list)
        !           456:     {
        !           457:       set_epilogue_insn (DELAY, 0);
        !           458:     }
        !           459:   set_epilogue_insn (NOP, 0);
        !           460: 
        !           461:   optimize_epilogue_vec ();
        !           462: 
        !           463:   output_epilogue_vec ();
        !           464: 
        !           465:   dump_constants (0);
        !           466:   current_function_anonymous_args = 0;
        !           467: }
        !           468: 
        !           469: /* Print the operand address in x to the stream */
        !           470: 
        !           471: void
        !           472: print_operand_address (stream, x)
        !           473:      FILE *stream;
        !           474:      rtx x;
        !           475: {
        !           476:   switch (GET_CODE (x))
        !           477:     {
        !           478:     case REG:
        !           479:       fprintf (stream, "@%s", reg_names[REGNO (x)]);
        !           480:       break;
        !           481: 
        !           482:     case PLUS:
        !           483:       {
        !           484:        rtx base = XEXP (x, 0);
        !           485:        rtx index = XEXP (x, 1);
        !           486: 
        !           487:        if (GET_CODE (base) != REG)
        !           488:          {
        !           489:            /* Ensure that BASE is a register (one of them must be). */
        !           490:            rtx temp = base;
        !           491:            base = index;
        !           492:            index = temp;
        !           493:          }
        !           494: 
        !           495:        switch (GET_CODE (index))
        !           496:          {
        !           497:          case CONST_INT:
        !           498:            fprintf (stream, "@(%d,%s)",
        !           499:                     INTVAL (index),
        !           500:                     reg_names[REGNO (base)]);
        !           501:            break;
        !           502: 
        !           503:          case REG:
        !           504:            fprintf (stream, "@(%s,%s)",
        !           505:                     reg_names[REGNO (base)],
        !           506:                     reg_names[REGNO (index)]);
        !           507:            break;
        !           508: 
        !           509:          default:
        !           510:            abort ();
        !           511:          }
        !           512:       }
        !           513: 
        !           514:       break;
        !           515:     case PRE_DEC:
        !           516:       fprintf (stream, "@-%s", reg_names[REGNO (XEXP (x, 0))]);
        !           517:       break;
        !           518: 
        !           519:     case POST_INC:
        !           520:       fprintf (stream, "@%s+", reg_names[REGNO (XEXP (x, 0))]);
        !           521:       break;
        !           522: 
        !           523:     default:
        !           524:       output_addr_const (stream, x);
        !           525:       break;
        !           526:     }
        !           527: }
        !           528: 
        !           529: /* Print operand x (an rtx) in assembler syntax to file stream
        !           530:    according to modifier code.
        !           531: 
        !           532:  '*'  print a local label
        !           533:  '^'  increment the local label number
        !           534:  '!'  dump the constant table
        !           535:  '#'  output a nop if there is nothing to put in the delay slot
        !           536:  'R'  print the next register or memory location along, ie the lsw in
        !           537:       a double word value
        !           538:  'I'  put something into the constant pool and print its label */
        !           539: 
        !           540: void
        !           541: print_operand (stream, x, code)
        !           542:      FILE *stream;
        !           543:      rtx x;
        !           544:      int code;
        !           545: {
        !           546:   switch (code)
        !           547:     {
        !           548:     case '*':
        !           549:       fprintf (stream, "LF%d", lf);
        !           550:       break;
        !           551:     case '!':
        !           552:       dump_constants (0);
        !           553:       break;
        !           554:     case '^':
        !           555:       lf++;
        !           556:       break;
        !           557: 
        !           558:     case '#':
        !           559:       /* Output a nop if there's nothing in the delay slot */
        !           560:       if (dbr_sequence_length () == 0)
        !           561:        {
        !           562:          fprintf (stream, "\n\tor      r0,r0\t!wasted slot");
        !           563:        }
        !           564:       break;
        !           565: 
        !           566:     case 'I':
        !           567:       fprintf (asm_out_file, "LK%d", add_constant (x, SImode));
        !           568:       break;
        !           569: 
        !           570:     case 'R':
        !           571:       /* Next location along in memory or register*/
        !           572:       switch (GET_CODE (x))
        !           573:        {
        !           574:        case REG:
        !           575:          fputs (reg_names[REGNO (x) + 1], (stream));
        !           576:          break;
        !           577:        case MEM:
        !           578:          print_operand_address (stream,
        !           579:                               XEXP (adj_offsettable_operand (x, 4), 0), 0);
        !           580:          break;
        !           581:        }
        !           582:       break;
        !           583: 
        !           584:     default:
        !           585:       switch (GET_CODE (x))
        !           586:        {
        !           587:        case REG:
        !           588:          fputs (reg_names[REGNO (x)], (stream));
        !           589:          break;
        !           590:        case MEM:
        !           591:          output_address (XEXP (x, 0));
        !           592:          break;
        !           593:        default:
        !           594:          fputc ('#', stream);
        !           595:          output_addr_const (stream, x);
        !           596:          break;
        !           597: 
        !           598:        }
        !           599:       break;
        !           600:     }
        !           601: }
        !           602: 
        !           603: 
        !           604: 
        !           605: /* Define the offset between two registers, one to be eliminated, and 
        !           606:    the other its replacement, at the start of a routine.  */
        !           607: 
        !           608: int
        !           609: initial_elimination_offset (from, to)
        !           610: {
        !           611:   int regs_saved;
        !           612:   int d = calc_live_regs (&regs_saved);
        !           613:   int total_saved_regs_space = (regs_saved + regs_ever_live[PR_REG]) * 4;
        !           614:   int total_auto_space = get_frame_size ();
        !           615: 
        !           616: 
        !           617:   if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
        !           618:     {
        !           619:       return total_saved_regs_space;
        !           620:     }
        !           621: 
        !           622:   if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
        !           623:     {
        !           624:       return total_saved_regs_space + total_auto_space;
        !           625:     }
        !           626: 
        !           627:   if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
        !           628:     {
        !           629:       return total_auto_space;
        !           630:     }
        !           631: }
        !           632: 
        !           633: delay_slots_for_epilogue ()
        !           634: {
        !           635:   /* We need to find something to fill the epilogue if there won't be
        !           636:      any instructions to make the stack or pop registers which can be
        !           637:      moved into the slot */
        !           638: 
        !           639:   int d;
        !           640:   calc_live_regs (&d);
        !           641:   return !(get_frame_size () + d);
        !           642: }
        !           643: 
        !           644: 
        !           645: /* Prepare operands for a move define_expand; specifically, one of the
        !           646:    operands must be in a register */
        !           647: 
        !           648: void
        !           649: prepare_move_operands (operands, mode)
        !           650:      rtx operands[];
        !           651:      enum machine_mode mode;
        !           652: {
        !           653:   /* One of the operands has to be a register */
        !           654:   if ((!register_operand (operands[0], mode)
        !           655:        && !register_operand (operands[1], mode))
        !           656:       || GET_CODE(operands[1]) == PLUS)
        !           657:     {
        !           658:       /* copy the source to a register */
        !           659:       operands[1] = copy_to_mode_reg (mode, operands[1]);
        !           660:     }
        !           661: }
        !           662: 
        !           663: 
        !           664: /* Prepare the operands for an scc instruction; make sure that the
        !           665:    compare has been done.  */
        !           666: rtx
        !           667: prepare_scc_operands (code)
        !           668: {
        !           669:   if (GET_CODE(sh_compare_op0) != REG 
        !           670:       || REGNO(sh_compare_op0) != T_REG)
        !           671:     {
        !           672:       /* First need a compare insn */
        !           673:       emit_insn (gen_rtx (SET, SImode, 
        !           674:                          gen_rtx (REG, SImode, T_REG),
        !           675:                          gen_rtx (code, SImode, sh_compare_op0,
        !           676:                                   sh_compare_op1)));
        !           677:     }
        !           678:   return gen_rtx(REG, SImode, T_REG);
        !           679: }
        !           680: 
        !           681: /* Functions to output assembly */
        !           682: 
        !           683: /* Return a sequence of instructions to perform DI move, taking into
        !           684:    account overlapping source and dest registers */
        !           685: 
        !           686: char *
        !           687: output_movedouble (operands, mode)
        !           688:      rtx operands[];
        !           689:      enum machine_mode mode;
        !           690: {
        !           691:   if (register_operand (operands[0], mode)
        !           692:       && register_operand (operands[1], mode))
        !           693:     {
        !           694:       if (REGNO (operands[1]) == MACH_REG)
        !           695:        return "sts     mach,%0\n\tsts  macl,%R0";
        !           696:       if (REGNO (operands[1]) > REGNO (operands[0])) 
        !           697:        {
        !           698:          return "mov   %1,%0\n\tmov    %R1,%R0";
        !           699:        }
        !           700:       else 
        !           701:        {
        !           702:          return "mov   %R1,%R0\n\tmov  %1,%0";
        !           703:        }
        !           704:     }
        !           705: 
        !           706:   if (GET_CODE (operands[1]) == CONST_INT)
        !           707:     {
        !           708:       if (INTVAL (operands[1]) < 0)
        !           709:        return "mov     #-1,%0\n\tmov   %1,%R0";
        !           710:       else
        !           711:        return "mov     #0,%0\n\tmov    %1,%R0";
        !           712:     }
        !           713: 
        !           714:   if (GET_CODE (operands[1]) == MEM)
        !           715:     {
        !           716:       int idxreg = -1;
        !           717:       rtx inside = XEXP (operands[1], 0);
        !           718: 
        !           719:       if (GET_CODE (inside) == REG)
        !           720:        idxreg = REGNO (inside);
        !           721:       else if (GET_CODE (inside) == PLUS)
        !           722:        {
        !           723:          rtx lhs = XEXP (inside, 0);
        !           724:          rtx rhs = XEXP (inside, 1);
        !           725:          if (GET_CODE (lhs) == REG)
        !           726:            idxreg = REGNO (lhs);
        !           727:          else if (GET_CODE (rhs) == REG)
        !           728:            idxreg = REGNO (rhs);
        !           729:          else
        !           730:            abort ();
        !           731:        }
        !           732:       else
        !           733:        abort ();
        !           734: 
        !           735:       if (REGNO (operands[0]) != idxreg)
        !           736:        {
        !           737:          /* The dest register is mentioned in the addressing mode,
        !           738:             so print them the other way around */
        !           739:          return "mov.l %1,%0\n\tmov.l  %R1,%R0 ! one way";
        !           740:        }
        !           741:       return "mov.l    %R1,%R0\n\tmov.l        %1,%0 ! other way";
        !           742:     }
        !           743: 
        !           744:   return "mov.l        %R1,%R0\n\tmov.l        %1,%0";
        !           745: }
        !           746: 
        !           747: /* Emit assembly to shift reg by k bits */
        !           748: 
        !           749: char *
        !           750: output_shift (string, reg, k)
        !           751:      char *string;
        !           752:      rtx reg;
        !           753:      rtx k;
        !           754: {
        !           755:   int s = INTVAL (k);
        !           756:   while (s)
        !           757:     {
        !           758:       char *out;
        !           759:       int d;
        !           760: 
        !           761:       if (s >= 16)
        !           762:        {
        !           763:          d = 16;
        !           764:          out = "16";
        !           765:        }
        !           766:       else if (s >= 8)
        !           767:        {
        !           768:          d = 8;
        !           769:          out = "8";
        !           770:        }
        !           771:       else if (s >= 2)
        !           772:        {
        !           773:          d = 2;
        !           774:          out = "2";
        !           775:        }
        !           776:       else
        !           777:        {
        !           778:          d = 1;
        !           779:          out = "";
        !           780:        }
        !           781:       fprintf (asm_out_file, "\t%s%s\tr%d\n", string, out, REGNO (reg));
        !           782:       s -= d;
        !           783:     }
        !           784:   return "";
        !           785: }
        !           786: 
        !           787: /* Return the text of the branch instruction which matches its length
        !           788:    attribute.  */
        !           789: 
        !           790: char *
        !           791: output_branch (logic, insn)
        !           792:      int logic;
        !           793:      rtx *insn;
        !           794: {
        !           795:   extern rtx recog_operand[];
        !           796:   int label = lf++;
        !           797:   
        !           798:   switch (get_attr_length (insn))
        !           799:     {
        !           800:     case 2:
        !           801:       /* Simple branch in range -200..+200 bytes */
        !           802:       return logic ? "bt       %l0" : "bf      %l0";
        !           803: 
        !           804:     case 6:
        !           805:       /* Branch in range -4000..+4000 bytes */
        !           806:       fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't', label);
        !           807:       output_asm_insn ("bra    %l0     ! 12 bit cond ", recog_operand);
        !           808:       fprintf (asm_out_file, "\tor     r0,r0\n");
        !           809:       label = dump_constants (label);
        !           810:       fprintf (asm_out_file, "LF%d:\n", label);
        !           811:       return "";
        !           812: 
        !           813:     case 8:
        !           814:       /* Branches a long way away */
        !           815:        
        !           816:       fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't', label);
        !           817:       output_asm_insn ("mov.l  %I0,r13", recog_operand);
        !           818:       fprintf (asm_out_file, "\tjmp    @r13    ! 32 cond \n");
        !           819:       fprintf (asm_out_file, "\tor     r0,r0\n");
        !           820:       fprintf (asm_out_file, "LF%d:\n", label);
        !           821:       return "";
        !           822:     }
        !           823:   return "bad";
        !           824: 
        !           825: }
        !           826: 
        !           827: /* Predicates used by the templates */
        !           828: 
        !           829: /* Nonzero if OP is a normal arithmetic register. */
        !           830: 
        !           831: int
        !           832: arith_reg_operand(op, mode)
        !           833:      rtx op;
        !           834:      enum machine_mode mode;
        !           835: {
        !           836:   if (register_operand (op, mode))
        !           837:     {
        !           838:       if (GET_CODE (op) == REG)
        !           839:        return REGNO (op) != T_REG;
        !           840:       return 1;
        !           841:     }
        !           842:   return 0;
        !           843: }
        !           844: 
        !           845:   
        !           846: /* Nonzero if OP is a valid source operand for an arithmetic insn.  */
        !           847: 
        !           848: int
        !           849: arith_operand (op, mode)
        !           850:      rtx op;
        !           851:      enum machine_mode mode;
        !           852: {
        !           853:   if (register_operand (op, mode))
        !           854:     return 1;
        !           855: 
        !           856:   if (GET_CODE (op) == CONST_INT)
        !           857:     {
        !           858:       if (CONST_OK_FOR_I (INTVAL (op)))
        !           859:        return 1;
        !           860:     }
        !           861:   return 0;
        !           862: }
        !           863: 
        !           864: 
        !           865: /* Nonzero if OP is a valid source operand for a logical operation */
        !           866: 
        !           867: int
        !           868: logical_operand (op, mode)
        !           869:      rtx op;
        !           870:      enum machine_mode mode;
        !           871: {
        !           872:   if (register_operand (op, mode))
        !           873:     return 1;
        !           874: 
        !           875:   if (GET_CODE (op) == CONST_INT)
        !           876:     {
        !           877:       if (CONST_OK_FOR_L (INTVAL (op)))
        !           878:        return 1;
        !           879:     }
        !           880:   return 0;
        !           881: }
        !           882: 
        !           883: /* Nonzero if p is a valid shift operand for lshr and ashl */
        !           884: 
        !           885: int
        !           886: ok_shift_value (p)
        !           887:      rtx p;
        !           888: {
        !           889:   if (GET_CODE (p) == CONST_INT)
        !           890:     {
        !           891:       switch (INTVAL (p))
        !           892:        {
        !           893:        case 1:
        !           894:        case 2:
        !           895:        case 8:
        !           896:        case 16:
        !           897:          return 1;
        !           898:        default:
        !           899:          if (TARGET_FASTCODE)
        !           900:            return INTVAL(p) >= 0;
        !           901:        }
        !           902:     }
        !           903:   return 0;
        !           904: }
        !           905: 
        !           906: /* Nonzero if the arg is an immediate which has to be loaded from
        !           907:    memory */
        !           908: 
        !           909: int
        !           910: hard_immediate_operand (op, mode)
        !           911:      rtx op;
        !           912:      enum machine_mode mode;
        !           913: {
        !           914:   if (immediate_operand (op, mode))
        !           915:     {
        !           916:       if (GET_CODE (op) == CONST_INT
        !           917:          && INTVAL (op) >= -128 && INTVAL (op) < 127)
        !           918:        return 0;
        !           919:       return 1;
        !           920:     }
        !           921:   return 0;
        !           922: }
        !           923: 
        !           924: /* The SH cannot load a large constant into a register, constants have to
        !           925:    come from a pc relative load.  The reference of a pc relative load
        !           926:    instruction must be less than 1k infront of the instruction.  This
        !           927:    means that we often have to dump a constant inside a function, and
        !           928:    generate code to branch around it.
        !           929: 
        !           930:    It is important to minimize this, since the branches will slow things
        !           931:    down and make things bigger.
        !           932: 
        !           933:   Worst case code looks like:
        !           934: 
        !           935:       mov.l L1,rn
        !           936:       bra   L2
        !           937:       nop
        !           938:       align
        !           939: L1:   .long value
        !           940: L2:
        !           941:       ..
        !           942: 
        !           943:       mov.l L3,rn
        !           944:       bra   L4
        !           945:       nop
        !           946:       align
        !           947: L3:   .long value
        !           948: L4:
        !           949:       ..
        !           950: 
        !           951:    During shorten_branches we notice the instructions which can have a
        !           952:    constant table in them, if we see two that are close enough
        !           953:    together, we move the constants from the first table to the second
        !           954:    table and continue.  This process can happen again and again, and
        !           955:    in the best case, moves the constant table outside of the function.
        !           956: 
        !           957:    In the above example, we can tell that L3 is within 1k of L1, so
        !           958:    the first move can be shrunk from the 3 insn+constant sequence into
        !           959:    just 1 insn, and the constant moved to L3 to make:
        !           960: 
        !           961:    mov.l       L1,rn
        !           962:    ..
        !           963:    mov.l       L3,rn
        !           964:    bra         L4
        !           965:    nop
        !           966:    align
        !           967: L3:.long value
        !           968: L4:.long value
        !           969: 
        !           970:    Then the second move becomes the target for the shortening process.
        !           971: 
        !           972:    We keep a simple list of all the constants accumulated in the
        !           973:    current pool so there are no duplicates in a single table, but
        !           974:    they are not factored into the size estimates.
        !           975: 
        !           976: */
        !           977: 
        !           978: typedef struct
        !           979: {
        !           980:   rtx value;
        !           981:   int number;
        !           982:   enum machine_mode mode;
        !           983: } pool_node;
        !           984: 
        !           985: /* The maximum number of constants that can fit into one pool, since
        !           986:    the pc relative range is 0...1020 bytes and constants are at least 4
        !           987:    bytes long */
        !           988: 
        !           989: #define MAX_POOL_SIZE (1020/4)
        !           990: static pool_node pool_vector[MAX_POOL_SIZE];
        !           991: static int pool_size;
        !           992: 
        !           993: 
        !           994: /* Add a constant to the pool and return its label number.  */
        !           995: 
        !           996: static int
        !           997: add_constant (x, mode)
        !           998:      rtx x;
        !           999:      enum machine_mode mode;
        !          1000: {
        !          1001:   int i;
        !          1002: 
        !          1003:   /* Start the countdown on the first constant */
        !          1004: 
        !          1005:   if (!pool_size)
        !          1006:     {
        !          1007:       first_pc = pc;
        !          1008:     }
        !          1009: 
        !          1010:   /* First see if we've already got it */
        !          1011: 
        !          1012:   for (i = 0; i < pool_size; i++)
        !          1013:     {
        !          1014: 
        !          1015:       if (x->code == pool_vector[i].value->code
        !          1016:          && mode == pool_vector[i].mode)
        !          1017:        {
        !          1018:          if (x->code == CODE_LABEL)
        !          1019:            {
        !          1020:              if (XINT (x, 3) != XINT (pool_vector[i].value, 3))
        !          1021:                continue;
        !          1022:            }
        !          1023:        }
        !          1024: 
        !          1025:       if (rtx_equal_p (x, pool_vector[i].value))
        !          1026:        return pool_vector[i].number;
        !          1027:     }
        !          1028:   
        !          1029: 
        !          1030:   pool_vector[pool_size].value = x;
        !          1031:   pool_vector[pool_size].mode = mode;
        !          1032:   pool_vector[pool_size].number = lf;
        !          1033:   pool_size++;
        !          1034: 
        !          1035:   return lf++;
        !          1036: }
        !          1037: 
        !          1038: /* Nonzero if the insn could take a constant table.  */
        !          1039: 
        !          1040: static int
        !          1041: has_constant_table (insn)
        !          1042:      rtx insn;
        !          1043: {
        !          1044:   rtx body;
        !          1045: 
        !          1046:   if (GET_CODE (insn) == NOTE
        !          1047:       || GET_CODE (insn) == BARRIER
        !          1048:       || GET_CODE (insn) == CODE_LABEL)
        !          1049:     return 0;
        !          1050: 
        !          1051:   body = PATTERN (insn);
        !          1052:   if (GET_CODE (body) == SEQUENCE)
        !          1053:     return 0;
        !          1054:   if (GET_CODE (body) == ADDR_VEC)
        !          1055:     return 0;
        !          1056:   if (GET_CODE (body) == USE)
        !          1057:     return 0;
        !          1058:   if (GET_CODE (body) == CLOBBER)
        !          1059:     return 0;
        !          1060:   if (get_attr_constneed (insn) == CONSTNEED_YES)
        !          1061:     return 1;
        !          1062: 
        !          1063:   if (GET_CODE (body) == UNSPEC_VOLATILE)
        !          1064:     {
        !          1065:       return INTVAL (XVECEXP (body, 0, 0)) == 1;
        !          1066:     }
        !          1067:   return 0;
        !          1068: }
        !          1069: 
        !          1070: /*  Adjust the length of an instruction.
        !          1071: 
        !          1072:     We'll look at the previous instruction which holds a constant
        !          1073:     table and see if we can move the table to here instead. */
        !          1074: 
        !          1075: int target_insn_uid;
        !          1076: int target_insn_smallest_size;
        !          1077: 
        !          1078: int target_pc;
        !          1079: int target_insn_range;
        !          1080: int current_pc;
        !          1081: int table_size;
        !          1082: 
        !          1083: void
        !          1084: adjust_insn_length (insn, insn_lengths)
        !          1085:      rtx insn;
        !          1086:      short *insn_lengths;
        !          1087: {
        !          1088:   int uid = INSN_UID (insn);
        !          1089: 
        !          1090:   current_pc += insn_lengths[uid];
        !          1091: 
        !          1092:   if (has_constant_table (insn)) 
        !          1093:     {
        !          1094:       if (current_pc >= target_insn_range)
        !          1095:        {
        !          1096:          /* This instruction is further away from the referencing
        !          1097:             instruction than it can reach, so we'll stop accumulating
        !          1098:             from that one and start fresh. */
        !          1099:          target_pc = current_pc;
        !          1100:          target_insn_range = current_pc + MAYBE_DUMP_LEVEL;
        !          1101:        }
        !          1102:       else
        !          1103:        {
        !          1104:          /* This instruction is within the reach of the target,
        !          1105:             remove the constant table from the target by adjusting
        !          1106:             downwards, and increase the size of this one to
        !          1107:             compensate.  */
        !          1108: 
        !          1109: 
        !          1110:          /* Add the stuff from this insn to what will go in the
        !          1111:             growing table. */
        !          1112: 
        !          1113:          table_size += get_attr_constantsize (insn);
        !          1114: 
        !          1115:          /* The target shinks to its smallest natural size */
        !          1116:          insn_lengths[target_insn_uid] = target_insn_smallest_size;
        !          1117: 
        !          1118:          /* The current insn grows to be its larger size plust the
        !          1119:             table size. */
        !          1120: 
        !          1121:          insn_lengths[uid] = get_attr_largestsize (insn) + table_size;
        !          1122: 
        !          1123:        }
        !          1124:       /* Current insn becomes the target.  */
        !          1125:       target_insn_uid = uid;
        !          1126:       target_insn_smallest_size = get_attr_smallestsize (insn);
        !          1127: 
        !          1128:     }
        !          1129: 
        !          1130: }
        !          1131: 
        !          1132: 
        !          1133: /* Dump out the pending constant pool. 
        !          1134:    If label provided then insert an branch in the middle of the table 
        !          1135:   */
        !          1136: 
        !          1137: static int
        !          1138: dump_constants (label)
        !          1139: {
        !          1140:   int i;
        !          1141:   int rlabel = label;
        !          1142:   int size = 0;
        !          1143:   
        !          1144:   for (i = 0; i < pool_size; i++)
        !          1145:     {
        !          1146:       pool_node *p = pool_vector + i;
        !          1147:       fprintf (asm_out_file, "\n\t! constants - waited %d\n", pc - first_pc);
        !          1148:       fprintf (asm_out_file, "\t.align\t2\n");
        !          1149:       fprintf (asm_out_file, "LK%d:", p->number);
        !          1150:       size += GET_MODE_SIZE (p->mode);
        !          1151:       
        !          1152:       switch (GET_MODE_CLASS (p->mode))
        !          1153:        {
        !          1154:        case MODE_INT:
        !          1155:        case MODE_PARTIAL_INT:
        !          1156:          assemble_integer (p->value, GET_MODE_SIZE (p->mode), 1);
        !          1157:          break;
        !          1158:        case MODE_FLOAT:
        !          1159:          {
        !          1160:            union real_extract u;
        !          1161:            bcopy (&CONST_DOUBLE_LOW (p->value), &u, sizeof u);
        !          1162:            assemble_real (u.d, p->mode);
        !          1163:          }
        !          1164:        }
        !          1165:       
        !          1166:       /* After 200 bytes of table, stick in another branch */
        !          1167:       if (label && size > 200) 
        !          1168:        {
        !          1169:          rlabel = lf ++;
        !          1170:          fprintf (asm_out_file,"LF%d:\tbra     LF%d\n", label, rlabel);
        !          1171:          fprintf (asm_out_file,"\tor   r0,r0\n");
        !          1172:          label = 0;
        !          1173:        }
        !          1174:       
        !          1175:       fprintf (asm_out_file, "\n");
        !          1176:     }
        !          1177:   pool_size = 0;
        !          1178:   current_pc = 0;
        !          1179:   target_insn_range = 0;
        !          1180:   return rlabel;
        !          1181:   
        !          1182: }
        !          1183: 
        !          1184: 
        !          1185: /* Emit the text to load a value from a constant table.  */
        !          1186: 
        !          1187: char *
        !          1188: output_movepcrel (insn, operands, mode)
        !          1189:      rtx insn;
        !          1190:      rtx operands[];
        !          1191:      enum machine_mode mode;
        !          1192: {
        !          1193:   int len = GET_MODE_SIZE (mode);
        !          1194:   int rn = REGNO (operands[0]);
        !          1195: 
        !          1196:   fprintf (asm_out_file, "\tmov.l      LK%d,r%d\n",
        !          1197:           add_constant (operands[1], mode), rn);
        !          1198: 
        !          1199:   if (GET_MODE_SIZE(mode) > 4) 
        !          1200:     {
        !          1201:       fprintf (asm_out_file,
        !          1202:               "\tmov.l LK%d+4,r%d\n",
        !          1203:               add_constant (operands[1], mode),
        !          1204:               rn + 1);
        !          1205: 
        !          1206:     } 
        !          1207:   /* If this instruction is as small as it can be, there can be no 
        !          1208:      constant table attached to it.  */
        !          1209:   if (get_attr_length (insn) !=  get_attr_smallestsize (insn))
        !          1210:     {
        !          1211:       /* This needs a constant table */
        !          1212:       fprintf (asm_out_file, "\t!constant table start\n");
        !          1213:       fprintf (asm_out_file, "\tbra    LF%d\n", lf);
        !          1214:       fprintf (asm_out_file, "\tor     r0,r0 ! wasted slot\n");
        !          1215:       dump_constants (0);
        !          1216:       fprintf (asm_out_file, "LF%d:\n", lf++);
        !          1217:       fprintf (asm_out_file, "\t!constant table end\n");
        !          1218:     }
        !          1219:   return "";
        !          1220: }
        !          1221: 
        !          1222: 
        !          1223: /* Dump out interesting debug info */
        !          1224: 
        !          1225: void
        !          1226: final_prescan_insn (insn, opvec, noperands)
        !          1227:      rtx insn;
        !          1228:      rtx *opvec;
        !          1229:      int noperands;
        !          1230: {
        !          1231:   register rtx body = PATTERN (insn);
        !          1232: 
        !          1233:   if (target_flags & ISIZE_BIT)
        !          1234:     {
        !          1235:       extern int *insn_addresses;
        !          1236: 
        !          1237:       fprintf (asm_out_file, "\n!%04x*\n",
        !          1238:               insn_addresses[INSN_UID (insn)] + 0x10);
        !          1239: 
        !          1240:       fprintf (asm_out_file, "\n!%04x %d %04x len=%d\n",
        !          1241:               pc, pool_size, first_pc, get_attr_length (insn));
        !          1242: 
        !          1243:       if (TARGET_DUMP_RTL)
        !          1244:        print_rtl (asm_out_file, body);
        !          1245: 
        !          1246: 
        !          1247:     }
        !          1248:   
        !          1249:   pc += get_attr_length (insn);
        !          1250: 
        !          1251:   if (pool_size && pc - first_pc > MUST_DUMP_LEVEL)
        !          1252:     {
        !          1253:       /* For some reason we have not dumped out a constant table, and 
        !          1254:       we have emitted a lot of code.  This can happen if the think
        !          1255:       which wants the table is a long conditional branch (which has no
        !          1256:       room for a constant table), and there has not been a move
        !          1257:       constant anywhere. */
        !          1258:       int label = lf++;
        !          1259:       fprintf (asm_out_file, "\t!forced constant table\n");      
        !          1260:       fprintf (asm_out_file, "\tbra    LF%d\n", label);
        !          1261:       fprintf (asm_out_file, "\tor     r0,r0 ! wasted slot\n");
        !          1262:       label = dump_constants (label);
        !          1263:       fprintf (asm_out_file, "LF%d:\n", label);
        !          1264:       fprintf (asm_out_file, "\t!constant table end\n");
        !          1265:     }
        !          1266:   
        !          1267: }
        !          1268: 
        !          1269: 

unix.superglobalmegacorp.com

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