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