Annotation of gcc/caller-save.c, revision 1.1.1.2

1.1       root        1: /* Save and restore call-clobbered registers which are live across a call.
                      2:    Copyright (C) 1989 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 1, 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: #include "config.h"
                     21: #include "rtl.h"
                     22: #include "insn-config.h"
                     23: #include "flags.h"
                     24: #include "regs.h"
                     25: #include "hard-reg-set.h"
                     26: #include "reload.h"
                     27: #include "recog.h"
                     28: #include "basic-block.h"
                     29: 
                     30: /* Set of hard regs currently live (during scan of all insns).  */
                     31: 
                     32: static HARD_REG_SET hard_regs_live;
                     33: 
                     34: /* The block of storage on the stack where regs are saved */
                     35: 
                     36: static rtx save_block_addr;
                     37: static int save_block_size;
                     38: 
                     39: /* A REG rtx for each hard register that has been saved.  */
                     40: 
                     41: static rtx save_reg_rtx[FIRST_PSEUDO_REGISTER];
                     42: 
                     43: static void set_reg_live ();
                     44: static void clear_reg_live ();
                     45: static void insert_call_saves ();
                     46: static void emit_mult_save ();
                     47: static void emit_mult_restore ();
                     48: static rtx grow_save_block ();
                     49: static enum machine_mode choose_hard_reg_mode ();
                     50: 
                     51: /* Find the places where hard regs are live across calls and save them.  */
                     52: 
                     53: save_call_clobbered_regs ()
                     54: {
                     55:   rtx insn;
                     56:   int b;
                     57: 
                     58:   if (obey_regdecls)
                     59:     return;
                     60:   
                     61:   save_block_size = 0;
                     62:   save_block_addr = 0;
                     63:   bzero (save_reg_rtx, sizeof save_reg_rtx);
                     64: 
                     65:   for (b = 0; b < n_basic_blocks; b++)
                     66:     {
                     67:       regset regs_live = basic_block_live_at_start[b];
                     68:       int offset, bit, i;
                     69: 
                     70:       /* Compute hard regs live at start of block -- this is the
                     71:         real hard regs marked live, plus live pseudo regs that
                     72:         have been renumbered to hard regs.  */
                     73: 
                     74: #ifdef HARD_REG_SET
                     75:       hard_regs_live = *regs_live;
                     76: #else
                     77:       COPY_HARD_REG_SET (hard_regs_live, regs_live);
                     78: #endif
                     79: 
                     80:       for (offset = 0, i = 0; offset < regset_size; offset++)
                     81:        {
                     82:          if (regs_live[offset] == 0)
                     83:            i += HOST_BITS_PER_INT;
                     84:          else
                     85:            for (bit = 1; bit && i < max_regno; bit <<= 1, i++)
                     86:              if ((regs_live[offset] & bit) && reg_renumber[i] >= 0)
                     87:                SET_HARD_REG_BIT (hard_regs_live, reg_renumber[i]);
                     88:        }
                     89: 
                     90:       /* Now scan the insns in the block, keeping track of what hard
                     91:         regs are live as we go.  When we see a call, save the live
                     92:         call-clobbered hard regs.  */
                     93: 
                     94:       for (insn = basic_block_head[b]; TRUE; insn = NEXT_INSN (insn))
                     95:        {
                     96:          RTX_CODE code = GET_CODE (insn);
                     97: 
                     98:          if (code == CALL_INSN)
                     99:            insert_call_saves (insn);
                    100: 
                    101:          if (code == INSN || code == CALL_INSN || code == JUMP_INSN)
                    102:            {
                    103:              rtx link;
                    104: 
                    105:              /* NB: the normal procedure is to first enliven any
                    106:                 registers set by insn, then deaden any registers that
                    107:                 had their last use at insn.  This is incorrect now,
                    108:                 since multiple pseudos may have been mapped to the
                    109:                 same hard reg, and the death notes are ambiguous.  So
                    110:                 it must be done in the other, safe, order.  */
                    111: 
                    112:              for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
                    113:                if (REG_NOTE_KIND (link) == REG_DEAD)
                    114:                  clear_reg_live (XEXP (link, 0));
                    115: 
                    116:              note_stores (PATTERN (insn), set_reg_live);
                    117:            }
                    118: 
                    119:          if (insn == basic_block_end[b])
                    120:            break;
                    121:        }
                    122:     }
                    123: }
                    124: 
                    125: /* Here from note_stores when an insn stores a value in a register.
                    126:    Set the proper bit or bits in hard_regs_live.  */
                    127: 
                    128: static void
                    129: set_reg_live (reg, setter)
                    130:      rtx reg, setter;
                    131: {
                    132:   register int regno;
                    133: 
                    134:   /* WORD is which word of a multi-register group is being stored.
                    135:      For the case where the store is actually into a SUBREG of REG.
                    136:      Except we don't use it; I believe the entire REG needs to be
                    137:      live.  */
                    138:   int word = 0;
                    139: 
                    140:   if (GET_CODE (reg) == SUBREG)
                    141:     {
                    142:       word = SUBREG_WORD (reg);
                    143:       reg = SUBREG_REG (reg);
                    144:     }
                    145: 
                    146:   if (GET_CODE (reg) != REG)
                    147:     return;
                    148: 
                    149:   regno = REGNO (reg);
                    150: 
                    151:   /* For pseudo reg, see if it has been assigned a hardware reg.  */
                    152:   if (reg_renumber[regno] >= 0)
                    153:     regno = reg_renumber[regno] /* + word */;
                    154: 
                    155:   /* Handle hardware regs (and pseudos allocated to hard regs).  */
                    156:   if (regno < FIRST_PSEUDO_REGISTER && ! call_fixed_regs[regno])
                    157:     {
                    158:       register int last = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
                    159:       while (regno < last)
                    160:        {
                    161:          SET_HARD_REG_BIT (hard_regs_live, regno);
                    162:          regno++;
                    163:        }
                    164:     }
                    165: }
                    166: 
                    167: /* Here when a REG_DEAD note records the last use of a reg.  Clear
                    168:    the appropriate bit or bits in hard_regs_live.  */
                    169: 
                    170: static void
                    171: clear_reg_live (reg)
                    172:      rtx reg;
                    173: {
                    174:   register int regno = REGNO (reg);
                    175: 
                    176:   /* For pseudo reg, see if it has been assigned a hardware reg.  */
                    177:   if (reg_renumber[regno] >= 0)
                    178:     regno = reg_renumber[regno];
                    179: 
                    180:   /* Handle hardware regs (and pseudos allocated to hard regs).  */
                    181:   if (regno < FIRST_PSEUDO_REGISTER && ! call_fixed_regs[regno])
                    182:     {
                    183:       /* Pseudo regs already assigned hardware regs are treated
                    184:         almost the same as explicit hardware regs.  */
                    185:       register int last = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
                    186:       while (regno < last)
                    187:        {
                    188:          CLEAR_HARD_REG_BIT (hard_regs_live, regno);
                    189:          regno++;
                    190:        }
                    191:     }
                    192: }      
                    193: 
                    194: /* Insert insns to save and restore live call-clobbered regs around
                    195:    call insn INSN.  */
                    196: 
                    197: static void
                    198: insert_call_saves (insn)
                    199:      rtx insn;
                    200: {
                    201:   int regno;
                    202:   int save_block_size_needed;
                    203:   int save_block_offset[FIRST_PSEUDO_REGISTER];
                    204: 
                    205:   save_block_size_needed = 0;
                    206:   
                    207:   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
                    208:     {
                    209:       save_block_offset[regno] = -1;
                    210:       if (call_used_regs[regno] && ! call_fixed_regs[regno]
                    211:          && TEST_HARD_REG_BIT (hard_regs_live, regno))
                    212:        {
                    213:          enum machine_mode mode = choose_hard_reg_mode (regno);
                    214:          int align = GET_MODE_UNIT_SIZE (mode);
                    215:          if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
                    216:            align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
                    217:          save_block_size_needed =
                    218:            ((save_block_size_needed + align - 1) / align) * align;
                    219:          save_block_offset[regno] = save_block_size_needed;
                    220:          save_block_size_needed += GET_MODE_SIZE (mode);
                    221:          if (! save_reg_rtx[regno])
                    222:            save_reg_rtx[regno] = gen_rtx (REG, mode, regno);
                    223:        }
                    224:     }
                    225: 
                    226:   if (save_block_size < save_block_size_needed)
                    227:     save_block_addr = grow_save_block (save_block_addr,
                    228:                                       save_block_size_needed);
                    229:   emit_mult_save (insn, save_block_addr, save_block_offset);
                    230:   emit_mult_restore (insn, save_block_addr, save_block_offset);
                    231: }
                    232: 
                    233: /* Emit a string of stores to save the hard regs listed in
1.1.1.2 ! root      234:    OFFSET[] at address ADDR.  Emit them before INSN.
1.1       root      235:    OFFSET[reg] is -1 if reg should not be saved, or a
                    236:    suitably-aligned offset from ADDR.  
                    237:    The offsets actually used do not have to be those listed
                    238:    in OFFSET, but should fit in a block of the same size.  */
                    239: 
                    240: static void
                    241: emit_mult_save (insn, addr, offset)
                    242:      rtx insn, addr;
                    243:      int offset[];
                    244: {
                    245:   int regno;
1.1.1.2 ! root      246:   /* A register to use as a temporary for address calculations.  */
        !           247:   rtx tempreg;
        !           248:   /* A register that could be used as that temp if we save and restore it.  */
        !           249:   rtx can_push_reg;
        !           250:   /* Nonzero means we need to save a register to use it as TEMPREG.  */
        !           251:   int needpush;
        !           252:   /* The amount the stack is decremented to save that register (if we do).  */
        !           253:   int decrement;
        !           254:   /* Record which regs we save, in case we branch to retry.  */
        !           255:   char already_saved[FIRST_PSEUDO_REGISTER];
        !           256: 
        !           257:   bzero (already_saved, sizeof already_saved);
        !           258: 
        !           259:   /* Hair is needed because sometimes the addresses to save in are
        !           260:      not valid (offsets too big).
        !           261:      So we need a reg, TEMPREG, to compute addresses in.
        !           262: 
        !           263:      We look first for an empty reg to use.
        !           264:      Sometimes no reg is empty.  Then we push a reg, use it, and pop it.
        !           265: 
        !           266:      Sometimes the only reg to push and pop this way is one we want to save.
        !           267:      We can't save it while using it as a temporary.
        !           268:      So we save all the other registers, pop it, and go back to `retry'.
        !           269:      At that point, only this reg remains to be saved;
        !           270:      all the others already saved are empty.
        !           271:      So one of them can be the temporary for this one.  */
        !           272: 
        !           273:   /* Sometimes we can't save all the regs conveniently at once, just some.
        !           274:      If that happens, we branch back here to save the rest.  */
        !           275:  retry:
        !           276:   needpush = 0;
        !           277:   tempreg = 0;
        !           278:   can_push_reg = 0;
        !           279: 
        !           280:   /* Set NEEDPUSH if any save-addresses are not valid memory addresses.
        !           281:      If any register is available, record it in TEMPREG.
        !           282:      If any register doesn't need saving here, record it in CAN_PUSH_REG.  */
        !           283:   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
        !           284:     {
        !           285:       if (offset[regno] >= 0 && ! already_saved[regno])
        !           286:        {
        !           287:          rtx reg = save_reg_rtx[regno];
        !           288:          rtx addr1 = plus_constant (addr, offset[regno]);
        !           289:          if (memory_address_p (GET_MODE (reg), addr1))
        !           290:            needpush = 1;
        !           291:        }
        !           292: 
        !           293:       /* A call-clobbered reg that is dead, or already saved,
        !           294:         can be used as a temporary for sure, at no extra cost.  */
        !           295:       if (tempreg == 0 && call_used_regs[regno] && ! fixed_regs[regno]
        !           296:          && !(offset[regno] >= 0 && ! already_saved[regno])
        !           297:          && HARD_REGNO_MODE_OK (regno, Pmode))
        !           298:        {
        !           299:          tempreg = gen_rtx (REG, Pmode, regno);
        !           300:          /* Don't use it if not valid for addressing.  */
        !           301:          if (! strict_memory_address_p (QImode, tempreg))
        !           302:            tempreg = 0;
        !           303:        }
        !           304: 
        !           305:       /* A call-saved reg can be a temporary if we push and pop it.  */
        !           306:       if (can_push_reg == 0 && ! call_used_regs[regno]
        !           307:          && HARD_REGNO_MODE_OK (regno, Pmode))
        !           308:        {
        !           309:          can_push_reg = gen_rtx (REG, Pmode, regno);
        !           310:          /* Don't use it if not valid for addressing.  */
        !           311:          if (! strict_memory_address_p (QImode, can_push_reg))
        !           312:            can_push_reg = 0;
        !           313:        }
        !           314:     }
        !           315: 
        !           316:   /* Clear NEEDPUSH if we already found an empty reg.  */
        !           317:   if (tempreg != 0)
        !           318:     needpush = 0;
        !           319: 
        !           320:   /* If we need a temp reg and none is free, make one free.  */
        !           321:   if (needpush)
        !           322:     {
        !           323:       /* Choose a reg, preferably not among those it is our job to save.  */
        !           324:       if (can_push_reg != 0)
        !           325:        tempreg = can_push_reg;
        !           326:       else
        !           327:        {
        !           328:          for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
        !           329:            if (offset[regno] >= 0 && !already_saved[regno]
        !           330:                && HARD_REGNO_MODE_OK (regno, Pmode))
        !           331:              {
        !           332:                tempreg = gen_rtx (REG, Pmode, regno);
        !           333:                /* Don't use it if not valid for addressing.  */
        !           334:                if (! strict_memory_address_p (QImode, tempreg))
        !           335:                  tempreg = 0;
        !           336:                else
        !           337:                  break;
        !           338:              }
        !           339:        }
        !           340: 
        !           341:       /* Push it on the stack.  */
        !           342: #ifdef STACK_GROWS_DOWNWARD
        !           343:       decrement = UNITS_PER_WORD;
        !           344: #else
        !           345:       decrement = - UNITS_PER_WORD;
        !           346: #endif
        !           347: 
        !           348:       emit_insn_before (gen_add2_insn (stack_pointer_rtx,
        !           349:                                       gen_rtx (CONST_INT, VOIDmode, -decrement)),
        !           350:                        insn);
        !           351:       emit_insn_before (gen_move_insn (gen_rtx (MEM, Pmode, stack_pointer_rtx),
        !           352:                                       tempreg),
        !           353:                        insn);
        !           354:     }
1.1       root      355: 
1.1.1.2 ! root      356:   /* Save the regs we are supposed to save, aside from TEMPREG.
        !           357:      Use TEMPREG for address calculations when needed.  */
1.1       root      358:   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
1.1.1.2 ! root      359:     if (offset[regno] >= 0 && ! already_saved[regno]
        !           360:        && tempreg != 0 && REGNO (tempreg) != regno)
1.1       root      361:       {
                    362:        rtx reg = save_reg_rtx[regno];
1.1.1.2 ! root      363:        rtx addr1 = plus_constant (addr, offset[regno]);
        !           364:        rtx temp;
        !           365:        if (! memory_address_p (GET_MODE (reg), addr1))
        !           366:          {
        !           367:            if (GET_CODE (addr1) != PLUS)
        !           368:              abort ();
        !           369:            if (GET_CODE (XEXP (addr1, 1)) != CONST_INT
        !           370:                || GET_CODE (XEXP (addr1, 0)) != REG)
        !           371:              abort ();
        !           372:            emit_insn_before (gen_move_insn (tempreg, XEXP (addr1, 0)), insn);
        !           373:            emit_insn_before (gen_add2_insn (tempreg, XEXP (addr1, 1)), insn);
        !           374:            addr1 = tempreg;
        !           375:          }
        !           376:        temp = gen_rtx (MEM, GET_MODE (reg), addr1);
1.1       root      377:        emit_insn_before (gen_move_insn (temp, reg), insn);
1.1.1.2 ! root      378:        already_saved[regno] = 1;
1.1       root      379:       }
1.1.1.2 ! root      380: 
        !           381:   /* If we pushed TEMPREG to make it free, pop it.  */
        !           382:   if (needpush)
        !           383:     {
        !           384:       emit_insn_before (gen_move_insn (tempreg,
        !           385:                                       gen_rtx (MEM, Pmode, stack_pointer_rtx)),
        !           386:                        insn);
        !           387:       emit_insn_before (gen_add2_insn (stack_pointer_rtx,
        !           388:                                       gen_rtx (CONST_INT, VOIDmode, decrement)),
        !           389:                        insn);
        !           390:     }
        !           391: 
        !           392:   /* If TEMPREG itself needs saving, go back and save it.
        !           393:      There are plenty of free regs now, those already saved.  */
        !           394:   if (tempreg != 0
        !           395:       && offset[REGNO (tempreg)] >= 0 && ! already_saved[REGNO (tempreg)])
        !           396:     goto retry;
1.1       root      397: }
                    398: 
                    399: /* Emit a string of loads to restore the hard regs listed in
1.1.1.2 ! root      400:    OFFSET[] from address ADDR; insert the loads after INSN.
1.1       root      401:    OFFSET[reg] is -1 if reg should not be loaded, or a
                    402:    suitably-aligned offset from ADDR.  
                    403:    The offsets actually used do not need to be those provided in
                    404:    OFFSET, but should agree with whatever emit_mult_save does.  */
                    405: 
                    406: static void
                    407: emit_mult_restore (insn, addr, offset)
                    408:      rtx insn, addr;
