|
|
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.