]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/combine-stack-adj.c
Update copyright years.
[thirdparty/gcc.git] / gcc / combine-stack-adj.c
CommitLineData
c7a0240a 1/* Combine stack adjustments.
818ab71a 2 Copyright (C) 1987-2016 Free Software Foundation, Inc.
c7a0240a
SB
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
9dcd6f09 8Software Foundation; either version 3, or (at your option) any later
c7a0240a
SB
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
9dcd6f09
NC
17along with GCC; see the file COPYING3. If not see
18<http://www.gnu.org/licenses/>. */
c7a0240a
SB
19
20/* Track stack adjustments and stack memory references. Attempt to
21 reduce the number of stack adjustments by back-propagating across
22 the memory references.
23
24 This is intended primarily for use with targets that do not define
25 ACCUMULATE_OUTGOING_ARGS. It is of significantly more value to
26 targets that define PREFERRED_STACK_BOUNDARY more aligned than
27 STACK_BOUNDARY (e.g. x86), or if not all registers can be pushed
28 (e.g. x86 fp regs) which would ordinarily have to be implemented
29 as a sub/mov pair due to restrictions in calls.c.
30
31 Propagation stops when any of the insns that need adjusting are
32 (a) no longer valid because we've exceeded their range, (b) a
33 non-trivial push instruction, or (c) a call instruction.
34
35 Restriction B is based on the assumption that push instructions
36 are smaller or faster. If a port really wants to remove all
37 pushes, it should have defined ACCUMULATE_OUTGOING_ARGS. The
38 one exception that is made is for an add immediately followed
39 by a push. */
40
41#include "config.h"
42#include "system.h"
43#include "coretypes.h"
c7131fb2 44#include "backend.h"
c7a0240a 45#include "rtl.h"
c7131fb2 46#include "df.h"
c7a0240a 47#include "insn-config.h"
957060b5
AM
48#include "emit-rtl.h"
49#include "recog.h"
60393bbc 50#include "cfgrtl.h"
c7a0240a 51#include "tree-pass.h"
f8305d18 52#include "rtl-iter.h"
c7a0240a
SB
53
54\f
90588a10
JJ
55/* This structure records two kinds of stack references between stack
56 adjusting instructions: stack references in memory addresses for
57 regular insns and all stack references for debug insns. */
c7a0240a 58
90588a10 59struct csa_reflist
c7a0240a
SB
60{
61 HOST_WIDE_INT sp_offset;
71e88baf
DM
62 rtx_insn *insn;
63 rtx *ref;
90588a10 64 struct csa_reflist *next;
c7a0240a
SB
65};
66
67static int stack_memref_p (rtx);
71e88baf 68static rtx single_set_for_csa (rtx_insn *);
90588a10 69static void free_csa_reflist (struct csa_reflist *);
71e88baf 70static struct csa_reflist *record_one_stack_ref (rtx_insn *, rtx *,
90588a10 71 struct csa_reflist *);
71e88baf 72static int try_apply_stack_adjustment (rtx_insn *, struct csa_reflist *,
c7a0240a
SB
73 HOST_WIDE_INT, HOST_WIDE_INT);
74static void combine_stack_adjustments_for_block (basic_block);
c7a0240a
SB
75
76
77/* Main entry point for stack adjustment combination. */
78
79static void
80combine_stack_adjustments (void)
81{
82 basic_block bb;
83
11cd3bed 84 FOR_EACH_BB_FN (bb, cfun)
c7a0240a
SB
85 combine_stack_adjustments_for_block (bb);
86}
87
88/* Recognize a MEM of the form (sp) or (plus sp const). */
89
90static int
91stack_memref_p (rtx x)
92{
93 if (!MEM_P (x))
94 return 0;
95 x = XEXP (x, 0);
96
97 if (x == stack_pointer_rtx)
98 return 1;
99 if (GET_CODE (x) == PLUS
100 && XEXP (x, 0) == stack_pointer_rtx
481683e1 101 && CONST_INT_P (XEXP (x, 1)))
c7a0240a
SB
102 return 1;
103
104 return 0;
105}
106
107/* Recognize either normal single_set or the hack in i386.md for
108 tying fp and sp adjustments. */
109
110static rtx
71e88baf 111single_set_for_csa (rtx_insn *insn)
c7a0240a
SB
112{
113 int i;
114 rtx tmp = single_set (insn);
115 if (tmp)
116 return tmp;
117
118 if (!NONJUMP_INSN_P (insn)
119 || GET_CODE (PATTERN (insn)) != PARALLEL)
120 return NULL_RTX;
121
122 tmp = PATTERN (insn);
123 if (GET_CODE (XVECEXP (tmp, 0, 0)) != SET)
124 return NULL_RTX;
125
126 for (i = 1; i < XVECLEN (tmp, 0); ++i)
127 {
48c54229 128 rtx this_rtx = XVECEXP (tmp, 0, i);
c7a0240a
SB
129
130 /* The special case is allowing a no-op set. */
48c54229
KG
131 if (GET_CODE (this_rtx) == SET
132 && SET_SRC (this_rtx) == SET_DEST (this_rtx))
c7a0240a 133 ;
48c54229
KG
134 else if (GET_CODE (this_rtx) != CLOBBER
135 && GET_CODE (this_rtx) != USE)
c7a0240a
SB
136 return NULL_RTX;
137 }
138
139 return XVECEXP (tmp, 0, 0);
140}
141
90588a10 142/* Free the list of csa_reflist nodes. */
c7a0240a
SB
143
144static void
90588a10 145free_csa_reflist (struct csa_reflist *reflist)
c7a0240a 146{
90588a10
JJ
147 struct csa_reflist *next;
148 for (; reflist ; reflist = next)
c7a0240a 149 {
90588a10
JJ
150 next = reflist->next;
151 free (reflist);
c7a0240a
SB
152 }
153}
154
90588a10
JJ
155/* Create a new csa_reflist node from the given stack reference.
156 It is already known that the reference is either a MEM satisfying the
157 predicate stack_memref_p or a REG representing the stack pointer. */
c7a0240a 158
90588a10 159static struct csa_reflist *
71e88baf 160record_one_stack_ref (rtx_insn *insn, rtx *ref, struct csa_reflist *next_reflist)
c7a0240a 161{
90588a10 162 struct csa_reflist *ml;
c7a0240a 163
90588a10 164 ml = XNEW (struct csa_reflist);
c7a0240a 165
90588a10 166 if (REG_P (*ref) || XEXP (*ref, 0) == stack_pointer_rtx)
c7a0240a
SB
167 ml->sp_offset = 0;
168 else
90588a10 169 ml->sp_offset = INTVAL (XEXP (XEXP (*ref, 0), 1));
c7a0240a
SB
170
171 ml->insn = insn;
90588a10
JJ
172 ml->ref = ref;
173 ml->next = next_reflist;
c7a0240a
SB
174
175 return ml;
176}
177
3dce0964
RH
178/* We only know how to adjust the CFA; no other frame-related changes
179 may appear in any insn to be deleted. */
180
181static bool
182no_unhandled_cfa (rtx_insn *insn)
183{
184 if (!RTX_FRAME_RELATED_P (insn))
185 return true;
186
187 /* No CFA notes at all is a legacy interpretation like
188 FRAME_RELATED_EXPR, and is context sensitive within
189 the prologue state machine. We can't handle that here. */
190 bool has_cfa_adjust = false;
191
192 for (rtx link = REG_NOTES (insn); link; link = XEXP (link, 1))
193 switch (REG_NOTE_KIND (link))
194 {
195 default:
196 break;
197 case REG_CFA_ADJUST_CFA:
198 has_cfa_adjust = true;
199 break;
200
201 case REG_FRAME_RELATED_EXPR:
202 case REG_CFA_DEF_CFA:
203 case REG_CFA_OFFSET:
204 case REG_CFA_REGISTER:
205 case REG_CFA_EXPRESSION:
206 case REG_CFA_RESTORE:
207 case REG_CFA_SET_VDRAP:
208 case REG_CFA_WINDOW_SAVE:
209 case REG_CFA_FLUSH_QUEUE:
210 return false;
211 }
212
213 return has_cfa_adjust;
214}
215
c7a0240a 216/* Attempt to apply ADJUST to the stack adjusting insn INSN, as well
90588a10
JJ
217 as each of the memories and stack references in REFLIST. Return true
218 on success. */
c7a0240a
SB
219
220static int
71e88baf 221try_apply_stack_adjustment (rtx_insn *insn, struct csa_reflist *reflist,
90588a10 222 HOST_WIDE_INT new_adjust, HOST_WIDE_INT delta)
c7a0240a 223{
90588a10 224 struct csa_reflist *ml;
c7a0240a
SB
225 rtx set;
226
227 set = single_set_for_csa (insn);
1362aa31
EB
228 if (MEM_P (SET_DEST (set)))
229 validate_change (insn, &SET_DEST (set),
230 replace_equiv_address (SET_DEST (set), stack_pointer_rtx),
231 1);
232 else
233 validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (new_adjust), 1);
c7a0240a 234
90588a10
JJ
235 for (ml = reflist; ml ; ml = ml->next)
236 {
0a81f074
RS
237 rtx new_addr = plus_constant (Pmode, stack_pointer_rtx,
238 ml->sp_offset - delta);
90588a10
JJ
239 rtx new_val;
240
241 if (MEM_P (*ml->ref))
242 new_val = replace_equiv_address_nv (*ml->ref, new_addr);
243 else if (GET_MODE (*ml->ref) == GET_MODE (stack_pointer_rtx))
244 new_val = new_addr;
245 else
246 new_val = lowpart_subreg (GET_MODE (*ml->ref), new_addr,
247 GET_MODE (new_addr));
248 validate_change (ml->insn, ml->ref, new_val, 1);
249 }
c7a0240a
SB
250
251 if (apply_change_group ())
252 {
90588a10
JJ
253 /* Succeeded. Update our knowledge of the stack references. */
254 for (ml = reflist; ml ; ml = ml->next)
c7a0240a
SB
255 ml->sp_offset -= delta;
256
257 return 1;
258 }
259 else
260 return 0;
261}
262
f8305d18
RS
263/* For non-debug insns, record all stack memory references in INSN
264 and return true if there were no other (unrecorded) references to the
265 stack pointer. For debug insns, record all stack references regardless
266 of context and unconditionally return true. */
c7a0240a 267
f8305d18
RS
268static bool
269record_stack_refs (rtx_insn *insn, struct csa_reflist **reflist)
c7a0240a 270{
f8305d18
RS
271 subrtx_ptr_iterator::array_type array;
272 FOR_EACH_SUBRTX_PTR (iter, array, &PATTERN (insn), NONCONST)
c7a0240a 273 {
f8305d18
RS
274 rtx *loc = *iter;
275 rtx x = *loc;
276 switch (GET_CODE (x))
90588a10 277 {
f8305d18
RS
278 case MEM:
279 if (!reg_mentioned_p (stack_pointer_rtx, x))
280 iter.skip_subrtxes ();
281 /* We are not able to handle correctly all possible memrefs
282 containing stack pointer, so this check is necessary. */
283 else if (stack_memref_p (x))
284 {
285 *reflist = record_one_stack_ref (insn, loc, *reflist);
286 iter.skip_subrtxes ();
287 }
288 /* Try harder for DEBUG_INSNs, handle e.g.
289 (mem (mem (sp + 16) + 4). */
290 else if (!DEBUG_INSN_P (insn))
291 return false;
292 break;
293
294 case REG:
295 /* ??? We want be able to handle non-memory stack pointer
296 references later. For now just discard all insns referring to
297 stack pointer outside mem expressions. We would probably
298 want to teach validate_replace to simplify expressions first.
299
300 We can't just compare with STACK_POINTER_RTX because the
301 reference to the stack pointer might be in some other mode.
302 In particular, an explicit clobber in an asm statement will
303 result in a QImode clobber.
304
305 In DEBUG_INSNs, we want to replace all occurrences, otherwise
306 they will cause -fcompare-debug failures. */
307 if (REGNO (x) == STACK_POINTER_REGNUM)
308 {
309 if (!DEBUG_INSN_P (insn))
310 return false;
311 *reflist = record_one_stack_ref (insn, loc, *reflist);
312 }
313 break;
314
315 default:
316 break;
90588a10 317 }
c7a0240a 318 }
f8305d18 319 return true;
c7a0240a
SB
320}
321
4efb91df
RH
322/* If INSN has a REG_ARGS_SIZE note, move it to LAST.
323 AFTER is true iff LAST follows INSN in the instruction stream. */
a182fb6b
JJ
324
325static void
71e88baf 326maybe_move_args_size_note (rtx_insn *last, rtx_insn *insn, bool after)
a182fb6b 327{
9a08d230 328 rtx note, last_note;
a182fb6b 329
9a08d230
RH
330 note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
331 if (note == NULL)
a182fb6b
JJ
332 return;
333
9a08d230
RH
334 last_note = find_reg_note (last, REG_ARGS_SIZE, NULL_RTX);
335 if (last_note)
4efb91df
RH
336 {
337 /* The ARGS_SIZE notes are *not* cumulative. They represent an
338 absolute value, and the "most recent" note wins. */
339 if (!after)
340 XEXP (last_note, 0) = XEXP (note, 0);
341 }
a182fb6b 342 else
9a08d230 343 add_reg_note (last, REG_ARGS_SIZE, XEXP (note, 0));
a182fb6b
JJ
344}
345
3dce0964
RH
346/* Merge any REG_CFA_ADJUST_CFA note from SRC into DST.
347 AFTER is true iff DST follows SRC in the instruction stream. */
348
349static void
350maybe_merge_cfa_adjust (rtx_insn *dst, rtx_insn *src, bool after)
351{
352 rtx snote = NULL, dnote = NULL;
353 rtx sexp, dexp;
354 rtx exp1, exp2;
355
356 if (RTX_FRAME_RELATED_P (src))
357 snote = find_reg_note (src, REG_CFA_ADJUST_CFA, NULL_RTX);
358 if (snote == NULL)
359 return;
360 sexp = XEXP (snote, 0);
361
362 if (RTX_FRAME_RELATED_P (dst))
363 dnote = find_reg_note (dst, REG_CFA_ADJUST_CFA, NULL_RTX);
364 if (dnote == NULL)
365 {
366 add_reg_note (dst, REG_CFA_ADJUST_CFA, sexp);
367 return;
368 }
369 dexp = XEXP (dnote, 0);
370
371 gcc_assert (GET_CODE (sexp) == SET);
372 gcc_assert (GET_CODE (dexp) == SET);
373
374 if (after)
375 exp1 = dexp, exp2 = sexp;
376 else
377 exp1 = sexp, exp2 = dexp;
378
379 SET_SRC (exp1) = simplify_replace_rtx (SET_SRC (exp1), SET_DEST (exp2),
380 SET_SRC (exp2));
381 XEXP (dnote, 0) = exp1;
382}
383
3825692d
RH
384/* Return the next (or previous) active insn within BB. */
385
71e88baf
DM
386static rtx_insn *
387prev_active_insn_bb (basic_block bb, rtx_insn *insn)
3825692d
RH
388{
389 for (insn = PREV_INSN (insn);
390 insn != PREV_INSN (BB_HEAD (bb));
391 insn = PREV_INSN (insn))
392 if (active_insn_p (insn))
393 return insn;
71e88baf 394 return NULL;
3825692d
RH
395}
396
71e88baf
DM
397static rtx_insn *
398next_active_insn_bb (basic_block bb, rtx_insn *insn)
3825692d
RH
399{
400 for (insn = NEXT_INSN (insn);
401 insn != NEXT_INSN (BB_END (bb));
402 insn = NEXT_INSN (insn))
403 if (active_insn_p (insn))
404 return insn;
71e88baf 405 return NULL;
3825692d
RH
406}
407
408/* If INSN has a REG_ARGS_SIZE note, if possible move it to PREV. Otherwise
409 search for a nearby candidate within BB where we can stick the note. */
410
411static void
71e88baf 412force_move_args_size_note (basic_block bb, rtx_insn *prev, rtx_insn *insn)
3825692d 413{
71e88baf
DM
414 rtx note;
415 rtx_insn *test, *next_candidate, *prev_candidate;
3825692d
RH
416
417 /* If PREV exists, tail-call to the logic in the other function. */
418 if (prev)
419 {
420 maybe_move_args_size_note (prev, insn, false);
421 return;
422 }
423
424 /* First, make sure there's anything that needs doing. */
425 note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
426 if (note == NULL)
427 return;
428
429 /* We need to find a spot between the previous and next exception points
430 where we can place the note and "properly" deallocate the arguments. */
431 next_candidate = prev_candidate = NULL;
432
433 /* It is often the case that we have insns in the order:
434 call
435 add sp (previous deallocation)
436 sub sp (align for next arglist)
437 push arg
438 and the add/sub cancel. Therefore we begin by searching forward. */
439
440 test = insn;
441 while ((test = next_active_insn_bb (bb, test)) != NULL)
442 {
443 /* Found an existing note: nothing to do. */
444 if (find_reg_note (test, REG_ARGS_SIZE, NULL_RTX))
445 return;
446 /* Found something that affects unwinding. Stop searching. */
447 if (CALL_P (test) || !insn_nothrow_p (test))
448 break;
449 if (next_candidate == NULL)
450 next_candidate = test;
451 }
452
453 test = insn;
454 while ((test = prev_active_insn_bb (bb, test)) != NULL)
455 {
456 rtx tnote;
457 /* Found a place that seems logical to adjust the stack. */
458 tnote = find_reg_note (test, REG_ARGS_SIZE, NULL_RTX);
459 if (tnote)
460 {
461 XEXP (tnote, 0) = XEXP (note, 0);
462 return;
463 }
464 if (prev_candidate == NULL)
465 prev_candidate = test;
466 /* Found something that affects unwinding. Stop searching. */
467 if (CALL_P (test) || !insn_nothrow_p (test))
468 break;
469 }
470
471 if (prev_candidate)
472 test = prev_candidate;
473 else if (next_candidate)
474 test = next_candidate;
475 else
476 {
477 /* ??? We *must* have a place, lest we ICE on the lost adjustment.
478 Options are: dummy clobber insn, nop, or prevent the removal of
65c2e636
RH
479 the sp += 0 insn. */
480 /* TODO: Find another way to indicate to the dwarf2 code that we
481 have not in fact lost an adjustment. */
482 test = emit_insn_before (gen_rtx_CLOBBER (VOIDmode, const0_rtx), insn);
3825692d
RH
483 }
484 add_reg_note (test, REG_ARGS_SIZE, XEXP (note, 0));
485}
486
c7a0240a
SB
487/* Subroutine of combine_stack_adjustments, called for each basic block. */
488
489static void
490combine_stack_adjustments_for_block (basic_block bb)
491{
492 HOST_WIDE_INT last_sp_adjust = 0;
71e88baf
DM
493 rtx_insn *last_sp_set = NULL;
494 rtx_insn *last2_sp_set = NULL;
90588a10 495 struct csa_reflist *reflist = NULL;
71e88baf
DM
496 rtx_insn *insn, *next;
497 rtx set;
c7a0240a
SB
498 bool end_of_block = false;
499
500 for (insn = BB_HEAD (bb); !end_of_block ; insn = next)
501 {
502 end_of_block = insn == BB_END (bb);
503 next = NEXT_INSN (insn);
504
505 if (! INSN_P (insn))
506 continue;
507
508 set = single_set_for_csa (insn);
509 if (set)
510 {
511 rtx dest = SET_DEST (set);
512 rtx src = SET_SRC (set);
513
514 /* Find constant additions to the stack pointer. */
515 if (dest == stack_pointer_rtx
516 && GET_CODE (src) == PLUS
517 && XEXP (src, 0) == stack_pointer_rtx
481683e1 518 && CONST_INT_P (XEXP (src, 1)))
c7a0240a
SB
519 {
520 HOST_WIDE_INT this_adjust = INTVAL (XEXP (src, 1));
521
522 /* If we've not seen an adjustment previously, record
523 it now and continue. */
524 if (! last_sp_set)
525 {
526 last_sp_set = insn;
527 last_sp_adjust = this_adjust;
528 continue;
529 }
530
90588a10 531 /* If not all recorded refs can be adjusted, or the
c7a0240a
SB
532 adjustment is now too large for a constant addition,
533 we cannot merge the two stack adjustments.
534
535 Also we need to be careful to not move stack pointer
536 such that we create stack accesses outside the allocated
537 area. We can combine an allocation into the first insn,
538 or a deallocation into the second insn. We can not
539 combine an allocation followed by a deallocation.
540
541 The only somewhat frequent occurrence of the later is when
542 a function allocates a stack frame but does not use it.
543 For this case, we would need to analyze rtl stream to be
544 sure that allocated area is really unused. This means not
545 only checking the memory references, but also all registers
546 or global memory references possibly containing a stack
547 frame address.
548
549 Perhaps the best way to address this problem is to teach
550 gcc not to allocate stack for objects never used. */
551
552 /* Combine an allocation into the first instruction. */
553 if (STACK_GROWS_DOWNWARD ? this_adjust <= 0 : this_adjust >= 0)
554 {
3dce0964
RH
555 if (no_unhandled_cfa (insn)
556 && try_apply_stack_adjustment (last_sp_set, reflist,
557 last_sp_adjust
558 + this_adjust,
559 this_adjust))
c7a0240a
SB
560 {
561 /* It worked! */
3825692d 562 maybe_move_args_size_note (last_sp_set, insn, false);
3dce0964 563 maybe_merge_cfa_adjust (last_sp_set, insn, false);
c7a0240a
SB
564 delete_insn (insn);
565 last_sp_adjust += this_adjust;
566 continue;
567 }
568 }
569
570 /* Otherwise we have a deallocation. Do not combine with
571 a previous allocation. Combine into the second insn. */
572 else if (STACK_GROWS_DOWNWARD
573 ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
574 {
3dce0964
RH
575 if (no_unhandled_cfa (last_sp_set)
576 && try_apply_stack_adjustment (insn, reflist,
577 last_sp_adjust
578 + this_adjust,
579 -last_sp_adjust))
c7a0240a
SB
580 {
581 /* It worked! */
3825692d 582 maybe_move_args_size_note (insn, last_sp_set, true);
3dce0964 583 maybe_merge_cfa_adjust (insn, last_sp_set, true);
c7a0240a
SB
584 delete_insn (last_sp_set);
585 last_sp_set = insn;
586 last_sp_adjust += this_adjust;
90588a10
JJ
587 free_csa_reflist (reflist);
588 reflist = NULL;
c7a0240a
SB
589 continue;
590 }
591 }
592
593 /* Combination failed. Restart processing from here. If
594 deallocation+allocation conspired to cancel, we can
595 delete the old deallocation insn. */
3825692d
RH
596 if (last_sp_set)
597 {
3dce0964 598 if (last_sp_adjust == 0 && no_unhandled_cfa (last_sp_set))
3825692d
RH
599 {
600 maybe_move_args_size_note (insn, last_sp_set, true);
3dce0964 601 maybe_merge_cfa_adjust (insn, last_sp_set, true);
3825692d
RH
602 delete_insn (last_sp_set);
603 }
604 else
605 last2_sp_set = last_sp_set;
606 }
90588a10
JJ
607 free_csa_reflist (reflist);
608 reflist = NULL;
c7a0240a
SB
609 last_sp_set = insn;
610 last_sp_adjust = this_adjust;
611 continue;
612 }
613
1362aa31
EB
614 /* Find a store with pre-(dec|inc)rement or pre-modify of exactly
615 the previous adjustment and turn it into a simple store. This
616 is equivalent to anticipating the stack adjustment so this must
617 be an allocation. */
618 if (MEM_P (dest)
619 && ((STACK_GROWS_DOWNWARD
620 ? (GET_CODE (XEXP (dest, 0)) == PRE_DEC
621 && last_sp_adjust
622 == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest)))
623 : (GET_CODE (XEXP (dest, 0)) == PRE_INC
624 && last_sp_adjust
625 == -(HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest))))
626 || ((STACK_GROWS_DOWNWARD
627 ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
628 && GET_CODE (XEXP (dest, 0)) == PRE_MODIFY
c7a0240a 629 && GET_CODE (XEXP (XEXP (dest, 0), 1)) == PLUS
1362aa31
EB
630 && XEXP (XEXP (XEXP (dest, 0), 1), 0)
631 == stack_pointer_rtx
632 && GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
633 == CONST_INT
634 && INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1))
635 == -last_sp_adjust))
c7a0240a 636 && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx
1362aa31 637 && !reg_mentioned_p (stack_pointer_rtx, src)
c7a0240a 638 && memory_address_p (GET_MODE (dest), stack_pointer_rtx)
1362aa31
EB
639 && try_apply_stack_adjustment (insn, reflist, 0,
640 -last_sp_adjust))
c7a0240a 641 {
3825692d
RH
642 if (last2_sp_set)
643 maybe_move_args_size_note (last2_sp_set, last_sp_set, false);
644 else
645 maybe_move_args_size_note (insn, last_sp_set, true);
c7a0240a 646 delete_insn (last_sp_set);
90588a10
JJ
647 free_csa_reflist (reflist);
648 reflist = NULL;
71e88baf 649 last_sp_set = NULL;
c7a0240a
SB
650 last_sp_adjust = 0;
651 continue;
652 }
653 }
654
c7a0240a 655 if (!CALL_P (insn) && last_sp_set
f8305d18
RS
656 && record_stack_refs (insn, &reflist))
657 continue;
c7a0240a
SB
658
659 /* Otherwise, we were not able to process the instruction.
660 Do not continue collecting data across such a one. */
661 if (last_sp_set
662 && (CALL_P (insn)
663 || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
664 {
665 if (last_sp_set && last_sp_adjust == 0)
3825692d
RH
666 {
667 force_move_args_size_note (bb, last2_sp_set, last_sp_set);
668 delete_insn (last_sp_set);
669 }
90588a10
JJ
670 free_csa_reflist (reflist);
671 reflist = NULL;
71e88baf
DM
672 last2_sp_set = NULL;
673 last_sp_set = NULL;
c7a0240a
SB
674 last_sp_adjust = 0;
675 }
676 }
677
678 if (last_sp_set && last_sp_adjust == 0)
3825692d
RH
679 {
680 force_move_args_size_note (bb, last2_sp_set, last_sp_set);
681 delete_insn (last_sp_set);
682 }
c7a0240a 683
90588a10
JJ
684 if (reflist)
685 free_csa_reflist (reflist);
c7a0240a
SB
686}
687\f
11a687e7
RH
688static unsigned int
689rest_of_handle_stack_adjustments (void)
690{
691 df_note_add_problem ();
692 df_analyze ();
693 combine_stack_adjustments ();
c7a0240a
SB
694 return 0;
695}
696
27a4cd48
DM
697namespace {
698
699const pass_data pass_data_stack_adjustments =
c7a0240a 700{
27a4cd48
DM
701 RTL_PASS, /* type */
702 "csa", /* name */
703 OPTGROUP_NONE, /* optinfo_flags */
27a4cd48
DM
704 TV_COMBINE_STACK_ADJUST, /* tv_id */
705 0, /* properties_required */
706 0, /* properties_provided */
707 0, /* properties_destroyed */
708 0, /* todo_flags_start */
3bea341f 709 TODO_df_finish, /* todo_flags_finish */
c7a0240a 710};
27a4cd48
DM
711
712class pass_stack_adjustments : public rtl_opt_pass
713{
714public:
c3284718
RS
715 pass_stack_adjustments (gcc::context *ctxt)
716 : rtl_opt_pass (pass_data_stack_adjustments, ctxt)
27a4cd48
DM
717 {}
718
719 /* opt_pass methods: */
1a3d085c 720 virtual bool gate (function *);
be55bfe6
TS
721 virtual unsigned int execute (function *)
722 {
723 return rest_of_handle_stack_adjustments ();
724 }
27a4cd48
DM
725
726}; // class pass_stack_adjustments
727
1a3d085c
TS
728bool
729pass_stack_adjustments::gate (function *)
730{
731 /* This is kind of a heuristic. We need to run combine_stack_adjustments
732 even for machines with possibly nonzero TARGET_RETURN_POPS_ARGS
733 and ACCUMULATE_OUTGOING_ARGS. We expect that only ports having
734 push instructions will have popping returns. */
735#ifndef PUSH_ROUNDING
736 if (ACCUMULATE_OUTGOING_ARGS)
737 return false;
738#endif
739 return flag_combine_stack_adjustments;
740}
741
27a4cd48
DM
742} // anon namespace
743
744rtl_opt_pass *
745make_pass_stack_adjustments (gcc::context *ctxt)
746{
747 return new pass_stack_adjustments (ctxt);
748}