Annotation of researchv10dc/cmd/gcc/jump.c, revision 1.1.1.1

1.1       root        1: /* Optimize jump instructions, for GNU compiler.
                      2:    Copyright (C) 1988 Free Software Foundation, Inc.
                      3: 
                      4: This file is part of GNU CC.
                      5: 
                      6: GNU CC is distributed in the hope that it will be useful,
                      7: but WITHOUT ANY WARRANTY.  No author or distributor
                      8: accepts responsibility to anyone for the consequences of using it
                      9: or for whether it serves any particular purpose or works at all,
                     10: unless he says so in writing.  Refer to the GNU CC General Public
                     11: License for full details.
                     12: 
                     13: Everyone is granted permission to copy, modify and redistribute
                     14: GNU CC, but only under the conditions described in the
                     15: GNU CC General Public License.   A copy of this license is
                     16: supposed to have been given to you along with GNU CC so you
                     17: can know your rights and responsibilities.  It should be in a
                     18: file named COPYING.  Among other things, the copyright notice
                     19: and this notice must be preserved on all copies.  */
                     20: 
                     21: 
                     22: /* This is the jump-optimization pass of the compiler.
                     23:    It is run two or three times: once before cse, sometimes once after cse,
                     24:    and once after reload (before final).
                     25: 
                     26:    jump_optimize deletes unreachable code and labels that are not used.
                     27:    It also deletes jumps that jump to the following insn,
                     28:    and simplifies jumps around unconditional jumps and jumps
                     29:    to unconditional jumps.
                     30: 
                     31:    Each CODE_LABEL has a count of the times it is used
                     32:    stored in the LABEL_NUSES internal field, and each JUMP_INSN
                     33:    has one label that it refers to stored in the
                     34:    JUMP_LABEL internal field.  With this we can detect labels that
                     35:    become unused because of the deletion of all the jumps that
                     36:    formerly used them.  The JUMP_LABEL info is sometimes looked
                     37:    at by later passes.
                     38: 
                     39:    Optionally, cross-jumping can be done.  Currently it is done
                     40:    only the last time (when after reload and before final).
                     41:    In fact, the code for cross-jumping now assumes that register
                     42:    allocation has been done, since it uses `rtx_renumbered_equal_p'.
                     43: 
                     44:    Jump optimization is done after cse when cse's constant-propagation
                     45:    causes jumps to become unconditional or to be deleted.
                     46: 
                     47:    Unreachable loops are not detected here, because the labels
                     48:    have references and the insns appear reachable from the labels.
                     49:    find_basic_blocks in flow.c finds and deletes such loops.
                     50: 
                     51:    The subroutines delete_insn, redirect_jump, invert_jump, next_real_insn
                     52:    and prev_real_insn are used from other passes as well.  */
                     53: 
                     54: #include "config.h"
                     55: #include "rtl.h"
                     56: #include "flags.h"
                     57: #include "regs.h"
                     58: 
                     59: /* ??? Eventually must record somehow the labels used by jumps
                     60:    from nested functions.  */
                     61: /* Pre-record the next or previous real insn for each label?
                     62:    No, this pass is very fast anyway.  */
                     63: /* Condense consecutive labels?
                     64:    This would make life analysis faster, maybe.  */
                     65: /* Optimize jump y; x: ... y: jumpif... x?
                     66:    Don't know if it is worth bothering with.  */
                     67: /* Optimize two cases of conditional jump to conditional jump?
                     68:    This can never delete any instruction or make anything dead,
                     69:    or even change what is live at any point.
                     70:    So perhaps let combiner do it.  */
                     71: 
                     72: /* Vector indexed by uid.
                     73:    For each CODE_LABEL, index by its uid to get first unconditional jump
                     74:    that jumps to the label.
                     75:    For each JUMP_INSN, index by its uid to get the next unconditional jump
                     76:    that jumps to the same label.
                     77:    Element 0 is the start of a chain of all return insns.
                     78:    (It is safe to use element 0 because insn uid 0 is not used.  */
                     79: 
                     80: rtx *jump_chain;
                     81: 
                     82: rtx delete_insn ();
                     83: void redirect_jump ();
                     84: void invert_jump ();
                     85: rtx next_real_insn ();
                     86: rtx prev_real_insn ();
                     87: rtx next_label ();
                     88: 
                     89: static void mark_jump_label ();
                     90: static void delete_jump ();
                     91: static void invert_exp ();
                     92: static void redirect_exp ();
                     93: static rtx follow_jumps ();
                     94: static int tension_vector_labels ();
                     95: static void find_cross_jump ();
                     96: static void do_cross_jump ();
                     97: static enum rtx_code reverse_condition ();
                     98: static int jump_back_p ();
                     99: 
                    100: /* Delete no-op jumps and optimize jumps to jumps
                    101:    and jumps around jumps.
                    102:    Delete unused labels and unreachable code.
                    103:    If CROSS_JUMP is nonzero, detect matching code
                    104:    before a jump and its destination and unify them.
                    105:    If NOOP_MOVES is nonzero, also delete no-op move insns
                    106:    and perform machine-specific peephole optimizations
                    107:    (but flag_no_peephole inhibits the latter).
                    108: 
                    109:    If `optimize' is zero, don't change any code,
                    110:    just determine whether control drops off the end of the function.
                    111:    This case occurs when we have -W and not -O.
                    112:    It works because `delete_insn' checks the value of `optimize'
                    113:    and refrains from actually deleting when that is 0.  */
                    114: 
                    115: void
                    116: jump_optimize (f, cross_jump, noop_moves)
                    117:      rtx f;
                    118: {
                    119:   register rtx insn;
                    120:   int changed;
                    121:   int first = 1;
                    122:   int max_uid = 0;
                    123:   rtx last_insn;
                    124: 
                    125:   /* Initialize LABEL_NUSES and JUMP_LABEL fields.  */
                    126: 
                    127:   for (insn = f; insn; insn = NEXT_INSN (insn))
                    128:     {
                    129:       if (GET_CODE (insn) == CODE_LABEL)
                    130:        LABEL_NUSES (insn) = 0;
                    131:       if (GET_CODE (insn) == JUMP_INSN)
                    132:        JUMP_LABEL (insn) = 0;
                    133:       if (INSN_UID (insn) > max_uid)
                    134:        max_uid = INSN_UID (insn);
                    135:     }
                    136: 
                    137:   max_uid++;
                    138: 
                    139:   jump_chain = (rtx *) alloca (max_uid * sizeof (rtx));
                    140:   bzero (jump_chain, max_uid * sizeof (rtx));
                    141: 
                    142:   /* Delete insns following barriers, up to next label.  */
                    143: 
                    144:   for (insn = f; insn;)
                    145:     {
                    146:       if (GET_CODE (insn) == BARRIER)
                    147:        {
                    148:          insn = NEXT_INSN (insn);
                    149:          while (insn != 0 && GET_CODE (insn) != CODE_LABEL)
                    150:            {
                    151:              if (GET_CODE (insn) == NOTE
                    152:                  && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
                    153:                insn = NEXT_INSN (insn);
                    154:              else
                    155:                insn = delete_insn (insn);
                    156:            }
                    157:          /* INSN is now the code_label.  */
                    158:        }
                    159:       else
                    160:        insn = NEXT_INSN (insn);
                    161:     }
                    162: 
                    163:   /* Mark the label each jump jumps to.
                    164:      Combine consecutive labels, and count uses of labels.
                    165: 
                    166:      For each label, make a chain (using `jump_chain')
                    167:      of all the *unconditional* jumps that jump to it;
                    168:      also make a chain of all returns.  */
                    169: 
                    170:   for (insn = f; insn; insn = NEXT_INSN (insn))
                    171:     if (GET_CODE (insn) == JUMP_INSN && !insn->volatil)
                    172:       {
                    173:        mark_jump_label (PATTERN (insn), insn, cross_jump);
                    174:        if (JUMP_LABEL (insn) != 0 && simplejump_p (insn))
                    175:          {
                    176:            jump_chain[INSN_UID (insn)]
                    177:              = jump_chain[INSN_UID (JUMP_LABEL (insn))];
                    178:            jump_chain[INSN_UID (JUMP_LABEL (insn))] = insn;
                    179:          }
                    180:        if (GET_CODE (PATTERN (insn)) == RETURN)
                    181:          {
                    182:            jump_chain[INSN_UID (insn)] = jump_chain[0];
                    183:            jump_chain[0] = insn;
                    184:          }
                    185:       }
                    186: 
                    187:   /* Delete all labels already not referenced.
                    188:      Also find the last insn.  */
                    189: 
                    190:   last_insn = 0;
                    191:   for (insn = f; insn; )
                    192:     {
                    193:       if (GET_CODE (insn) == CODE_LABEL && LABEL_NUSES (insn) == 0)
                    194:        insn = delete_insn (insn);
                    195:       else
                    196:        {
                    197:          last_insn = insn;
                    198:          insn = NEXT_INSN (insn);
                    199:        }
                    200:     }
                    201: 
                    202:   if (!optimize)
                    203:     {
                    204:       /* See if there is still a NOTE_INSN_FUNCTION_END in this function.
                    205:         If so record that this function can drop off the end.  */
                    206: 
                    207:       insn = last_insn;
                    208:       while (insn && (GET_CODE (insn) == CODE_LABEL
                    209:                      /* If machine uses explicit RETURN insns, no epilogue,
                    210:                         then this note precedes the drop-through RETURN.  */
                    211:                      || (GET_CODE (insn) == JUMP_INSN
                    212:                          && GET_CODE (PATTERN (insn)) == RETURN)))
                    213:        insn = PREV_INSN (insn);
                    214: 
                    215:       if (GET_CODE (insn) == NOTE
                    216:          && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END
                    217:          && ! insn->volatil)
                    218:        {
                    219:          extern int current_function_returns_null;
                    220:          current_function_returns_null = 1;
                    221:        }
                    222:       /* Zero the "deleted" flag of all the "deleted" insns.  */
                    223:       for (insn = f; insn; insn = NEXT_INSN (insn))
                    224:        insn->volatil = 0;
                    225:       return;
                    226:     }
                    227: 
                    228: #if 0
                    229: #ifdef EXIT_IGNORE_STACK
                    230:   /* If the last insn just adjusts the stack,
                    231:      we can delete it on certain machines,
                    232:      provided we have a frame pointer.  */
                    233: 
                    234:   if (frame_pointer_needed && EXIT_IGNORE_STACK)
                    235:     {
                    236:       insn = last_insn;
                    237:       while (insn)
                    238:        {
                    239:          rtx prev;
                    240:          /* Back up to a real insn.  */
                    241:          if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN
                    242:              && GET_CODE (insn) != CALL_INSN)
                    243:            insn = prev_real_insn (insn);
                    244:          if (insn == 0)
                    245:            break;
                    246:          prev = PREV_INSN (insn);
                    247:          /* If this insn is a stack adjust, delete it.  */
                    248:          if (GET_CODE (insn) == INSN
                    249:              && GET_CODE (PATTERN (insn)) == SET
                    250:              && GET_CODE (SET_DEST (PATTERN (insn))) == REG
                    251:              && REGNO (SET_DEST (PATTERN (insn))) == STACK_POINTER_REGNUM)
                    252:            {
                    253:              delete_insn (insn);
                    254:              if (insn == last_insn)
                    255:                last_insn = prev;
                    256:            }
                    257:          else
                    258:            /* If we find an insn that isn't a stack adjust, stop deleting.  */
                    259:            break;
                    260:          /* Back up to insn before the deleted one and try to delete more.  */
                    261:          insn = prev;
                    262:        }
                    263:     }
                    264: #endif
                    265: #endif
                    266: 
                    267:   if (noop_moves)
                    268:     for (insn = f; insn; )
                    269:       {
                    270:        register rtx next = NEXT_INSN (insn);
                    271: 
                    272:        if (GET_CODE (insn) == INSN)
                    273:          {
                    274:            register rtx body = PATTERN (insn);
                    275: 
                    276:            /* Delete insns that existed just to advise flow-analysis.  */
                    277: 
                    278:            if (GET_CODE (body) == USE
                    279:                || GET_CODE (body) == CLOBBER)
                    280:              delete_insn (insn);
                    281: 
                    282:            /* Detect and delete no-op move instructions
                    283:               resulting from not allocating a parameter in a register.  */
                    284: 
                    285:            else if (GET_CODE (body) == SET
                    286:                     && (SET_DEST (body) == SET_SRC (body)
                    287:                         || (GET_CODE (SET_DEST (body)) == MEM
                    288:                             && GET_CODE (SET_SRC (body)) == MEM
                    289:                             && rtx_equal_p (SET_SRC (body), SET_DEST (body))))
                    290:                     && ! SET_DEST (body)->volatil
                    291:                     && ! SET_SRC (body)->volatil)
                    292:              delete_insn (insn);
                    293: 
                    294:            /* Detect and ignore no-op move instructions
                    295:               resulting from smart or fortuitous register allocation.  */
                    296: 
                    297:            else if (GET_CODE (body) == SET)
                    298:              {
                    299:                int sreg = true_regnum (SET_SRC (body));
                    300:                int dreg = true_regnum (SET_DEST (body));
                    301: 
                    302:                if (sreg == dreg && sreg >= 0)
                    303:                  delete_insn (insn);
                    304:                else if (sreg >= 0 && dreg >= 0)
                    305:                  {
                    306:                    rtx tem = find_equiv_reg (0, insn, 0,
                    307:                                              sreg, 0, dreg);
                    308:                    if (tem != 0
                    309:                        && GET_MODE (tem) == GET_MODE (SET_DEST (body)))
                    310:                      delete_insn (insn);
                    311:                  }
                    312:              }
                    313:          }
                    314:       insn = next;
                    315:     }
                    316: 
                    317:   /* Now iterate optimizing jumps until nothing changes over one pass.  */
                    318:   changed = 1;
                    319:   while (changed)
                    320:     {
                    321:       register rtx next;
                    322:       changed = 0;
                    323: 
                    324:       for (insn = f; insn; insn = next)
                    325:        {
                    326:          next = NEXT_INSN (insn);
                    327: 
                    328:          /* On the first iteration, if this is the last jump pass
                    329:             (just before final), do the special peephole optimizations.  */
                    330: 
                    331:          if (noop_moves && first && !flag_no_peephole)
                    332:            if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
                    333:              peephole (insn);
                    334: 
                    335:          /* Tension the labels in dispatch tables.  */
                    336: 
                    337:          if (GET_CODE (insn) == JUMP_INSN)
                    338:            {
                    339:              if (GET_CODE (PATTERN (insn)) == ADDR_VEC)
                    340:                changed |= tension_vector_labels (PATTERN (insn), 0);
                    341:              if (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
                    342:                changed |= tension_vector_labels (PATTERN (insn), 1);
                    343:            }
                    344: 
                    345:          if (GET_CODE (insn) == JUMP_INSN && JUMP_LABEL (insn))
                    346:            {
                    347:              register rtx reallabelprev = prev_real_insn (JUMP_LABEL (insn));
                    348: 
                    349:              /* Delete insns that adjust stack pointer before a return,
                    350:                 if this is the last jump-optimization before final
                    351:                 and we need to have a frame pointer.  */
                    352: #if 0
                    353: #ifdef EXIT_IGNORE_STACK
                    354:              if (noop_moves && frame_pointer_needed && EXIT_IGNORE_STACK
                    355:                  && NEXT_INSN (JUMP_LABEL (insn)) == 0)
                    356:                {
                    357:                  rtx prev = prev_real_insn (insn);
                    358:                  if (prev != 0
                    359:                      && GET_CODE (prev) == INSN
                    360:                      && GET_CODE (PATTERN (prev)) == SET
                    361:                      && GET_CODE (SET_DEST (PATTERN (prev))) == REG
                    362:                      && REGNO (SET_DEST (PATTERN (prev))) == STACK_POINTER_REGNUM)
                    363:                    {
                    364:                      delete_insn (prev);
                    365:                      changed = 1;
                    366:                    }
                    367:                }
                    368: #endif
                    369: #endif
                    370: 
                    371:              /* Detect jump to following insn.  */
                    372:              if (reallabelprev == insn && condjump_p (insn))
                    373:                {
                    374:                  reallabelprev = PREV_INSN (insn);
                    375:                  delete_jump (insn);
                    376:                  changed = 1;
                    377:                }
                    378:              /* Detect jumping over an unconditional jump.  */
                    379:              else if (reallabelprev != 0
                    380:                       && GET_CODE (reallabelprev) == JUMP_INSN
                    381:                       && prev_real_insn (reallabelprev) == insn
                    382:                       && no_labels_between_p (insn, reallabelprev)
                    383:                       && simplejump_p (reallabelprev)
                    384:                       /* Ignore this if INSN is a hairy kind of jump,
                    385:                          since they may not be invertible.
                    386:                          This is conservative; could instead construct
                    387:                          the inverted insn and try recognizing it.  */
                    388:                       && condjump_p (insn))
                    389:                {
                    390:                  /* Delete the original unconditional jump (and barrier).  */
                    391:                  /* But don't lEST (PATTERN (insn))) == STACK_POINTER_REGNUM)
                    392:            {
                    393:              delete_insn (insn);
                    394:              if (insn == last_insn)
                    395:                last_insn = prev;
                    396:            }
                    397:          else
                    398:            /* If we find an insn that isn't a stack adjust, stop deleting.  */
                    399:            break;
                    400:          /* Back up to insn before the deleted one and try to delete more.  */
                    401:          insn = prev;
                    402:        }
                    403:     }
                    404: #endif
                    405: #endif
                    406: 
                    407:   if (noop_moves)
                    408:     for (insn = f; insn; )
                    409:       {
                    410:        register rtx next = NEXT_INSN (insn);
                    411: 
                    412:        if (GET_CODE (insn) == INSN)
                    413:          {
                    414:            register rtx body = PATTERN (insn);
                    415: 
                    416:            /* Delete insns that existed just to advise flow-analysis.  */
                    417: 
                    418:            if (GET_CODE (body) == USE
                    419:                || GET_CODE (body) == CLOBBER)
                    420:              delete_insn (insn);
                    421: 
                    422:            /* Detect and delete no-op move instructions
                    423:               resulting from not allocating a parameter in a register.  */
                    424: 
                    425:            else if (GET_CODE (body) == SET
                    426:                     && (SET_DEST (body) == SET_SRC (body)
                    427:                         || (GET_CODE (SET_DEST (body)) == MEM
                    428:                             && GET_CODE (SET_SRC (body)) == MEM
                    429:                             && rtx_equal_p (SET_SRC (body), SET_DEST (body))))
                    430:                     && ! SET_DEST (body)->volatil
                    431:                     && ! SET_SRC (body)->volatil)
                    432:              delete_insn (insn);
                    433: 
                    434:            /* Detect and ignore no-op move instructions
                    435:               resulting from smart or fortuitous register allocation.  */
                    436: 
                    437:            else if (GET_CODE (body) == SET)
                    438:              {
                    439:                int sreg = true_regnum (SET_SRC (body));
                    440:                int dreg = true_regnum (SET_DEST (body));
                    441: 
                    442:                if (sreg == dreg && sreg >= 0)
                    443:                  delete_insn (insn);
                    444:                else if (sreg >= 0 && dreg >= 0)
                    445:                  {
                    446:                    rtx tem = find_equiv_reg (0, insn, 0,
                    447:                                              sreg, 0, dreg);
                    448:                    if (tem != 0
                    449:                        && GET_MODE (tem) == GET_MODE (SET_DEST (body)))
                    450:                      delete_insn (insn);
                    451:                  }
                    452:              }
                    453:          }
                    454:       insn = next;
                    455:     }
                    456: 
                    457:   /* Now iterate optimizing jumps until nothing changes over one pass.  */
                    458:   changed = 1;
                    459:   while (changed)
                    460:     {
                    461:       register rtx next;
                    462:       changed = 0;
                    463: 
                    464:       for (insn = f; insn; insn = next)
                    465:        {
                    466:          next = NEXT_INSN (insn);
                    467: 
                    468:          /* On the first iteration, if this is the last jump pass
                    469:             (just before final), do the special peephole optimizations.  */
                    470: 
                    471:          if (noop_moves && first && !flag_no_peephole)
                    472:            if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
                    473:              peephole (insn);
                    474: 
                    475:          /* Tension the labels in dispatch tables.  */
                    476: 
                    477:          if (GET_CODE (insn) == JUMP_INSN)
                    478:            {
                    479:              if (GET_CODE (PATTERN (insn)) == ADDR_VEC)
                    480:                changed |= tension_vector_labels (PATTERN (insn), 0);
                    481:              if (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
                    482:                changed |= tension_vector_labels (PATTERN (insn), 1);
                    483:            }
                    484: 
                    485:          if (GET_CODE (insn) == JUMP_INSN && JUMP_LABEL (insn))
                    486:            {
                    487:              register rtx reallabelprev = prev_real_insn (JUMP_LABEL (insn));
                    488: 
                    489:              /* Delete insns that adjust stack pointer before a return,
                    490:                 if this is the last jump-optimization before final
                    491:                 and we need to have a frame pointer.  */
                    492: #if 0
                    493: #ifdef EXIT_IGNORE_STACK
                    494:              if (noop_moves && frame_pointer_needed && EXIT_IGNORE_STACK
                    495:                  && NEXT_INSN (JUMP_LABEL (insn)) == 0)
                    496:                {
                    497:                  rtx prev = prev_real_insn (insn);
                    498:                  if (prev != 0
                    499:                      && GET_CODE (prev) == INSN
                    500:                      && GET_CODE (PATTERN (prev)) == SET
                    501:                      && GET_CODE (SET_DEST (PATTERN (prev))) == REG
                    502:                      && REGNO (SET_DEST (PATTERN (prev))) == STACK_POINTER_REGNUM)
                    503:                    {
                    504:                      delete_insn (prev);
                    505:                      changed = 1;
                    506:                    }
                    507:                }
                    508: #endif
                    509: #endif
                    510: 
                    511:              /* Detect jump to following insn.  */
                    512:              if (reallabelprev == insn && condjump_p (insn))
                    513:                {
                    514:                  reallabelprev = PREV_INSN (insn);
                    515:                  delete_jump (insn);
                    516:                  changed = 1;
                    517:                }
                    518:              /* Detect jumping over an unconditional jump.  */
                    519:              else if (reallabelprev != 0
                    520:                       && GET_CODE (reallabelprev) == JUMP_INSN
                    521:                       && prev_real_insn (reallabelprev) == insn
                    522:                       && no_labels_between_p (insn, reallabelprev)
                    523:                       && simplejump_p (reallabelprev)
                    524:                       /* Ignore this if INSN is a hairy kind of jump,
                    525:                          since they may not be invertible.
                    526:                          This is conservative; could instead construct
                    527:                          the inverted insn and try recognizing it.  */
                    528:                       && condjump_p (insn))
                    529:                {
                    530:                  /* Delete the original unconditional jump (and barrier).  */
                    531:                  /* But don't l/* If cannot cross jump to code before the label,
                    532:                         see if we can cross jump to another jump to
                    533:                         the same label.  */
                    534:                      /* Try each other jump to this label.  */
                    535:                      if (INSN_UID (JUMP_LABEL (insn)) < max_uid)
                    536:                        for (target = jump_chain[INSN_UID (JUMP_LABEL (insn))];
                    537:                             target != 0 && newjpos == 0;
                    538:                             target = jump_chain[INSN_UID (target)])
                    539:                          if (target != insn
                    540:                              && JUMP_LABEL (target) == JUMP_LABEL (insn)
                    541:                              /* Ignore TARGET if it's deleted.  */
                    542:                              && ! target->volatil)
                    543:                            find_cross_jump (insn, target, 2,
                    544:                                             &newjpos, &newlpos);
                    545: 
                    546:                      if (newjpos != 0)
                    547:                        {
                    548:                          do_cross_jump (insn, newjpos, newlpos);
                    549:                          changed = 1;
                    550:                          next = insn;
                    551:                        }
                    552:                    }
                    553:                }
                    554:            }
                    555:          else if (GET_CODE (insn) == JUMP_INSN
                    556:                   && GET_CODE (PATTERN (insn)) == RETURN)
                    557:            {
                    558:              /* Return insns all "jump to the same place"
                    559:                 so we can cross-jump between any two of them.  */
                    560:              if (cross_jump)
                    561:                {
                    562:                  rtx newjpos, newlpos, target;
                    563: 
                    564:                  newjpos = 0;
                    565: 
                    566:                  /* If cannot cross jump to code before the label,
                    567:                     see if we can cross jump to another jump to
                    568:                     the same label.  */
                    569:                  /* Try each other jump to this label.  */
                    570:                  for (target = jump_chain[0];
                    571:                       target != 0 && newjpos == 0;
                    572:                       target = jump_chain[INSN_UID (target)])
                    573:                    if (target != insn
                    574:                        && ! target->volatil
                    575:                        && GET_CODE (PATTERN (target)) == RETURN)
                    576:                      find_cross_jump (insn, target, 2,
                    577:                                       &newjpos, &newlpos);
                    578: 
                    579:                  if (newjpos != 0)
                    580:                    {
                    581:                      do_cross_jump (insn, newjpos, newlpos);
                    582:                      changed = 1;
                    583:                      next = insn;
                    584:                    }
                    585:                }
                    586:            }
                    587: 
                    588:        }
                    589: 
                    590:       first = 0;
                    591:     }
                    592: 
                    593:   /* See if there is still a NOTE_INSN_FUNCTION_END in this function.
                    594:      If so, delete it, and record that this function can drop off the end.  */
                    595: 
                    596:   insn = last_insn;
                    597:   while (insn && (GET_CODE (insn) == CODE_LABEL
                    598:                  /* If machine uses explicit RETURN insns, no epilogue,
                    599:                     then this note precedes the drop-through RETURN.  */
                    600:                  || (GET_CODE (insn) == JUMP_INSN
                    601:                      && GET_CODE (PATTERN (insn)) == RETURN)))
                    602:     insn = PREV_INSN (insn);
                    603:   if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END)
                    604:     {
                    605:       extern int current_function_returns_null;
                    606:       current_function_returns_null = 1;
                    607:       delete_insn (insn);
                    608:     }
                    609: }
                    610: 
                    611: /* Compare the instructions before insn E1 with those before E2.
                    612:    Assume E1 is a jump that jumps to label E2
                    613:    (that is not always true but it might as well be).
                    614:    Find the longest possible equivalent sequences
                    615:    and store the first insns of those sequences into *F1 and *F2.
                    616:    Store zero there if no equivalent preceding instructions are found.
                    617: 
                    618:    We give up if we find a label in stream 1.
                    619:    Actually we could transfer that label into stream 2.  */
                    620: 
                    621: static void
                    622: find_cross_jump (e1, e2, minimum, f1, f2)
                    623:      rtx e1, e2;
                    624:      int minimum;
                    625:      rtx *f1, *f2;
                    626: {
                    627:   register rtx i1 = e1, i2 = e2;
                    628:   register rtx p1, p2;
                    629: 
                    630:   rtx last1 = 0, last2 = 0;
                    631:   rtx afterlast1 = 0, afterlast2 = 0;
                    632: 
                    633:   *f1 = 0;
                    634:   *f2 = 0;
                    635: 
                    636:   while (1)
                    637:     {
                    638:       i1 = PREV_INSN (i1);
                    639:       while (i1 && GET_CODE (i1) == NOTE)
                    640:        i1 = PREV_INSN (i1);
                    641: 
                    642:       i2 = PREV_INSN (i2);
                    643:       while (i2 && (GET_CODE (i2) == NOTE || GET_CODE (i2) == CODE_LABEL))
                    644:        i2 = PREV_INSN (i2);
                    645: 
                    646:       if (i1 == 0)
                    647:        break;
                    648: 
                    649:       /* If we will get to this code by jumping, those jumps will be
                    650:         tensioned to go directly to the new label (before I2),
                    651:         so this cross-jumping won't cost extra.  So reduce the minimum.  */
                    652:       if (GET_CODE (i1) == CODE_LABEL)
                    653:        {
                    654:          --minimum;
                    655:          break;
                    656:        }
                    657: 
                    658:       if (i2 == 0 || GET_CODE (i1) != GET_CODE (i2))
                    659:        break;
                    660: 
                    661:       p1 = PATTERN (i1);
                    662:       p2 = PATTERN (i2);
                    663:        
                    664:       if (GET_CODE (p1) != GET_CODE (p2)
                    665:          || !rtx_renumbered_equal_p (p1, p2))
                    666:        {
                    667:          /* Insns fail to match; cross jumping is limited to the following
                    668:             insns.  */
                    669: 
                    670:          /* Don't allow the insn after a compare to be shared by cross-jumping
                    671:             unless the compare is also shared.
                    672:             Here, if either of these non-matching insns is a compare,
                    673:             exclude the following insn from possible cross-jumping.  */
                    674:          if ((GET_CODE (p1) == SET && SET_DEST (p1) == cc0_rtx)
                    675:              || (GET_CODE (p2) == SET && SET_DEST (p2) == cc0_rtx))
                    676:            last1 = afterlast1, last2 = afterlast2, ++minimum;
                    677: 
                    678:          /* If cross-jumping here will feed a jump-around-jump optimization,
                    679:             this jump won't cost extra, so reduce the minimum.  */
                    680:          if (GET_CODE (i1) == JUMP_INSN
                    681:              && JUMP_LABEL (i1)
                    682:              && prev_real_insn (JUMP_LABEL (i1)) == e1)
                    683:            --minimum;
                    684:          break;
                    685:        }
                    686: 
                    687:       if (GET_CODE (p1) != USE && GET_CODE (p1) != CLOBBER)
                    688:        {
                    689:          /* Ok, this insn is potentially includable in a cross-jump here.  */
                    690:          afterlast1 = last1, afterlast2 = last2;
                    691:          last1 = i1, last2 = i2, --minimum;
                    692:        }
                    693:     }
                    694: 
                    695:   if (minimum <= 0 && last1 != 0)
                    696:     *f1 = last1, *f2 = last2;
                    697: }
                    698: 
                    699: static void
                    700: do_cross_jump (insn, newjpos, newlpos)
                    701:      rtx insn, newjpos, newlpos;
                    702: {
                    703:   register rtx label;
                    704:   /* Find an existing label at this point
                    705:      or make a new one if there is none.  */
                    706:   label = PREV_INSN (newlpos);
                    707:   if (GET_CODE (label) != CODE_LABEL)
                    708:     {
                    709:       label = gen_label_rtx ();
                    710:       emit_label_after (label, PREV_INSN (newlpos));
                    711:       LABEL_NUSES (label) = 0;
                    712:     }
                    713:   /* Make the same jump insn jump to the new point.  */
                    714:   if (GET_CODE (PATTERN (insn)) == RETURN)
                    715:     {
                    716:       extern rtx gen_jump ();
                    717:       PATTERN (insn) = gen_jump (label);
                    718:       INSN_CODE (insn) = -1;
                    719:       JUMP_LABEL (insn) = label;
                    720:       LABEL_NUSES (label)++;
                    721:     }
                    722:   else
                    723:     redirect_jump (insn, label);
                    724:   /* Delete the matching insns before the jump.  */
                    725:   newjpos = PREV_INSN (newjpos);
                    726:   while (NEXT_INSN (newjpos) != insn)
                    727:     /* Don't delete line numbers.  */
                    728:     if (GET_CODE (NEXT_INSN (newjpos)) != NOTE)
                    729:       delete_insn (NEXT_INSN (newjpos));
                    730:     else
                    731:       newjpos = NEXT_INSN (newjpos);
                    732: }
                    733: 
                    734: /* Return 1 if INSN is a jump that jumps to right after TARGET
                    735:    only on the condition that TARGET itself would drop through.
                    736:    Assumes that TARGET is a conditional jump.  */
                    737: 
                    738: static int
                    739: jump_back_p (insn, target)
                    740:      rtx insn, target;
                    741: {
                    742:   rtx cinsn, ctarget;
                    743:   enum rtx_code codei, codet;
                    744: 
                    745:   if (simplejump_p (insn) || ! condjump_p (insn)
                    746:       || simplejump_p (target))
                    747:     return 0;
                    748:   if (target != prev_real_insn (JUMP_LABEL (insn)))
                    749:     return 0;
                    750: 
                    751:   cinsn = XEXP (SET_SRC (PATTERN (insn)), 0);
                    752:   ctarget = XEXP (SET_SRC (PATTERN (target)), 0);
                    753: 
                    754:   codei = GET_CODE (cinsn);
                    755:   codet = GET_CODE (ctarget);
                    756:   if (XEXP (SET_SRC (PATTERN (insn)), 1) == pc_rtx)
                    757:     codei = reverse_condition (codei);
                    758:   if (XEXP (SET_SRC (PATTERN (target)), 2) == pc_rtx)
                    759:     codet = reverse_condition (codet);
                    760:   return (codei == codet
                    761:          && rtx_renumbered_equal_p (XEXP (cinsn, 0), XEXP (ctarget, 0))
                    762:          && rtx_renumbered_equal_p (XEXP (cinsn, 1), XEXP (ctarget, 1)));
                    763: }
                    764: 
                    765: /* Given an rtx-code for a comparison, return the code
                    766:    for the negated comparison.  */
                    767: 
                    768: static enum rtx_code
                    769: reverse_condition (code)
                    770:      enum rtx_code code;
                    771: {
                    772:   switch (code)
                    773:     {
                    774:     case EQ:
                    775:       return NE;
                    776: 
                    777:     case NE:
                    778:       return EQ;
                    779: 
                    780:     case GT:
                    781:       return LE;
                    782: 
                    783:     case GE:
                    784:       return LT;
                    785: 
                    786:     case LT:
                    787:       return GE;
                    788: 
                    789:     case LE:
                    790:       return GT;
                    791: 
                    792:     case GTU:
                    793:       return LEU;
                    794: 
                    795:     case GEU:
                    796:       return LTU;
                    797: 
                    798:     case LTU:
                    799:       return GEU;
                    800: 
                    801:     case LEU:
                    802:       return GTU;
                    803: 
                    804:     default:
                    805:       abort ();
                    806:       return UNKNOWN;
                    807:     }
                    808: }
                    809: 
                    810: /* Return 1 if INSN is an unconditional jump and nothing else.  */
                    811: 
                    812: int
                    813: simplejump_p (insn)
                    814:      rtx insn;
                    815: {
                    816:   register rtx x = PATTERN (insn);
                    817:   if (GET_CODE (x) != SET)
                    818:     return 0;
                    819:   if (GET_CODE (SET_DEST (x)) != PC)
                    820:     return 0;
                    821:   if (GET_CODE (SET_SRC (x)) != LABEL_REF)
                    822:     return 0;
                    823:   return 1;
                    824: }
                    825: 
                    826: /* Return nonzero if INSN is a (possibly) conditional jump
                    827:    and nothing more.  */
                    828: 
                    829: static int
                    830: condjump_p (insn)
                    831:      rtx insn;
                    832: {
                    833:   register rtx x = PATTERN (insn);
                    834:   if (GET_CODE (x) != SET)
                    835:     return 0;
                    836:   if (GET_CODE (SET_DEST (x)) != PC)
                    837:     return 0;
                    838:   if (GET_CODE (SET_SRC (x)) == LABEL_REF)
                    839:     return 1;
                    840:   if (GET_CODE (SET_SRC (x)) != IF_THEN_ELSE)
                    841:     return 0;
                    842:   if (XEXP (SET_SRC (x), 2) == pc_rtx
                    843:       && GET_CODE (XEXP (SET_SRC (x), 1)) == LABEL_REF)
                    844:     return 1;
                    845:   if (XEXP (SET_SRC (x), 1) == pc_rtx
                    846:       && GET_CODE (XEXP (SET_SRC (x), 2)) == LABEL_REF)
                    847:     return 1;
                    848:   return 0;
                    849: }
                    850: 
                    851: /* Return 1 if in between BEG and END there is no CODE_LABEL insn.  */
                    852: 
                    853: int
                    854: no_labels_between_p (beg, end)
                    855:      rtx beg, end;
                    856: {
                    857:   register rtx p;
                    858:   for (p = beg; p != end; p = NEXT_INSN (p))
                    859:     if (GET_CODE (p) == CODE_LABEL)
                    860:       return 0;
                    861:   return 1;
                    862: }
                    863: 
                    864: /* Return the last INSN, CALL_INSN or JUMP_INSN before LABEL;
                    865:    or 0, if there is none.  */
                    866: 
                    867: rtx
                    868: prev_real_insn (label)
                    869:      rtx label;
                    870: {
                    871:   register rtx insn = PREV_INSN (label);
                    872:   register RTX_CODE code;
                    873: 
                    874:   while (1)
                    875:     {
                    876:       if (insn == 0)
                    877:        return 0;
                    878:       code = GET_CODE (insn);
                    879:       if (code == INSN || code == CALL_INSN || code == JUMP_INSN)
                    880:        break;
                    881:       insn = PREV_INSN (insn);
                    882:     }
                    883: 
                    884:   return insn;
                    885: }
                    886: 
                    887: /* Return the next INSN, CALL_INSN or JUMP_INSN after LABEL;
                    888:    or 0, if there is none.  */
                    889: 
                    890: rtx
                    891: next_real_insn (label)
                    892:      rtx label;
                    893: {
                    894:   register rtx insn = NEXT_INSN (label);
                    895:   register RTX_CODE code;
                    896: 
                    897:   while (1)
                    898:     {
                    899:       if (insn == 0)
                    900:        return insn;
                    901:       code = GET_CODE (insn);
                    902:       if (code == INSN || code == CALL_INSN || code == JUMP_INSN)
                    903:        break;
                    904:       insn = NEXT_INSN (insn);
                    905:     }
                    906: 
                    907:   return insn;
                    908: }
                    909: 
                    910: /* Return the next CODE_LABEL after the insn INSN, or 0 if there is none.  */
                    911: 
                    912: rtx
                    913: next_label (insn)
                    914:      rtx insn;
                    915: {
                    916:   do insn = NEXT_INSN (insn);
                    917:   while (insn != 0 && GET_CODE (insn) != CODE_LABEL);
                    918:   return insn;
                    919: }
                    920: 
                    921: /* Follow any unconditional jump at LABEL;
                    922:    return the ultimate label reached by any such chain of jumps.
                    923:    If LABEL is not followed by a jump, return LABEL.  */
                    924: 
                    925: static rtx
                    926: follow_jumps (label)
                    927:      rtx label;
                    928: {
                    929:   register rtx insn;
                    930:   register rtx next;
                    931:   register rtx value = label;
                    932:   register int depth;
                    933: 
                    934:   for (depth = 0;
                    935:        (depth < 10
                    936:        && (insn = next_real_insn (value)) != 0
                    937:        && GET_CODE (insn) == JUMP_INSN
                    938:        && JUMP_LABEL (insn) != 0
                    939:        && (next = NEXT_INSN (insn))
                    940:        && GET_CODE (next) == BARRIER);
                    941:        depth++)
                    942:     {
                    943:       /* If we have found a cycle, make the insn jump to itself.  */
                    944:       if (JUMP_LABEL (insn) == label)
                    945:        break;
                    946:       value = JUMP_LABEL (insn);
                    947:     }
                    948:   return value;
                    949: }
                    950: 
                    951: /* Assuming that field IDX of X is a vector of label_refs,
                    952:    replace each of them by the ultimate label reached by it.
                    953:    Return nonzero if a change is made.  */
                    954: 
                    955: static int
                    956: tension_vector_labels (x, idx)
                    957:      register rtx x;
                    958:      register int idx;
                    959: {
                    960:   int changed = 0;
                    961:   register int i;
                    962:   for (i = XVECLEN (x, idx) - 1; i >= 0; i--)
                    963:     {
                    964:       register rtx olabel = XEXP (XVECEXP (x, idx, i), 0);
                    965:       register rtx nlabel = follow_jumps (olabel);
                    966:       if (nlabel != olabel)
                    967:        {
                    968:          XEXP (XVECEXP (x, idx, i), 0) = nlabel;
                    969:          ++LABEL_NUSES (nlabel);
                    970:          if (--LABEL_NUSES (olabel) == 0)
                    971:            delete_insn (olabel);
                    972:          changed = 1;
                    973:        }
                    974:     }
                    975:   return changed;
                    976: }
                    977: 
                    978: /* Find all CODE_LABELs referred to in X,
                    979:    and increment their use counts.
                    980:    Also store one of them in JUMP_LABEL (INSN) if INSN is nonzero.
                    981:    Also, when there are consecutive labels,
                    982:    canonicalize on the last of them.
                    983: 
                    984:    Note that two labels separated by a loop-beginning note
                    985:    must be kept distinct if we have not yet done loop-optimization,
                    986:    because the gap between them is where loop-optimize
                    987:    will want to move invariant code to.  CROSS_JUMP tells us
                    988:    that loop-optimization is done with.  */
                    989: 
                    990: static void
                    991: mark_jump_label (x, insn, cross_jump)
                    992:      register rtx x;
                    993:      rtx insn;
                    994:      int cross_jump;
                    995: {
                    996:   register RTX_CODE code = GET_CODE (x);
                    997:   register int i;
                    998:   register char *fmt;
                    999: 
                   1000:   if (code == LABEL_REF)
                   1001:     {
                   1002:       register rtx label = XEXP (x, 0);
                   1003:       register rtx next;
                   1004:       if (GET_CODE (label) != CODE_LABEL)
                   1005:        return;
                   1006:       /* If there are other labels following this one,
                   1007:         replace it with the last of the consecutive labels.  */
                   1008:       for (next = NEXT_INSN (label); next; next = NEXT_INSN (next))
                   1009:        {
                   1010:          if (GET_CODE (next) == CODE_LABEL)
                   1011:            label = next;
                   1012:          else if (GET_CODE (next) != NOTE
                   1013:                   || NOTE_LINE_NUMBER (next) == NOTE_INSN_LOOP_BEG
                   1014:                   || NOTE_LINE_NUMBER (next) == NOTE_INSN_FUNCTION_END)
                   1015:            break;
                   1016:        }
                   1017:       XEXP (x, 0) = label;
                   1018:       ++LABEL_NUSES (label);
                   1019:       if (insn)
                   1020:        JUMP_LABEL (insn) = label;
                   1021:       return;
                   1022:     }
                   1023: 
                   1024:   /* Do walk the labels in a vector,
                   1025:      but don't set its JUMP_LABEL.  */
                   1026:   if (code == ADDR_VEC || code == ADDR_DIFF_VEC)
                   1027:     insn = 0;
                   1028: 
                   1029:   fmt = GET_RTX_FORMAT (code);
                   1030:   for (i = GET_RTX_LENGTH (code); i >= 0; i--)
                   1031:     {
                   1032:       if (fmt[i] == 'e')
                   1033:        mark_jump_label (XEXP (x, i), insn, cross_jump);
                   1034:       else if (fmt[i] == 'E')
                   1035:        {
                   1036:          register int j;
                   1037:          for (j = 0; j < XVECLEN (x, i); j++)
                   1038:            mark_jump_label (XVECEXP (x, i, j), insn, cross_jump);
                   1039:        }
                   1040:     }
                   1041: }
                   1042: 
                   1043: /* If all INSN does is set the pc, delete it,
                   1044:    and delete the insn that set the condition codes for it
                   1045:    if that's what the previous thing was.  */
                   1046: 
                   1047: static void
                   1048: delete_jump (insn)
                   1049:      rtx insn;
                   1050: {
                   1051:   register rtx x = PATTERN (insn);
                   1052:   register rtx prev;
                   1053: 
                   1054:   if (GET_CODE (x) == SET
                   1055:       && GET_CODE (SET_DEST (x)) == PC)
                   1056:     {
                   1057:       prev = PREV_INSN (insn);
                   1058:       delete_insn (insn);
                   1059:       /* We assume that at this stage
                   1060:         CC's are always set explicitly
                   1061:         and always immediately before the jump that
                   1062:         will use them.  So if the previous insn
                   1063:         exists to set the CC's, delete it.  */
                   1064:       while (prev && GET_CODE (prev) == NOTE)
                   1065:        prev = PREV_INSN (prev);
                   1066:       if (prev && GET_CODE (prev) == INSN
                   1067:          && GET_CODE (PATTERN (prev)) == SET
                   1068:          && SET_DEST (PATTERN (prev)) == cc0_rtx)
                   1069:        delete_insn (prev);
                   1070:     }
                   1071: }
                   1072: 
                   1073: /* Delete insn INSN from the chain of insns and update label ref counts.
                   1074:    May delete some following insns as a consequence; may even delete
                   1075:    a label elsewhere and insns that follow it.
                   1076: 
                   1077:    Returns the first insn after INSN that was not deleted.  */
                   1078: 
                   1079: rtx
                   1080: delete_insn (insn)
                   1081:      register rtx insn;
                   1082: {
                   1083:   register rtx next = NEXT_INSN (insn);
                   1084:   register rtx prev = PREV_INSN (insn);
                   1085: 
                   1086:   if (insn->volatil)
                   1087:     {
                   1088:       /* This insn is already deleted => return first following nondeleted.  */
                   1089:       while (next && next->volatil)
                   1090:        next = NEXT_INSN (next);
                   1091:       return next;
                   1092:     }
                   1093: 
                   1094:   /* Mark this insn as deleted.  */
                   1095: 
                   1096:   insn->volatil = 1;
                   1097: 
                   1098:   /* If instruction is followed by a barrier,
                   1099:      delete the barrier too.  */
                   1100: 
                   1101:   if (next != 0 && GET_CODE (next) == BARRIER)
                   1102:     {
                   1103:       next->volatil = 1;
                   1104:       next = NEXT_INSN (next);
                   1105:     }
                   1106: 
                   1107:   /* Patch out INSN (and the barrier if any) */
                   1108: 
                   1109:   if (optimize)
                   1110:     {
                   1111:       if (prev)
                   1112:        NEXT_INSN (prev) = next;
                   1113: 
                   1114:       if (next)
                   1115:        PREV_INSN (next)= prev;
                   1116:     }
                   1117: 
                   1118:   /* If deleting a jump, decrement the count of the label,
                   1119:      and delete the label if it is now unused.  */
                   1120: 
                   1121:   if (GET_CODE (insn) == JUMP_INSN && JUMP_LABEL (insn))
                   1122:     if (--LABEL_NUSES (JUMP_LABEL (insn)) == 0)
                   1123:       {
                   1124:        /* This can delete NEXT or PREV,
                   1125:           either directly if NEXT is JUMP_LABEL (INSN),
                   1126:           or indirectly through more levels of jumps.  */
                   1127:        delete_insn (JUMP_LABEL (insn));
                   1128:        /* I feel a little doubtful about this loop,
                   1129:           but I see no clean and sure alternative way
                   1130:           to find the first insn after INSN that is not now deleted.
                   1131:           I hope this works.  */
                   1132:        while (next && next->volatil)
                   1133:          next = NEXT_INSN (next);
                   1134:        return next;
                   1135:       }
                   1136: 
                   1137:   while (prev && GET_CODE (prev) == NOTE)
                   1138:     prev = PREV_INSN (prev);
                   1139: 
                   1140:   /* If INSN was a label, delete insns following it if now unreachable.  */
                   1141: 
                   1142:   if (GET_CODE (insn) == CODE_LABEL && prev
                   1143:       && GET_CODE (prev) == BARRIER)
                   1144:     {
                   1145:       register RTX_CODE code;
                   1146:       while (next != 0
                   1147:             && ((code = GET_CODE (next)) == INSN
                   1148:                 || code == JUMP_INSN || code == CALL_INSN
                   1149:                 || code == NOTE))
                   1150:        {
                   1151:          if (code == NOTE
                   1152:              && NOTE_LINE_NUMBER (next) != NOTE_INSN_FUNCTION_END)
                   1153:            next = NEXT_INSN (next);
                   1154:          else
                   1155:            /* Note: if this deletes a jump, it can cause more
                   1156:               deletion of unreachable code, after a different label.
                   1157:               As long as the value from this recursive call is correct,
                   1158:               this invocation functions correctly.  */
                   1159:            next = delete_insn (next);
                   1160:        }
                   1161:     }
                   1162: 
                   1163:   return next;
                   1164: }
                   1165: 
                   1166: /* Advance from INSN till reaching something not deleted
                   1167:    then return that.  May return INSN itself.  */
                   1168: 
                   1169: rtx
                   1170: next_nondeleted_insn (insn)
                   1171:      rtx insn;
                   1172: {
                   1173:   while (insn->volatil)
                   1174:     insn = NEXT_INSN (insn);
                   1175:   return insn;
                   1176: }
                   1177: 
                   1178: /* Invert the condition of the jump JUMP, and make it jump
                   1179:    to label NLABEL instead of where it jumps now.  */
                   1180: 
                   1181: void
                   1182: invert_jump (jump, nlabel)
                   1183:      rtx jump, nlabel;
                   1184: {
                   1185:   register rtx olabel = JUMP_LABEL (jump);
                   1186:   invert_exp (PATTERN (jump), olabel, nlabel);
                   1187:   JUMP_LABEL (jump) = nlabel;
                   1188:   ++LABEL_NUSES (nlabel);
                   1189:   INSN_CODE (jump) = -1;
                   1190: 
                   1191:   if (--LABEL_NUSES (olabel) == 0)
                   1192:     delete_insn (olabel);
                   1193: }
                   1194: 
                   1195: /* Invert the jump condition of rtx X,
                   1196:    and replace OLABEL with NLABEL throughout.  */
                   1197: 
                   1198: static void
                   1199: invert_exp (x, olabel, nlabel)
                   1200:      rtx x;
                   1201:      rtx olabel, nlabel;
                   1202: {
                   1203:   register RTX_CODE code = GET_CODE (x);
                   1204:   register int i;
                   1205:   register char *fmt;
                   1206: 
                   1207:   if (code == IF_THEN_ELSE)
                   1208:     {
                   1209:       /* Inverting the jump condition of an IF_THEN_ELSE
                   1210:         means exchanging the THEN-part with the ELSE-part.  */
                   1211:       register rtx tem = XEXP (x, 1);
                   1212:       XEXP (x, 1) = XEXP (x, 2);
                   1213:       XEXP (x, 2) = tem;
                   1214:     }
                   1215: 
                   1216:   if (code == LABEL_REF)
                   1217:     {
                   1218:       if (XEXP (x, 0) == olabel)
                   1219:        XEXP (x, 0) = nlabel;
                   1220:       return;
                   1221:     }
                   1222: 
                   1223:   fmt = GET_RTX_FORMAT (code);
                   1224:   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
                   1225:     {
                   1226:       if (fmt[i] == 'e')
                   1227:        invert_exp (XEXP (x, i), olabel, nlabel);
                   1228:       if (fmt[i] == 'E')
                   1229:        {
                   1230:          register int j;
                   1231:          for (j = 0; j < XVECLEN (x, i); j++)
                   1232:            invert_exp (XVECEXP (x, i, j), olabel, nlabel);
                   1233:        }
                   1234:     }
                   1235: }
                   1236: 
                   1237: /* Make jump JUMP jump to label NLABEL instead of where it jumps now.
                   1238:    If the old jump target label is unused as a result,
                   1239:    it and the code following it may be deleted.  */
                   1240: 
                   1241: void
                   1242: redirect_jump (jump, nlabel)
                   1243:      rtx jump, nlabel;
                   1244: {
                   1245:   register rtx olabel = JUMP_LABEL (jump);
                   1246: 
                   1247:   if (nlabel == olabel)
                   1248:     return;
                   1249: 
                   1250:   redirect_exp (PATTERN (jump), olabel, nlabel);
                   1251:   JUMP_LABEL (jump) = nlabel;
                   1252:   ++LABEL_NUSES (nlabel);
                   1253:   INSN_CODE (jump) = -1;
                   1254: 
                   1255:   if (--LABEL_NUSES (olabel) == 0)
                   1256:     delete_insn (olabel);
                   1257: }
                   1258: 
                   1259: /* Throughout the rtx X,
                   1260:    alter (LABEL_REF OLABEL) to (LABEL_REF NLABEL).  */
                   1261: 
                   1262: static void
                   1263: redirect_exp (x, olabel, nlabel)
                   1264:      rtx x;
                   1265:      rtx olabel, nlabel;
                   1266: {
                   1267:   register RTX_CODE code = GET_CODE (x);
                   1268:   register int i;
                   1269:   register char *fmt;
                   1270: 
                   1271:   if (code == LABEL_REF)
                   1272:     {
                   1273:       if (XEXP (x, 0) == olabel)
                   1274:        XEXP (x, 0) = nlabel;
                   1275:       return;
                   1276:     }
                   1277: 
                   1278:   fmt = GET_RTX_FORMAT (code);
                   1279:   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
                   1280:     {
                   1281:       if (fmt[i] == 'e')
                   1282:        redirect_exp (XEXP (x, i), olabel, nlabel);
                   1283:       if (fmt[i] == 'E')
                   1284:        {
                   1285:          register int j;
                   1286:          for (j = 0; j < XVECLEN (x, i); j++)
                   1287:            redirect_exp (XVECEXP (x, i, j), olabel, nlabel);
                   1288:        }
                   1289:     }
                   1290: }
                   1291: 
                   1292: /* Like rtx_equal_p except that it considers two REGs as equal
                   1293:    if they renumber to the same value.  */
                   1294: 
                   1295: int
                   1296: rtx_renumbered_equal_p (x, y)
                   1297:      rtx x, y;
                   1298: {
                   1299:   register int i;
                   1300:   register RTX_CODE code = GET_CODE (x);
                   1301:   register char *fmt;
                   1302:       
                   1303:   if (x == y)
                   1304:     return 1;
                   1305:   if ((code == REG || (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG))
                   1306:       && (GET_CODE (y) == REG || (GET_CODE (y) == SUBREG
                   1307:                                  && GET_CODE (SUBREG_REG (y)) == REG)))
                   1308:     {
                   1309:       register int j;
                   1310: 
                   1311:       if (GET_MODE (x) != GET_MODE (y))
                   1312:        return 0;
                   1313: 
                   1314:       if (code == SUBREG)
                   1315:        {
                   1316:          i = REGNO (SUBREG_REG (x));
                   1317:          if (reg_renumber[i] >= 0)
                   1318:            i = reg_renumber[i];
                   1319:          i += SUBREG_WORD (x);
                   1320:        }
                   1321:       else
                   1322:        {
                   1323:          i = REGNO (x);
                   1324:          if (reg_renumber[i] >= 0)
                   1325:            i = reg_renumber[i];
                   1326:        }
                   1327:       if (GET_CODE (y) == SUBREG)
                   1328:        {
                   1329:          j = REGNO (SUBREG_REG (y));
                   1330:          if (reg_renumber[j] >= 0)
                   1331:            j = reg_renumber[j];
                   1332:          j += SUBREG_WORD (y);
                   1333:        }
                   1334:       else
                   1335:        {
                   1336:          j = REGNO (y);
                   1337:          if (reg_renumber[j] >= 0)
                   1338:            j = reg_renumber[j];
                   1339:        }
                   1340:       return i == j;
                   1341:     }
                   1342:   /* Now we have disposed of all the cases 
                   1343:      in which different rtx codes can match.  */
                   1344:   if (code != GET_CODE (y))
                   1345:     return 0;
                   1346:   /* Two label-refs are equivalent if they point at labels
                   1347:      in the same position in the instruction stream.  */
                   1348:   if (code == LABEL_REF)
                   1349:     return (next_real_insn (XEXP (x, 0))
                   1350:            == next_real_insn (XEXP (y, 0)));
                   1351:   if (code == SYMBOL_REF)
                   1352:     return XSTR (x, 0) == XSTR (y, 0);
                   1353: 
                   1354:   /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.  */
                   1355: 
                   1356:   if (GET_MODE (x) != GET_MODE (y))
                   1357:     return 0;
                   1358: 
                   1359:   /* Compare the elements.  If any pair of corresponding elements
                   1360:      fail to match, return 0 for the whole things.  */
                   1361: 
                   1362:   fmt = GET_RTX_FORMAT (code);
                   1363:   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
                   1364:     {
                   1365:       register int j;
                   1366:       switch (fmt[i])
                   1367:        {
                   1368:        case 'i':
                   1369:          if (XINT (x, i) != XINT (y, i))
                   1370:            return 0;
                   1371:          break;
                   1372: 
                   1373:        case 's':
                   1374:          if (strcmp (XSTR (x, i), XSTR (y, i)))
                   1375:            return 0;
                   1376:          break;
                   1377: 
                   1378:        case 'e':
                   1379:          if (! rtx_renumbered_equal_p (XEXP (x, i), XEXP (y, i)))
                   1380:            return 0;
                   1381:          break;
                   1382: 
                   1383:        case '0':
                   1384:          break;
                   1385: 
                   1386:        case 'E':
                   1387:          if (XVECLEN (x, i) != XVECLEN (y, i))
                   1388:            return 0;
                   1389:          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
                   1390:            if (!rtx_renumbered_equal_p (XVECEXP (x, i, j), XVECEXP (y, i, j)))
                   1391:              return 0;
                   1392:          break;
                   1393: 
                   1394:          /* It is believed that rtx's at this level will never
                   1395:             contain anything but integers and other rtx's,
                   1396:             except for within LABEL_REFs and SYMBOL_REFs.  */
                   1397:        default:
                   1398:          abort ();
                   1399:        }
                   1400:     }
                   1401:   return 1;
                   1402: }
                   1403: 
                   1404: /* If X is a hard register or equivalent to one or a subregister of one,
                   1405:    return the hard register number.  Otherwise, return -1.
                   1406:    Any rtx is valid for X.  */
                   1407: 
                   1408: int
                   1409: true_regnum (x)
                   1410:      rtx x;
                   1411: {
                   1412:   if (GET_CODE (x) == REG)
                   1413:     {
                   1414:       if (REGNO (x) >= FIRST_PSEUDO_REGISTER)
                   1415:        return reg_renumber[REGNO (x)];
                   1416:       return REGNO (x);
                   1417:     }
                   1418:   if (GET_CODE (x) == SUBREG)
                   1419:     {
                   1420:       int base = true_regnum (SUBREG_REG (x));
                   1421:       if (base >= 0)
                   1422:        return SUBREG_WORD (x) + base;
                   1423:     }
                   1424:   return -1;
                   1425: }

unix.superglobalmegacorp.com

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