]> gcc.gnu.org Git - gcc.git/blame - gcc/combine-stack-adj.c
re PR tree-optimization/46177 (ICE: in prop_phis, at tree-loop-distribution.c:327...
[gcc.git] / gcc / combine-stack-adj.c
CommitLineData
c7a0240a 1/* Combine stack adjustments.
6fb5fa3c 2 Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
efc0b2bd 3 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
6fb5fa3c 4 Free Software Foundation, Inc.
c7a0240a
SB
5
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
9dcd6f09 10Software Foundation; either version 3, or (at your option) any later
c7a0240a
SB
11version.
12
13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
9dcd6f09
NC
19along with GCC; see the file COPYING3. If not see
20<http://www.gnu.org/licenses/>. */
c7a0240a
SB
21
22/* Track stack adjustments and stack memory references. Attempt to
23 reduce the number of stack adjustments by back-propagating across
24 the memory references.
25
26 This is intended primarily for use with targets that do not define
27 ACCUMULATE_OUTGOING_ARGS. It is of significantly more value to
28 targets that define PREFERRED_STACK_BOUNDARY more aligned than
29 STACK_BOUNDARY (e.g. x86), or if not all registers can be pushed
30 (e.g. x86 fp regs) which would ordinarily have to be implemented
31 as a sub/mov pair due to restrictions in calls.c.
32
33 Propagation stops when any of the insns that need adjusting are
34 (a) no longer valid because we've exceeded their range, (b) a
35 non-trivial push instruction, or (c) a call instruction.
36
37 Restriction B is based on the assumption that push instructions
38 are smaller or faster. If a port really wants to remove all
39 pushes, it should have defined ACCUMULATE_OUTGOING_ARGS. The
40 one exception that is made is for an add immediately followed
41 by a push. */
42
43#include "config.h"
44#include "system.h"
45#include "coretypes.h"
46#include "tm.h"
47#include "rtl.h"
48#include "tm_p.h"
49#include "insn-config.h"
50#include "recog.h"
51#include "output.h"
52#include "regs.h"
53#include "hard-reg-set.h"
54#include "flags.h"
55#include "function.h"
56#include "expr.h"
57#include "basic-block.h"
6fb5fa3c 58#include "df.h"
c7a0240a
SB
59#include "except.h"
60#include "toplev.h"
61#include "reload.h"
62#include "timevar.h"
63#include "tree-pass.h"
64
65\f
66/* Turn STACK_GROWS_DOWNWARD into a boolean. */
67#ifdef STACK_GROWS_DOWNWARD
68#undef STACK_GROWS_DOWNWARD
69#define STACK_GROWS_DOWNWARD 1
70#else
71#define STACK_GROWS_DOWNWARD 0
72#endif
73
90588a10
JJ
74/* This structure records two kinds of stack references between stack
75 adjusting instructions: stack references in memory addresses for
76 regular insns and all stack references for debug insns. */
c7a0240a 77
90588a10 78struct csa_reflist
c7a0240a
SB
79{
80 HOST_WIDE_INT sp_offset;
90588a10
JJ
81 rtx insn, *ref;
82 struct csa_reflist *next;
c7a0240a
SB
83};
84
85static int stack_memref_p (rtx);
86static rtx single_set_for_csa (rtx);
90588a10
JJ
87static void free_csa_reflist (struct csa_reflist *);
88static struct csa_reflist *record_one_stack_ref (rtx, rtx *,
89 struct csa_reflist *);
90static int try_apply_stack_adjustment (rtx, struct csa_reflist *,
c7a0240a
SB
91 HOST_WIDE_INT, HOST_WIDE_INT);
92static void combine_stack_adjustments_for_block (basic_block);
90588a10 93static int record_stack_refs (rtx *, void *);
c7a0240a
SB
94
95
96/* Main entry point for stack adjustment combination. */
97
98static void
99combine_stack_adjustments (void)
100{
101 basic_block bb;
102
103 FOR_EACH_BB (bb)
104 combine_stack_adjustments_for_block (bb);
105}
106
107/* Recognize a MEM of the form (sp) or (plus sp const). */
108
109static int
110stack_memref_p (rtx x)
111{
112 if (!MEM_P (x))
113 return 0;
114 x = XEXP (x, 0);
115
116 if (x == stack_pointer_rtx)
117 return 1;
118 if (GET_CODE (x) == PLUS
119 && XEXP (x, 0) == stack_pointer_rtx
481683e1 120 && CONST_INT_P (XEXP (x, 1)))
c7a0240a
SB
121 return 1;
122
123 return 0;
124}
125
126/* Recognize either normal single_set or the hack in i386.md for
127 tying fp and sp adjustments. */
128
129static rtx
130single_set_for_csa (rtx insn)
131{
132 int i;
133 rtx tmp = single_set (insn);
134 if (tmp)
135 return tmp;
136
137 if (!NONJUMP_INSN_P (insn)
138 || GET_CODE (PATTERN (insn)) != PARALLEL)
139 return NULL_RTX;
140
141 tmp = PATTERN (insn);
142 if (GET_CODE (XVECEXP (tmp, 0, 0)) != SET)
143 return NULL_RTX;
144
145 for (i = 1; i < XVECLEN (tmp, 0); ++i)
146 {
48c54229 147 rtx this_rtx = XVECEXP (tmp, 0, i);
c7a0240a
SB
148
149 /* The special case is allowing a no-op set. */
48c54229
KG
150 if (GET_CODE (this_rtx) == SET
151 && SET_SRC (this_rtx) == SET_DEST (this_rtx))
c7a0240a 152 ;
48c54229
KG
153 else if (GET_CODE (this_rtx) != CLOBBER
154 && GET_CODE (this_rtx) != USE)
c7a0240a
SB
155 return NULL_RTX;
156 }
157
158 return XVECEXP (tmp, 0, 0);
159}
160
90588a10 161/* Free the list of csa_reflist nodes. */
c7a0240a
SB
162
163static void
90588a10 164free_csa_reflist (struct csa_reflist *reflist)
c7a0240a 165{
90588a10
JJ
166 struct csa_reflist *next;
167 for (; reflist ; reflist = next)
c7a0240a 168 {
90588a10
JJ
169 next = reflist->next;
170 free (reflist);
c7a0240a
SB
171 }
172}
173
90588a10
JJ
174/* Create a new csa_reflist node from the given stack reference.
175 It is already known that the reference is either a MEM satisfying the
176 predicate stack_memref_p or a REG representing the stack pointer. */
c7a0240a 177
90588a10
JJ
178static struct csa_reflist *
179record_one_stack_ref (rtx insn, rtx *ref, struct csa_reflist *next_reflist)
c7a0240a 180{
90588a10 181 struct csa_reflist *ml;
c7a0240a 182
90588a10 183 ml = XNEW (struct csa_reflist);
c7a0240a 184
90588a10 185 if (REG_P (*ref) || XEXP (*ref, 0) == stack_pointer_rtx)
c7a0240a
SB
186 ml->sp_offset = 0;
187 else
90588a10 188 ml->sp_offset = INTVAL (XEXP (XEXP (*ref, 0), 1));
c7a0240a
SB
189
190 ml->insn = insn;
90588a10
JJ
191 ml->ref = ref;
192 ml->next = next_reflist;
c7a0240a
SB
193
194 return ml;
195}
196
197/* Attempt to apply ADJUST to the stack adjusting insn INSN, as well
90588a10
JJ
198 as each of the memories and stack references in REFLIST. Return true
199 on success. */
c7a0240a
SB
200
201static int
90588a10
JJ
202try_apply_stack_adjustment (rtx insn, struct csa_reflist *reflist,
203 HOST_WIDE_INT new_adjust, HOST_WIDE_INT delta)
c7a0240a 204{
90588a10 205 struct csa_reflist *ml;
c7a0240a
SB
206 rtx set;
207
208 set = single_set_for_csa (insn);
1362aa31
EB
209 if (MEM_P (SET_DEST (set)))
210 validate_change (insn, &SET_DEST (set),
211 replace_equiv_address (SET_DEST (set), stack_pointer_rtx),
212 1);
213 else
214 validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (new_adjust), 1);
c7a0240a 215
90588a10
JJ
216 for (ml = reflist; ml ; ml = ml->next)
217 {
218 rtx new_addr = plus_constant (stack_pointer_rtx, ml->sp_offset - delta);
219 rtx new_val;
220
221 if (MEM_P (*ml->ref))
222 new_val = replace_equiv_address_nv (*ml->ref, new_addr);
223 else if (GET_MODE (*ml->ref) == GET_MODE (stack_pointer_rtx))
224 new_val = new_addr;
225 else
226 new_val = lowpart_subreg (GET_MODE (*ml->ref), new_addr,
227 GET_MODE (new_addr));
228 validate_change (ml->insn, ml->ref, new_val, 1);
229 }
c7a0240a
SB
230
231 if (apply_change_group ())
232 {
90588a10
JJ
233 /* Succeeded. Update our knowledge of the stack references. */
234 for (ml = reflist; ml ; ml = ml->next)
c7a0240a
SB
235 ml->sp_offset -= delta;
236
237 return 1;
238 }
239 else
240 return 0;
241}
242
90588a10
JJ
243/* Called via for_each_rtx and used to record all stack memory and other
244 references in the insn and discard all other stack pointer references. */
245struct record_stack_refs_data
c7a0240a
SB
246{
247 rtx insn;
90588a10 248 struct csa_reflist *reflist;
c7a0240a
SB
249};
250
251static int
90588a10 252record_stack_refs (rtx *xp, void *data)
c7a0240a
SB
253{
254 rtx x = *xp;
90588a10
JJ
255 struct record_stack_refs_data *d =
256 (struct record_stack_refs_data *) data;
c7a0240a
SB
257 if (!x)
258 return 0;
259 switch (GET_CODE (x))
260 {
261 case MEM:
262 if (!reg_mentioned_p (stack_pointer_rtx, x))
263 return -1;
264 /* We are not able to handle correctly all possible memrefs containing
265 stack pointer, so this check is necessary. */
266 if (stack_memref_p (x))
267 {
90588a10 268 d->reflist = record_one_stack_ref (d->insn, xp, d->reflist);
c7a0240a
SB
269 return -1;
270 }
90588a10
JJ
271 /* Try harder for DEBUG_INSNs, handle e.g. (mem (mem (sp + 16) + 4). */
272 return !DEBUG_INSN_P (d->insn);
c7a0240a
SB
273 case REG:
274 /* ??? We want be able to handle non-memory stack pointer
275 references later. For now just discard all insns referring to
276 stack pointer outside mem expressions. We would probably
277 want to teach validate_replace to simplify expressions first.
278
279 We can't just compare with STACK_POINTER_RTX because the
280 reference to the stack pointer might be in some other mode.
281 In particular, an explicit clobber in an asm statement will
90588a10
JJ
282 result in a QImode clobber.
283
284 In DEBUG_INSNs, we want to replace all occurrences, otherwise
285 they will cause -fcompare-debug failures. */
c7a0240a 286 if (REGNO (x) == STACK_POINTER_REGNUM)
90588a10
JJ
287 {
288 if (!DEBUG_INSN_P (d->insn))
289 return 1;
290 d->reflist = record_one_stack_ref (d->insn, xp, d->reflist);
291 return -1;
292 }
c7a0240a
SB
293 break;
294 default:
295 break;
296 }
297 return 0;
298}
299
a182fb6b
JJ
300/* Adjust or create REG_FRAME_RELATED_EXPR note when merging a stack
301 adjustment into a frame related insn. */
302
303static void
304adjust_frame_related_expr (rtx last_sp_set, rtx insn,
305 HOST_WIDE_INT this_adjust)
306{
307 rtx note = find_reg_note (last_sp_set, REG_FRAME_RELATED_EXPR, NULL_RTX);
308 rtx new_expr = NULL_RTX;
309
310 if (note == NULL_RTX && RTX_FRAME_RELATED_P (insn))
311 return;
312
313 if (note
314 && GET_CODE (XEXP (note, 0)) == SEQUENCE
315 && XVECLEN (XEXP (note, 0), 0) >= 2)
316 {
317 rtx expr = XEXP (note, 0);
318 rtx last = XVECEXP (expr, 0, XVECLEN (expr, 0) - 1);
319 int i;
320
321 if (GET_CODE (last) == SET
322 && RTX_FRAME_RELATED_P (last) == RTX_FRAME_RELATED_P (insn)
323 && SET_DEST (last) == stack_pointer_rtx
324 && GET_CODE (SET_SRC (last)) == PLUS
325 && XEXP (SET_SRC (last), 0) == stack_pointer_rtx
481683e1 326 && CONST_INT_P (XEXP (SET_SRC (last), 1)))
a182fb6b
JJ
327 {
328 XEXP (SET_SRC (last), 1)
329 = GEN_INT (INTVAL (XEXP (SET_SRC (last), 1)) + this_adjust);
330 return;
331 }
332
333 new_expr = gen_rtx_SEQUENCE (VOIDmode,
334 rtvec_alloc (XVECLEN (expr, 0) + 1));
335 for (i = 0; i < XVECLEN (expr, 0); i++)
336 XVECEXP (new_expr, 0, i) = XVECEXP (expr, 0, i);
337 }
338 else
339 {
340 new_expr = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (2));
341 if (note)
342 XVECEXP (new_expr, 0, 0) = XEXP (note, 0);
343 else
344 {
345 rtx expr = copy_rtx (single_set_for_csa (last_sp_set));
346
347 XEXP (SET_SRC (expr), 1)
348 = GEN_INT (INTVAL (XEXP (SET_SRC (expr), 1)) - this_adjust);
349 RTX_FRAME_RELATED_P (expr) = 1;
350 XVECEXP (new_expr, 0, 0) = expr;
351 }
352 }
353
354 XVECEXP (new_expr, 0, XVECLEN (new_expr, 0) - 1)
355 = copy_rtx (single_set_for_csa (insn));
356 RTX_FRAME_RELATED_P (XVECEXP (new_expr, 0, XVECLEN (new_expr, 0) - 1))
357 = RTX_FRAME_RELATED_P (insn);
358 if (note)
359 XEXP (note, 0) = new_expr;
360 else
efc0b2bd 361 add_reg_note (last_sp_set, REG_FRAME_RELATED_EXPR, new_expr);
a182fb6b
JJ
362}
363
c7a0240a
SB
364/* Subroutine of combine_stack_adjustments, called for each basic block. */
365
366static void
367combine_stack_adjustments_for_block (basic_block bb)
368{
369 HOST_WIDE_INT last_sp_adjust = 0;
370 rtx last_sp_set = NULL_RTX;
90588a10 371 struct csa_reflist *reflist = NULL;
c7a0240a 372 rtx insn, next, set;
90588a10 373 struct record_stack_refs_data data;
c7a0240a
SB
374 bool end_of_block = false;
375
376 for (insn = BB_HEAD (bb); !end_of_block ; insn = next)
377 {
378 end_of_block = insn == BB_END (bb);
379 next = NEXT_INSN (insn);
380
381 if (! INSN_P (insn))
382 continue;
383
384 set = single_set_for_csa (insn);
385 if (set)
386 {
387 rtx dest = SET_DEST (set);
388 rtx src = SET_SRC (set);
389
390 /* Find constant additions to the stack pointer. */
391 if (dest == stack_pointer_rtx
392 && GET_CODE (src) == PLUS
393 && XEXP (src, 0) == stack_pointer_rtx
481683e1 394 && CONST_INT_P (XEXP (src, 1)))
c7a0240a
SB
395 {
396 HOST_WIDE_INT this_adjust = INTVAL (XEXP (src, 1));
397
398 /* If we've not seen an adjustment previously, record
399 it now and continue. */
400 if (! last_sp_set)
401 {
402 last_sp_set = insn;
403 last_sp_adjust = this_adjust;
404 continue;
405 }
406
90588a10 407 /* If not all recorded refs can be adjusted, or the
c7a0240a
SB
408 adjustment is now too large for a constant addition,
409 we cannot merge the two stack adjustments.
410
411 Also we need to be careful to not move stack pointer
412 such that we create stack accesses outside the allocated
413 area. We can combine an allocation into the first insn,
414 or a deallocation into the second insn. We can not
415 combine an allocation followed by a deallocation.
416
417 The only somewhat frequent occurrence of the later is when
418 a function allocates a stack frame but does not use it.
419 For this case, we would need to analyze rtl stream to be
420 sure that allocated area is really unused. This means not
421 only checking the memory references, but also all registers
422 or global memory references possibly containing a stack
423 frame address.
424
425 Perhaps the best way to address this problem is to teach
426 gcc not to allocate stack for objects never used. */
427
428 /* Combine an allocation into the first instruction. */
429 if (STACK_GROWS_DOWNWARD ? this_adjust <= 0 : this_adjust >= 0)
430 {
90588a10 431 if (try_apply_stack_adjustment (last_sp_set, reflist,
c7a0240a
SB
432 last_sp_adjust + this_adjust,
433 this_adjust))
434 {
a182fb6b
JJ
435 if (RTX_FRAME_RELATED_P (last_sp_set))
436 adjust_frame_related_expr (last_sp_set, insn,
437 this_adjust);
c7a0240a
SB
438 /* It worked! */
439 delete_insn (insn);
440 last_sp_adjust += this_adjust;
441 continue;
442 }
443 }
444
445 /* Otherwise we have a deallocation. Do not combine with
446 a previous allocation. Combine into the second insn. */
447 else if (STACK_GROWS_DOWNWARD
448 ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
449 {
90588a10 450 if (try_apply_stack_adjustment (insn, reflist,
c7a0240a
SB
451 last_sp_adjust + this_adjust,
452 -last_sp_adjust))
453 {
454 /* It worked! */
455 delete_insn (last_sp_set);
456 last_sp_set = insn;
457 last_sp_adjust += this_adjust;
90588a10
JJ
458 free_csa_reflist (reflist);
459 reflist = NULL;
c7a0240a
SB
460 continue;
461 }
462 }
463
464 /* Combination failed. Restart processing from here. If
465 deallocation+allocation conspired to cancel, we can
466 delete the old deallocation insn. */
467 if (last_sp_set && last_sp_adjust == 0)
a182fb6b 468 delete_insn (last_sp_set);
90588a10
JJ
469 free_csa_reflist (reflist);
470 reflist = NULL;
c7a0240a
SB
471 last_sp_set = insn;
472 last_sp_adjust = this_adjust;
473 continue;
474 }
475
1362aa31
EB
476 /* Find a store with pre-(dec|inc)rement or pre-modify of exactly
477 the previous adjustment and turn it into a simple store. This
478 is equivalent to anticipating the stack adjustment so this must
479 be an allocation. */
480 if (MEM_P (dest)
481 && ((STACK_GROWS_DOWNWARD
482 ? (GET_CODE (XEXP (dest, 0)) == PRE_DEC
483 && last_sp_adjust
484 == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest)))
485 : (GET_CODE (XEXP (dest, 0)) == PRE_INC
486 && last_sp_adjust
487 == -(HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest))))
488 || ((STACK_GROWS_DOWNWARD
489 ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
490 && GET_CODE (XEXP (dest, 0)) == PRE_MODIFY
c7a0240a 491 && GET_CODE (XEXP (XEXP (dest, 0), 1)) == PLUS
1362aa31
EB
492 && XEXP (XEXP (XEXP (dest, 0), 1), 0)
493 == stack_pointer_rtx
494 && GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
495 == CONST_INT
496 && INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1))
497 == -last_sp_adjust))
c7a0240a 498 && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx
1362aa31 499 && !reg_mentioned_p (stack_pointer_rtx, src)
c7a0240a 500 && memory_address_p (GET_MODE (dest), stack_pointer_rtx)
1362aa31
EB
501 && try_apply_stack_adjustment (insn, reflist, 0,
502 -last_sp_adjust))
c7a0240a
SB
503 {
504 delete_insn (last_sp_set);
90588a10
JJ
505 free_csa_reflist (reflist);
506 reflist = NULL;
c7a0240a
SB
507 last_sp_set = NULL_RTX;
508 last_sp_adjust = 0;
509 continue;
510 }
511 }
512
513 data.insn = insn;
90588a10 514 data.reflist = reflist;
c7a0240a 515 if (!CALL_P (insn) && last_sp_set
90588a10 516 && !for_each_rtx (&PATTERN (insn), record_stack_refs, &data))
c7a0240a 517 {
90588a10 518 reflist = data.reflist;
c7a0240a
SB
519 continue;
520 }
90588a10 521 reflist = data.reflist;
c7a0240a
SB
522
523 /* Otherwise, we were not able to process the instruction.
524 Do not continue collecting data across such a one. */
525 if (last_sp_set
526 && (CALL_P (insn)
527 || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
528 {
529 if (last_sp_set && last_sp_adjust == 0)
530 delete_insn (last_sp_set);
90588a10
JJ
531 free_csa_reflist (reflist);
532 reflist = NULL;
c7a0240a
SB
533 last_sp_set = NULL_RTX;
534 last_sp_adjust = 0;
535 }
536 }
537
538 if (last_sp_set && last_sp_adjust == 0)
539 delete_insn (last_sp_set);
540
90588a10
JJ
541 if (reflist)
542 free_csa_reflist (reflist);
c7a0240a
SB
543}
544\f
545
546static bool
547gate_handle_stack_adjustments (void)
548{
ccaeeafe 549 return flag_combine_stack_adjustments;
c7a0240a
SB
550}
551
552static unsigned int
553rest_of_handle_stack_adjustments (void)
554{
6fb5fa3c 555 cleanup_cfg (flag_crossjumping ? CLEANUP_CROSSJUMP : 0);
c7a0240a
SB
556
557 /* This is kind of a heuristic. We need to run combine_stack_adjustments
079e7538 558 even for machines with possibly nonzero TARGET_RETURN_POPS_ARGS
c7a0240a
SB
559 and ACCUMULATE_OUTGOING_ARGS. We expect that only ports having
560 push instructions will have popping returns. */
561#ifndef PUSH_ROUNDING
562 if (!ACCUMULATE_OUTGOING_ARGS)
563#endif
6fb5fa3c
DB
564 {
565 df_note_add_problem ();
566 df_analyze ();
567 combine_stack_adjustments ();
568 }
c7a0240a
SB
569 return 0;
570}
571
8ddbbcae 572struct rtl_opt_pass pass_stack_adjustments =
c7a0240a 573{
8ddbbcae
JH
574 {
575 RTL_PASS,
c7a0240a
SB
576 "csa", /* name */
577 gate_handle_stack_adjustments, /* gate */
578 rest_of_handle_stack_adjustments, /* execute */
579 NULL, /* sub */
580 NULL, /* next */
581 0, /* static_pass_number */
756b65f5 582 TV_COMBINE_STACK_ADJUST, /* tv_id */
c7a0240a
SB
583 0, /* properties_required */
584 0, /* properties_provided */
585 0, /* properties_destroyed */
586 0, /* todo_flags_start */
a36b8a1e 587 TODO_df_finish | TODO_verify_rtl_sharing |
c7a0240a
SB
588 TODO_dump_func |
589 TODO_ggc_collect, /* todo_flags_finish */
8ddbbcae 590 }
c7a0240a 591};
This page took 0.905211 seconds and 5 git commands to generate.