1.1.1.2 ! root      409:      int offset[];
1.1       root      410: {
                    411:   int regno;
                    412: 
1.1.1.2 ! root      413:   /* Number of regs now needing to be restored.  */
        !           414:   int restore_count;
        !           415:   /* A register to use as a temporary for address calculations.  */
        !           416:   rtx tempreg;
        !           417:   /* A register available for that purpose but less desirable.  */
        !           418:   rtx maybe_tempreg;
        !           419:   /* A register that could be used as that temp if we push and pop it.  */
        !           420:   rtx can_push_reg;
        !           421:   /* Nonzero means we need to push and pop a register to use it as TEMPREG.  */
        !           422:   int needpush;
        !           423:   /* The amount the stack is decremented to save that register (if we do).  */
        !           424:   int decrement;
        !           425:   /* Record which regs we restore, in case we branch to retry.  */
        !           426:   char already_restored[FIRST_PSEUDO_REGISTER];
        !           427: 
        !           428:   bzero (already_restored, sizeof already_restored);
        !           429: 
        !           430:   /* Note: INSN can't be the last insn, since if it were,
        !           431:      no regs would live across it.  */
        !           432:   insn = NEXT_INSN (insn);
        !           433:   if (insn == 0)
        !           434:     abort ();
        !           435:   /* Now we can insert before INSN.
        !           436:      That is convenient because we can insert them in the order
        !           437:      that they should ultimately appear.  */
        !           438: 
        !           439:   /* Hair is needed because sometimes the addresses to restore from are
        !           440:      not valid (offsets too big).
        !           441:      So we need a reg, TEMPREG, to compute addresses in.
        !           442: 
        !           443:      We look first for an empty reg to use.
        !           444:      Sometimes no reg is empty.  Then we push a reg, use it, and pop it.
        !           445: 
        !           446:      If all the suitable regs need to be restored,
        !           447:      that strategy won't work.  So we restore all but one, using that one
        !           448:      as a temporary.  Then we jump to `retry' to restore that one,
        !           449:      pushing and popping another (already restored) as a temporary.  */
        !           450: 
        !           451:  retry:
        !           452:   needpush = 0;
        !           453:   tempreg = 0;
        !           454:   can_push_reg = 0;
        !           455:   restore_count = 0;
        !           456: 
        !           457:   /* Set NEEDPUSH if any restore-addresses are not valid memory addresses.
        !           458:      If any register is available, record it in TEMPREG.
        !           459:      Otherwise, one register yet to be restored goes in MAYBE_TEMPREG,
        !           460:      and can be used as TEMPREG for any other regs to be restored.
        !           461:      If any register doesn't need restoring, record it in CAN_PUSH_REG.  */
        !           462:   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
        !           463:     {
        !           464:       if (offset[regno] >= 0 && ! already_restored[regno])
        !           465:        {
        !           466:          rtx reg = save_reg_rtx[regno];
        !           467:          rtx addr1 = plus_constant (addr, offset[regno]);
        !           468: 
        !           469:          restore_count++;
        !           470: 
        !           471:          if (memory_address_p (GET_MODE (reg), addr1))
        !           472:            needpush = 1;
        !           473: 
        !           474:          /* Find a call-clobbered reg that needs restoring.
        !           475:             We can use it as a temporary if we defer restoring it.  */
        !           476:          if (maybe_tempreg == 0)
        !           477:            {
        !           478:              maybe_tempreg = gen_rtx (REG, Pmode, regno);
        !           479:              /* Don't use it if not valid for addressing.  */
        !           480:              if (! strict_memory_address_p (QImode, maybe_tempreg))
        !           481:                maybe_tempreg = 0;
        !           482:            }
        !           483:        }
        !           484: 
        !           485:       /* If any call-clobbered reg is dead, put it in TEMPREG.
        !           486:         It can be used as a temporary at no extra cost.  */
        !           487:       if (tempreg == 0 && call_used_regs[regno] && ! fixed_regs[regno]
        !           488:          && ! offset[regno] >= 0
        !           489:          && HARD_REGNO_MODE_OK (regno, Pmode))
        !           490:        {
        !           491:          tempreg = gen_rtx (REG, Pmode, regno);
        !           492:          /* Don't use it if not valid for addressing.  */
        !           493:          if (! strict_memory_address_p (QImode, tempreg))
        !           494:            tempreg = 0;
        !           495:        }
        !           496: 
        !           497:       /* Any non-call-clobbered reg, put in CAN_PUSH_REG.
        !           498:         It can be used as a temporary if we push and pop it.  */
        !           499:       if (can_push_reg == 0 && ! call_used_regs[regno]
        !           500:          && HARD_REGNO_MODE_OK (regno, Pmode))
        !           501:        {
        !           502:          can_push_reg = gen_rtx (REG, Pmode, regno);
        !           503:          /* Don't use it if not valid for addressing.  */
        !           504:          if (! strict_memory_address_p (QImode, can_push_reg))
        !           505:            can_push_reg = 0;
        !           506:        }
        !           507:       /* Any reg we already restored can be a temporary
        !           508:         if we push and pop it.  */
        !           509:       if (can_push_reg == 0 && already_restored[regno]
        !           510:          && HARD_REGNO_MODE_OK (regno, Pmode))
        !           511:        {
        !           512:          can_push_reg = gen_rtx (REG, Pmode, regno);
        !           513:          /* Don't use it if not valid for addressing.  */
        !           514:          if (! strict_memory_address_p (QImode, can_push_reg))
        !           515:            can_push_reg = 0;
        !           516:        }
        !           517:     }
        !           518: 
        !           519:   /* If 2 or more regs need to be restored, use one as a temp reg
        !           520:      for the rest (if we need a tempreg).  */
        !           521:   if (tempreg == 0 && maybe_tempreg != 0 && restore_count > 1)
        !           522:     tempreg = maybe_tempreg;
        !           523: 
        !           524:   /* Clear NEEDPUSH if we already found an empty reg.  */
        !           525:   if (tempreg != 0)
        !           526:     needpush = 0;
        !           527: 
        !           528:   /* If we need a temp reg and none is free, make one free.  */
        !           529:   if (needpush)
        !           530:     {
        !           531:       tempreg = can_push_reg;
        !           532: 
        !           533:       /* Push it on the stack.  */
        !           534: #ifdef STACK_GROWS_DOWNWARD
        !           535:       decrement = UNITS_PER_WORD;
        !           536: #else
        !           537:       decrement = - UNITS_PER_WORD;
        !           538: #endif
        !           539: 
        !           540:       emit_insn_before (gen_add2_insn (stack_pointer_rtx,
        !           541:                                       gen_rtx (CONST_INT, VOIDmode, -decrement)),
        !           542:                        insn);
        !           543:       emit_insn_before (gen_move_insn (gen_rtx (MEM, Pmode, stack_pointer_rtx),
        !           544:                                       tempreg),
        !           545:                        insn);
        !           546:     }
        !           547: 
        !           548:   /* Restore the regs we are supposed to restore, aside from TEMPREG.
        !           549:      Use TEMPREG for address calculations when needed.  */
        !           550:   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
        !           551:     if (offset[regno] >= 0 && ! already_restored[regno]
        !           552:        && tempreg != 0 && REGNO (tempreg) != regno)
1.1       root      553:       {
                    554:        rtx reg = save_reg_rtx[regno];
1.1.1.2 ! root      555:        rtx addr1 = plus_constant (addr, offset[regno]);
        !           556:        rtx temp;
        !           557:        if (! memory_address_p (GET_MODE (reg), addr1))
        !           558:          {
        !           559:            if (GET_CODE (addr1) != PLUS)
        !           560:              abort ();
        !           561:            if (GET_CODE (XEXP (addr1, 1)) != CONST_INT
        !           562:                || GET_CODE (XEXP (addr1, 0)) != REG)
        !           563:              abort ();
        !           564:            emit_insn_before (gen_move_insn (tempreg, XEXP (addr1, 0)), insn);
        !           565:            emit_insn_before (gen_add2_insn (tempreg, XEXP (addr1, 1)), insn);
        !           566:            addr1 = tempreg;
        !           567:          }
        !           568:        temp = gen_rtx (MEM, GET_MODE (reg), addr1);
        !           569:        emit_insn_before (gen_move_insn (reg, temp), insn);
        !           570:        already_restored[regno] = 1;
1.1       root      571:       }
1.1.1.2 ! root      572: 
        !           573:   /* If we pushed TEMPREG to make it free, pop it.  */
        !           574:   if (needpush)
        !           575:     {
        !           576:       emit_insn_before (gen_move_insn (tempreg,
        !           577:                                       gen_rtx (MEM, Pmode, stack_pointer_rtx)),
        !           578:                        insn);
        !           579:       emit_insn_before (gen_add2_insn (stack_pointer_rtx,
        !           580:                                       gen_rtx (CONST_INT, VOIDmode, decrement)),
        !           581:                        insn);
        !           582:     }
        !           583: 
        !           584:   /* If TEMPREG itself needs restoring, go back and restore it.
        !           585:      We can find a reg already restored to push and use as a temporary.  */
        !           586:   if (tempreg != 0
        !           587:       && offset[REGNO (tempreg)] >= 0 && ! already_restored[REGNO (tempreg)])
        !           588:     goto retry;
1.1       root      589: }
                    590: 
                    591: /* Return the address of a new block of size SIZE on the stack.
                    592:    The old save block is at ADDR; ADDR is 0 if no block exists yet.  */
                    593: 
                    594: static rtx
                    595: grow_save_block (addr, size)
                    596:      rtx addr;
                    597:      int size;
                    598: {
                    599:   rtx newaddr;
                    600: 
                    601:   /* Keep the size a multiple of the main allocation unit.  */
                    602:   size = (((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1)
                    603:           / (BIGGEST_ALIGNMENT / BITS_PER_UNIT))
                    604:          * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
                    605: 
                    606:   /* If no save block exists yet, create one and return it.  */
                    607:   if (! addr)
                    608:     {
                    609:       save_block_size = size;
                    610:       return XEXP (assign_stack_local (BLKmode, size), 0);
                    611:     }
                    612: 
                    613:   /* Get a new block and coalesce it with the old one.  */
                    614:   newaddr = XEXP (assign_stack_local (BLKmode, size - save_block_size), 0);
                    615:   if (GET_CODE (newaddr) == PLUS
                    616:       && XEXP (newaddr, 0) == frame_pointer_rtx
                    617:       && GET_CODE (XEXP (newaddr, 1)) == CONST_INT
                    618:       && GET_CODE (addr) == PLUS
                    619:       && XEXP (addr, 0) == frame_pointer_rtx
                    620:       && GET_CODE (XEXP (addr, 1)) == CONST_INT
                    621:       && ((INTVAL (XEXP (newaddr, 1)) - INTVAL (XEXP (addr, 1))
                    622:           == size - save_block_size)
                    623:          || (INTVAL (XEXP (addr, 1)) - INTVAL (XEXP (newaddr, 1))
                    624:              == size - save_block_size)))
                    625:     {
                    626:       save_block_size = size;
                    627:       if (INTVAL (XEXP (newaddr, 1)) < INTVAL (XEXP (addr, 1)))
                    628:        return newaddr;
                    629:       else
                    630:        return addr;
                    631:     }
                    632: 
                    633:   /* They didn't coalesce, find out why */
                    634:   abort ();                    
                    635: 
                    636:   save_block_size = size;
                    637:   return XEXP (assign_stack_local (BLKmode, size), 0);
                    638: }
                    639: 
                    640: /* Return a machine mode that is legitimate for hard reg REGNO
                    641:    and large enough to save the whole register.  */
                    642: 
                    643: static enum machine_mode
                    644: choose_hard_reg_mode (regno)
                    645:      int regno;
                    646: {
                    647:   enum reg_class class = REGNO_REG_CLASS (regno);
                    648: 
                    649:   if (CLASS_MAX_NREGS (class, DImode) == 1
                    650:       && HARD_REGNO_MODE_OK (regno, DImode))
                    651:     return DImode;
                    652:   else if (CLASS_MAX_NREGS (class, DFmode) == 1
                    653:           && HARD_REGNO_MODE_OK (regno, DFmode))
                    654:     return DFmode;
                    655:   else if (CLASS_MAX_NREGS (class, SImode) == 1
                    656:           && HARD_REGNO_MODE_OK (regno, SImode))
                    657:     return SImode;
                    658:   else if (CLASS_MAX_NREGS (class, SFmode) == 1
                    659:           && HARD_REGNO_MODE_OK (regno, SFmode))
                    660:     return SFmode;
                    661:   else if (CLASS_MAX_NREGS (class, HImode) == 1
                    662:           && HARD_REGNO_MODE_OK (regno, HImode))
                    663:     return HImode;
                    664:   else
                    665:     abort ();
                    666: }

unix.superglobalmegacorp.com

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