Mercurial > hg > CbC > CbC_gcc
annotate gcc/combine-stack-adj.c @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | 04ced10e8804 |
children | 1830386684a0 |
rev | line source |
---|---|
0 | 1 /* Combine stack adjustments. |
131 | 2 Copyright (C) 1987-2018 Free Software Foundation, Inc. |
0 | 3 |
4 This file is part of GCC. | |
5 | |
6 GCC is free software; you can redistribute it and/or modify it under | |
7 the terms of the GNU General Public License as published by the Free | |
8 Software Foundation; either version 3, or (at your option) any later | |
9 version. | |
10 | |
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with GCC; see the file COPYING3. If not see | |
18 <http://www.gnu.org/licenses/>. */ | |
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" | |
111 | 44 #include "backend.h" |
0 | 45 #include "rtl.h" |
111 | 46 #include "df.h" |
0 | 47 #include "insn-config.h" |
111 | 48 #include "memmodel.h" |
49 #include "emit-rtl.h" | |
0 | 50 #include "recog.h" |
111 | 51 #include "cfgrtl.h" |
0 | 52 #include "tree-pass.h" |
111 | 53 #include "rtl-iter.h" |
0 | 54 |
55 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
56 /* This structure records two kinds of stack references between stack |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
57 adjusting instructions: stack references in memory addresses for |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
58 regular insns and all stack references for debug insns. */ |
0 | 59 |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
60 struct csa_reflist |
0 | 61 { |
62 HOST_WIDE_INT sp_offset; | |
111 | 63 rtx_insn *insn; |
64 rtx *ref; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
65 struct csa_reflist *next; |
0 | 66 }; |
67 | |
68 static int stack_memref_p (rtx); | |
111 | 69 static rtx single_set_for_csa (rtx_insn *); |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
70 static void free_csa_reflist (struct csa_reflist *); |
111 | 71 static struct csa_reflist *record_one_stack_ref (rtx_insn *, rtx *, |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
72 struct csa_reflist *); |
111 | 73 static int try_apply_stack_adjustment (rtx_insn *, struct csa_reflist *, |
0 | 74 HOST_WIDE_INT, HOST_WIDE_INT); |
75 static void combine_stack_adjustments_for_block (basic_block); | |
76 | |
77 | |
78 /* Main entry point for stack adjustment combination. */ | |
79 | |
80 static void | |
81 combine_stack_adjustments (void) | |
82 { | |
83 basic_block bb; | |
84 | |
111 | 85 FOR_EACH_BB_FN (bb, cfun) |
0 | 86 combine_stack_adjustments_for_block (bb); |
87 } | |
88 | |
89 /* Recognize a MEM of the form (sp) or (plus sp const). */ | |
90 | |
91 static int | |
92 stack_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 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
102 && CONST_INT_P (XEXP (x, 1))) |
0 | 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 | |
111 static rtx | |
111 | 112 single_set_for_csa (rtx_insn *insn) |
0 | 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 { | |
129 rtx this_rtx = XVECEXP (tmp, 0, i); | |
130 | |
131 /* The special case is allowing a no-op set. */ | |
132 if (GET_CODE (this_rtx) == SET | |
133 && SET_SRC (this_rtx) == SET_DEST (this_rtx)) | |
134 ; | |
135 else if (GET_CODE (this_rtx) != CLOBBER | |
131 | 136 && GET_CODE (this_rtx) != CLOBBER_HIGH |
0 | 137 && GET_CODE (this_rtx) != USE) |
138 return NULL_RTX; | |
139 } | |
140 | |
141 return XVECEXP (tmp, 0, 0); | |
142 } | |
143 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
144 /* Free the list of csa_reflist nodes. */ |
0 | 145 |
146 static void | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
147 free_csa_reflist (struct csa_reflist *reflist) |
0 | 148 { |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
149 struct csa_reflist *next; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
150 for (; reflist ; reflist = next) |
0 | 151 { |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
152 next = reflist->next; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
153 free (reflist); |
0 | 154 } |
155 } | |
156 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
157 /* Create a new csa_reflist node from the given stack reference. |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
158 It is already known that the reference is either a MEM satisfying the |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
159 predicate stack_memref_p or a REG representing the stack pointer. */ |
0 | 160 |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
161 static struct csa_reflist * |
111 | 162 record_one_stack_ref (rtx_insn *insn, rtx *ref, struct csa_reflist *next_reflist) |
0 | 163 { |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
164 struct csa_reflist *ml; |
0 | 165 |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
166 ml = XNEW (struct csa_reflist); |
0 | 167 |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
168 if (REG_P (*ref) || XEXP (*ref, 0) == stack_pointer_rtx) |
0 | 169 ml->sp_offset = 0; |
170 else | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
171 ml->sp_offset = INTVAL (XEXP (XEXP (*ref, 0), 1)); |
0 | 172 |
173 ml->insn = insn; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
174 ml->ref = ref; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
175 ml->next = next_reflist; |
0 | 176 |
177 return ml; | |
178 } | |
179 | |
111 | 180 /* We only know how to adjust the CFA; no other frame-related changes |
181 may appear in any insn to be deleted. */ | |
182 | |
183 static bool | |
184 no_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: | |
212 case REG_CFA_TOGGLE_RA_MANGLE: | |
213 return false; | |
214 } | |
215 | |
216 return has_cfa_adjust; | |
217 } | |
218 | |
0 | 219 /* Attempt to apply ADJUST to the stack adjusting insn INSN, as well |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
220 as each of the memories and stack references in REFLIST. Return true |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
221 on success. */ |
0 | 222 |
223 static int | |
111 | 224 try_apply_stack_adjustment (rtx_insn *insn, struct csa_reflist *reflist, |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
225 HOST_WIDE_INT new_adjust, HOST_WIDE_INT delta) |
0 | 226 { |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
227 struct csa_reflist *ml; |
0 | 228 rtx set; |
229 | |
230 set = single_set_for_csa (insn); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
231 if (MEM_P (SET_DEST (set))) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
232 validate_change (insn, &SET_DEST (set), |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
233 replace_equiv_address (SET_DEST (set), stack_pointer_rtx), |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
234 1); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
235 else |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
236 validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (new_adjust), 1); |
0 | 237 |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
238 for (ml = reflist; ml ; ml = ml->next) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
239 { |
111 | 240 rtx new_addr = plus_constant (Pmode, stack_pointer_rtx, |
241 ml->sp_offset - delta); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
242 rtx new_val; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
243 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
244 if (MEM_P (*ml->ref)) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
245 new_val = replace_equiv_address_nv (*ml->ref, new_addr); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
246 else if (GET_MODE (*ml->ref) == GET_MODE (stack_pointer_rtx)) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
247 new_val = new_addr; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
248 else |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
249 new_val = lowpart_subreg (GET_MODE (*ml->ref), new_addr, |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
250 GET_MODE (new_addr)); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
251 validate_change (ml->insn, ml->ref, new_val, 1); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
252 } |
0 | 253 |
254 if (apply_change_group ()) | |
255 { | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
256 /* Succeeded. Update our knowledge of the stack references. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
257 for (ml = reflist; ml ; ml = ml->next) |
0 | 258 ml->sp_offset -= delta; |
259 | |
260 return 1; | |
261 } | |
262 else | |
263 return 0; | |
264 } | |
265 | |
111 | 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. */ | |
0 | 270 |
111 | 271 static bool |
272 record_stack_refs (rtx_insn *insn, struct csa_reflist **reflist) | |
0 | 273 { |
111 | 274 subrtx_ptr_iterator::array_type array; |
275 FOR_EACH_SUBRTX_PTR (iter, array, &PATTERN (insn), NONCONST) | |
0 | 276 { |
111 | 277 rtx *loc = *iter; |
278 rtx x = *loc; | |
279 switch (GET_CODE (x)) | |
0 | 280 { |
111 | 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; | |
0 | 320 } |
111 | 321 } |
322 return true; | |
323 } | |
0 | 324 |
111 | 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. */ | |
327 | |
328 static void | |
329 maybe_move_args_size_note (rtx_insn *last, rtx_insn *insn, bool after) | |
330 { | |
331 rtx note, last_note; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
332 |
111 | 333 note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX); |
334 if (note == NULL) | |
335 return; | |
336 | |
337 last_note = find_reg_note (last, REG_ARGS_SIZE, NULL_RTX); | |
338 if (last_note) | |
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); | |
0 | 344 } |
111 | 345 else |
346 add_reg_note (last, REG_ARGS_SIZE, XEXP (note, 0)); | |
0 | 347 } |
348 | |
111 | 349 /* Merge any REG_CFA_ADJUST_CFA note from SRC into DST. |
350 AFTER is true iff DST follows SRC in the instruction stream. */ | |
0 | 351 |
352 static void | |
111 | 353 maybe_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 | |
387 /* Return the next (or previous) active insn within BB. */ | |
388 | |
389 static rtx_insn * | |
390 prev_active_insn_bb (basic_block bb, rtx_insn *insn) | |
0 | 391 { |
111 | 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; | |
397 return NULL; | |
398 } | |
399 | |
400 static rtx_insn * | |
401 next_active_insn_bb (basic_block bb, rtx_insn *insn) | |
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; | |
408 return NULL; | |
409 } | |
0 | 410 |
111 | 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 | |
414 static void | |
415 force_move_args_size_note (basic_block bb, rtx_insn *prev, rtx_insn *insn) | |
416 { | |
417 rtx note; | |
418 rtx_insn *test, *next_candidate, *prev_candidate; | |
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) | |
0 | 430 return; |
431 | |
111 | 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. */ | |
0 | 442 |
111 | 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) | |
0 | 463 { |
111 | 464 XEXP (tnote, 0) = XEXP (note, 0); |
0 | 465 return; |
466 } | |
111 | 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 } | |
0 | 473 |
111 | 474 if (prev_candidate) |
475 test = prev_candidate; | |
476 else if (next_candidate) | |
477 test = next_candidate; | |
0 | 478 else |
479 { | |
111 | 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 | |
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); | |
0 | 486 } |
111 | 487 add_reg_note (test, REG_ARGS_SIZE, XEXP (note, 0)); |
0 | 488 } |
489 | |
490 /* Subroutine of combine_stack_adjustments, called for each basic block. */ | |
491 | |
492 static void | |
493 combine_stack_adjustments_for_block (basic_block bb) | |
494 { | |
495 HOST_WIDE_INT last_sp_adjust = 0; | |
111 | 496 rtx_insn *last_sp_set = NULL; |
497 rtx_insn *last2_sp_set = NULL; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
498 struct csa_reflist *reflist = NULL; |
111 | 499 rtx_insn *insn, *next; |
500 rtx set; | |
0 | 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); | |
111 | 512 if (set && find_reg_note (insn, REG_STACK_CHECK, NULL_RTX)) |
513 set = NULL_RTX; | |
0 | 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 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
523 && CONST_INT_P (XEXP (src, 1))) |
0 | 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 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
536 /* If not all recorded refs can be adjusted, or the |
0 | 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 { | |
111 | 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)) | |
0 | 565 { |
566 /* It worked! */ | |
111 | 567 maybe_move_args_size_note (last_sp_set, insn, false); |
568 maybe_merge_cfa_adjust (last_sp_set, insn, false); | |
0 | 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 { | |
111 | 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)) | |
0 | 585 { |
586 /* It worked! */ | |
111 | 587 maybe_move_args_size_note (insn, last_sp_set, true); |
588 maybe_merge_cfa_adjust (insn, last_sp_set, true); | |
0 | 589 delete_insn (last_sp_set); |
590 last_sp_set = insn; | |
591 last_sp_adjust += this_adjust; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
592 free_csa_reflist (reflist); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
593 reflist = NULL; |
0 | 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. */ | |
111 | 601 if (last_sp_set) |
602 { | |
603 if (last_sp_adjust == 0 && no_unhandled_cfa (last_sp_set)) | |
604 { | |
605 maybe_move_args_size_note (insn, last_sp_set, true); | |
606 maybe_merge_cfa_adjust (insn, last_sp_set, true); | |
607 delete_insn (last_sp_set); | |
608 } | |
609 else | |
610 last2_sp_set = last_sp_set; | |
611 } | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
612 free_csa_reflist (reflist); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
613 reflist = NULL; |
0 | 614 last_sp_set = insn; |
615 last_sp_adjust = this_adjust; | |
616 continue; | |
617 } | |
618 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
619 /* Find a store with pre-(dec|inc)rement or pre-modify of exactly |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
620 the previous adjustment and turn it into a simple store. This |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
621 is equivalent to anticipating the stack adjustment so this must |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
622 be an allocation. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
623 if (MEM_P (dest) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
624 && ((STACK_GROWS_DOWNWARD |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
625 ? (GET_CODE (XEXP (dest, 0)) == PRE_DEC |
131 | 626 && known_eq (last_sp_adjust, |
627 GET_MODE_SIZE (GET_MODE (dest)))) | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
628 : (GET_CODE (XEXP (dest, 0)) == PRE_INC |
131 | 629 && known_eq (-last_sp_adjust, |
630 GET_MODE_SIZE (GET_MODE (dest))))) | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
631 || ((STACK_GROWS_DOWNWARD |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
632 ? last_sp_adjust >= 0 : last_sp_adjust <= 0) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
633 && GET_CODE (XEXP (dest, 0)) == PRE_MODIFY |
0 | 634 && GET_CODE (XEXP (XEXP (dest, 0), 1)) == PLUS |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
635 && XEXP (XEXP (XEXP (dest, 0), 1), 0) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
636 == stack_pointer_rtx |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
637 && GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1)) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
638 == CONST_INT |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
639 && INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1)) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
640 == -last_sp_adjust)) |
0 | 641 && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
642 && !reg_mentioned_p (stack_pointer_rtx, src) |
0 | 643 && memory_address_p (GET_MODE (dest), stack_pointer_rtx) |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
644 && try_apply_stack_adjustment (insn, reflist, 0, |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
645 -last_sp_adjust)) |
0 | 646 { |
111 | 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); | |
0 | 651 delete_insn (last_sp_set); |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
652 free_csa_reflist (reflist); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
653 reflist = NULL; |
111 | 654 last_sp_set = NULL; |
0 | 655 last_sp_adjust = 0; |
656 continue; | |
657 } | |
658 } | |
659 | |
660 if (!CALL_P (insn) && last_sp_set | |
111 | 661 && record_stack_refs (insn, &reflist)) |
662 continue; | |
0 | 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) | |
111 | 671 { |
672 force_move_args_size_note (bb, last2_sp_set, last_sp_set); | |
673 delete_insn (last_sp_set); | |
674 } | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
675 free_csa_reflist (reflist); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
676 reflist = NULL; |
111 | 677 last2_sp_set = NULL; |
678 last_sp_set = NULL; | |
0 | 679 last_sp_adjust = 0; |
680 } | |
681 } | |
682 | |
683 if (last_sp_set && last_sp_adjust == 0) | |
111 | 684 { |
685 force_move_args_size_note (bb, last2_sp_set, last_sp_set); | |
686 delete_insn (last_sp_set); | |
687 } | |
0 | 688 |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
689 if (reflist) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
690 free_csa_reflist (reflist); |
0 | 691 } |
692 | |
693 static unsigned int | |
694 rest_of_handle_stack_adjustments (void) | |
695 { | |
111 | 696 df_note_add_problem (); |
697 df_analyze (); | |
698 combine_stack_adjustments (); | |
699 return 0; | |
700 } | |
701 | |
702 namespace { | |
0 | 703 |
111 | 704 const pass_data pass_data_stack_adjustments = |
705 { | |
706 RTL_PASS, /* type */ | |
707 "csa", /* name */ | |
708 OPTGROUP_NONE, /* optinfo_flags */ | |
709 TV_COMBINE_STACK_ADJUST, /* tv_id */ | |
710 0, /* properties_required */ | |
711 0, /* properties_provided */ | |
712 0, /* properties_destroyed */ | |
713 0, /* todo_flags_start */ | |
714 TODO_df_finish, /* todo_flags_finish */ | |
715 }; | |
716 | |
717 class pass_stack_adjustments : public rtl_opt_pass | |
718 { | |
719 public: | |
720 pass_stack_adjustments (gcc::context *ctxt) | |
721 : rtl_opt_pass (pass_data_stack_adjustments, ctxt) | |
722 {} | |
723 | |
724 /* opt_pass methods: */ | |
725 virtual bool gate (function *); | |
726 virtual unsigned int execute (function *) | |
727 { | |
728 return rest_of_handle_stack_adjustments (); | |
729 } | |
730 | |
731 }; // class pass_stack_adjustments | |
732 | |
733 bool | |
734 pass_stack_adjustments::gate (function *) | |
735 { | |
0 | 736 /* This is kind of a heuristic. We need to run combine_stack_adjustments |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
737 even for machines with possibly nonzero TARGET_RETURN_POPS_ARGS |
0 | 738 and ACCUMULATE_OUTGOING_ARGS. We expect that only ports having |
739 push instructions will have popping returns. */ | |
740 #ifndef PUSH_ROUNDING | |
111 | 741 if (ACCUMULATE_OUTGOING_ARGS) |
742 return false; | |
0 | 743 #endif |
111 | 744 return flag_combine_stack_adjustments; |
0 | 745 } |
746 | |
111 | 747 } // anon namespace |
748 | |
749 rtl_opt_pass * | |
750 make_pass_stack_adjustments (gcc::context *ctxt) | |
0 | 751 { |
111 | 752 return new pass_stack_adjustments (ctxt); |
753 } |