|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.