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

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
                    234:    OFFSET[] at address ADDR; insert the loads after INSN.
                    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;
                    246: 
                    247:   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
                    248:     if (offset[regno] >= 0)
                    249:       {
                    250:        rtx reg = save_reg_rtx[regno];
                    251:        rtx temp =
                    252:          gen_rtx (MEM, GET_MODE (reg), plus_constant (addr, offset[regno]));
                    253:        emit_insn_before (gen_move_insn (temp, reg), insn);
                    254:       }
                    255: }
                    256: 
                    257: /* Emit a string of loads to restore the hard regs listed in
                    258:    OFFSET[] from address ADDR; insert the loads before INSN.
                    259:    OFFSET[reg] is -1 if reg should not be loaded, or a
                    260:    suitably-aligned offset from ADDR.  
                    261:    The offsets actually used do not need to be those provided in
                    262:    OFFSET, but should agree with whatever emit_mult_save does.  */
                    263: 
                    264: static void
                    265: emit_mult_restore (insn, addr, offset)
                    266:      rtx insn, addr;
                    267:      int offset[];     
                    268: {
                    269:   int regno;
                    270: 
                    271:   for (regno = FIRST_PSEUDO_REGISTER; --regno >= 0; )
                    272:     if (offset[regno] >= 0)
                    273:       {
                    274:        rtx reg = save_reg_rtx[regno];
                    275:        rtx temp =
                    276:          gen_rtx (MEM, GET_MODE (reg), plus_constant (addr, offset[regno]));
                    277:        emit_insn_after (gen_move_insn (reg, temp), insn);
                    278:       }
                    279: }
                    280: 
                    281: /* Return the address of a new block of size SIZE on the stack.
                    282:    The old save block is at ADDR; ADDR is 0 if no block exists yet.  */
                    283: 
                    284: static rtx
                    285: grow_save_block (addr, size)
                    286:      rtx addr;
                    287:      int size;
                    288: {
                    289:   rtx newaddr;
                    290: 
                    291:   /* Keep the size a multiple of the main allocation unit.  */
                    292:   size = (((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1)
                    293:           / (BIGGEST_ALIGNMENT / BITS_PER_UNIT))
                    294:          * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
                    295: 
                    296:   /* If no save block exists yet, create one and return it.  */
                    297:   if (! addr)
                    298:     {
                    299:       save_block_size = size;
                    300:       return XEXP (assign_stack_local (BLKmode, size), 0);
                    301:     }
                    302: 
                    303:   /* Get a new block and coalesce it with the old one.  */
                    304:   newaddr = XEXP (assign_stack_local (BLKmode, size - save_block_size), 0);
                    305:   if (GET_CODE (newaddr) == PLUS
                    306:       && XEXP (newaddr, 0) == frame_pointer_rtx
                    307:       && GET_CODE (XEXP (newaddr, 1)) == CONST_INT
                    308:       && GET_CODE (addr) == PLUS
                    309:       && XEXP (addr, 0) == frame_pointer_rtx
                    310:       && GET_CODE (XEXP (addr, 1)) == CONST_INT
                    311:       && ((INTVAL (XEXP (newaddr, 1)) - INTVAL (XEXP (addr, 1))
                    312:           == size - save_block_size)
                    313:          || (INTVAL (XEXP (addr, 1)) - INTVAL (XEXP (newaddr, 1))
                    314:              == size - save_block_size)))
                    315:     {
                    316:       save_block_size = size;
                    317:       if (INTVAL (XEXP (newaddr, 1)) < INTVAL (XEXP (addr, 1)))
                    318:        return newaddr;
                    319:       else
                    320:        return addr;
                    321:     }
                    322: 
                    323:   /* They didn't coalesce, find out why */
                    324:   abort ();                    
                    325: 
                    326:   save_block_size = size;
                    327:   return XEXP (assign_stack_local (BLKmode, size), 0);
                    328: }
                    329: 
                    330: /* Return a machine mode that is legitimate for hard reg REGNO
                    331:    and large enough to save the whole register.  */
                    332: 
                    333: static enum machine_mode
                    334: choose_hard_reg_mode (regno)
                    335:      int regno;
                    336: {
                    337:   enum reg_class class = REGNO_REG_CLASS (regno);
                    338: 
                    339:   if (CLASS_MAX_NREGS (class, DImode) == 1
                    340:       && HARD_REGNO_MODE_OK (regno, DImode))
                    341:     return DImode;
                    342:   else if (CLASS_MAX_NREGS (class, DFmode) == 1
                    343:           && HARD_REGNO_MODE_OK (regno, DFmode))
                    344:     return DFmode;
                    345:   else if (CLASS_MAX_NREGS (class, SImode) == 1
                    346:           && HARD_REGNO_MODE_OK (regno, SImode))
                    347:     return SImode;
                    348:   else if (CLASS_MAX_NREGS (class, SFmode) == 1
                    349:           && HARD_REGNO_MODE_OK (regno, SFmode))
                    350:     return SFmode;
                    351:   else if (CLASS_MAX_NREGS (class, HImode) == 1
                    352:           && HARD_REGNO_MODE_OK (regno, HImode))
                    353:     return HImode;
                    354:   else
                    355:     abort ();
                    356: }

unix.superglobalmegacorp.com

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