Mercurial > hg > CbC > CbC_gcc
annotate gcc/auto-inc-dec.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 /* Discovery of auto-inc and auto-dec instructions. |
131 | 2 Copyright (C) 2006-2018 Free Software Foundation, Inc. |
0 | 3 Contributed by Kenneth Zadeck <zadeck@naturalbridge.com> |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
4 |
0 | 5 This file is part of GCC. |
6 | |
7 GCC is free software; you can redistribute it and/or modify it under | |
8 the terms of the GNU General Public License as published by the Free | |
9 Software Foundation; either version 3, or (at your option) any later | |
10 version. | |
11 | |
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
18 along with GCC; see the file COPYING3. If not see | |
19 <http://www.gnu.org/licenses/>. */ | |
20 | |
21 #include "config.h" | |
22 #include "system.h" | |
23 #include "coretypes.h" | |
111 | 24 #include "backend.h" |
25 #include "target.h" | |
0 | 26 #include "rtl.h" |
111 | 27 #include "tree.h" |
28 #include "predict.h" | |
29 #include "df.h" | |
0 | 30 #include "insn-config.h" |
111 | 31 #include "memmodel.h" |
32 #include "emit-rtl.h" | |
0 | 33 #include "recog.h" |
111 | 34 #include "cfgrtl.h" |
0 | 35 #include "expr.h" |
36 #include "tree-pass.h" | |
37 #include "dbgcnt.h" | |
111 | 38 #include "print-rtl.h" |
0 | 39 |
40 /* This pass was originally removed from flow.c. However there is | |
41 almost nothing that remains of that code. | |
42 | |
43 There are (4) basic forms that are matched: | |
44 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
45 (1) FORM_PRE_ADD |
0 | 46 a <- b + c |
47 ... | |
48 *a | |
49 | |
50 becomes | |
51 | |
52 a <- b | |
53 ... | |
54 *(a += c) pre | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
55 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
56 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
57 (2) FORM_PRE_INC |
0 | 58 a += c |
59 ... | |
60 *a | |
61 | |
62 becomes | |
63 | |
64 *(a += c) pre | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
65 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
66 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
67 (3) FORM_POST_ADD |
0 | 68 *a |
69 ... | |
70 b <- a + c | |
71 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
72 (For this case to be true, b must not be assigned or used between |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
73 the *a and the assignment to b. B must also be a Pmode reg.) |
0 | 74 |
75 becomes | |
76 | |
77 b <- a | |
78 ... | |
79 *(b += c) post | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
80 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
81 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
82 (4) FORM_POST_INC |
0 | 83 *a |
84 ... | |
85 a <- a + c | |
86 | |
87 becomes | |
88 | |
89 *(a += c) post | |
90 | |
91 There are three types of values of c. | |
92 | |
93 1) c is a constant equal to the width of the value being accessed by | |
94 the pointer. This is useful for machines that have | |
95 HAVE_PRE_INCREMENT, HAVE_POST_INCREMENT, HAVE_PRE_DECREMENT or | |
96 HAVE_POST_DECREMENT defined. | |
97 | |
98 2) c is a constant not equal to the width of the value being accessed | |
99 by the pointer. This is useful for machines that have | |
100 HAVE_PRE_MODIFY_DISP, HAVE_POST_MODIFY_DISP defined. | |
101 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
102 3) c is a register. This is useful for machines that have |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
103 HAVE_PRE_MODIFY_REG, HAVE_POST_MODIFY_REG |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
104 |
0 | 105 The is one special case: if a already had an offset equal to it +- |
106 its width and that offset is equal to -c when the increment was | |
107 before the ref or +c if the increment was after the ref, then if we | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
108 can do the combination but switch the pre/post bit. */ |
0 | 109 |
110 | |
111 enum form | |
112 { | |
113 FORM_PRE_ADD, | |
114 FORM_PRE_INC, | |
115 FORM_POST_ADD, | |
116 FORM_POST_INC, | |
117 FORM_last | |
118 }; | |
119 | |
120 /* The states of the second operands of mem refs and inc insns. If no | |
121 second operand of the mem_ref was found, it is assumed to just be | |
122 ZERO. SIZE is the size of the mode accessed in the memref. The | |
123 ANY is used for constants that are not +-size or 0. REG is used if | |
124 the forms are reg1 + reg2. */ | |
125 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
126 enum inc_state |
0 | 127 { |
128 INC_ZERO, /* == 0 */ | |
129 INC_NEG_SIZE, /* == +size */ | |
130 INC_POS_SIZE, /* == -size */ | |
131 INC_NEG_ANY, /* == some -constant */ | |
132 INC_POS_ANY, /* == some +constant */ | |
133 INC_REG, /* == some register */ | |
134 INC_last | |
135 }; | |
136 | |
137 /* The eight forms that pre/post inc/dec can take. */ | |
138 enum gen_form | |
139 { | |
140 NOTHING, | |
141 SIMPLE_PRE_INC, /* ++size */ | |
142 SIMPLE_POST_INC, /* size++ */ | |
143 SIMPLE_PRE_DEC, /* --size */ | |
144 SIMPLE_POST_DEC, /* size-- */ | |
145 DISP_PRE, /* ++con */ | |
146 DISP_POST, /* con++ */ | |
147 REG_PRE, /* ++reg */ | |
148 REG_POST /* reg++ */ | |
149 }; | |
150 | |
151 /* Tmp mem rtx for use in cost modeling. */ | |
152 static rtx mem_tmp; | |
153 | |
154 static enum inc_state | |
131 | 155 set_inc_state (HOST_WIDE_INT val, poly_int64 size) |
0 | 156 { |
157 if (val == 0) | |
158 return INC_ZERO; | |
159 if (val < 0) | |
131 | 160 return known_eq (val, -size) ? INC_NEG_SIZE : INC_NEG_ANY; |
0 | 161 else |
131 | 162 return known_eq (val, size) ? INC_POS_SIZE : INC_POS_ANY; |
0 | 163 } |
164 | |
165 /* The DECISION_TABLE that describes what form, if any, the increment | |
166 or decrement will take. It is a three dimensional table. The first | |
167 index is the type of constant or register found as the second | |
168 operand of the inc insn. The second index is the type of constant | |
169 or register found as the second operand of the memory reference (if | |
170 no second operand exists, 0 is used). The third index is the form | |
171 and location (relative to the mem reference) of inc insn. */ | |
172 | |
173 static bool initialized = false; | |
174 static enum gen_form decision_table[INC_last][INC_last][FORM_last]; | |
175 | |
176 static void | |
177 init_decision_table (void) | |
178 { | |
179 enum gen_form value; | |
180 | |
181 if (HAVE_PRE_INCREMENT || HAVE_PRE_MODIFY_DISP) | |
182 { | |
183 /* Prefer the simple form if both are available. */ | |
184 value = (HAVE_PRE_INCREMENT) ? SIMPLE_PRE_INC : DISP_PRE; | |
185 | |
186 decision_table[INC_POS_SIZE][INC_ZERO][FORM_PRE_ADD] = value; | |
187 decision_table[INC_POS_SIZE][INC_ZERO][FORM_PRE_INC] = value; | |
188 | |
189 decision_table[INC_POS_SIZE][INC_POS_SIZE][FORM_POST_ADD] = value; | |
190 decision_table[INC_POS_SIZE][INC_POS_SIZE][FORM_POST_INC] = value; | |
191 } | |
192 | |
193 if (HAVE_POST_INCREMENT || HAVE_POST_MODIFY_DISP) | |
194 { | |
195 /* Prefer the simple form if both are available. */ | |
196 value = (HAVE_POST_INCREMENT) ? SIMPLE_POST_INC : DISP_POST; | |
197 | |
198 decision_table[INC_POS_SIZE][INC_ZERO][FORM_POST_ADD] = value; | |
199 decision_table[INC_POS_SIZE][INC_ZERO][FORM_POST_INC] = value; | |
200 | |
201 decision_table[INC_POS_SIZE][INC_NEG_SIZE][FORM_PRE_ADD] = value; | |
202 decision_table[INC_POS_SIZE][INC_NEG_SIZE][FORM_PRE_INC] = value; | |
203 } | |
204 | |
205 if (HAVE_PRE_DECREMENT || HAVE_PRE_MODIFY_DISP) | |
206 { | |
207 /* Prefer the simple form if both are available. */ | |
208 value = (HAVE_PRE_DECREMENT) ? SIMPLE_PRE_DEC : DISP_PRE; | |
209 | |
210 decision_table[INC_NEG_SIZE][INC_ZERO][FORM_PRE_ADD] = value; | |
211 decision_table[INC_NEG_SIZE][INC_ZERO][FORM_PRE_INC] = value; | |
212 | |
213 decision_table[INC_NEG_SIZE][INC_NEG_SIZE][FORM_POST_ADD] = value; | |
214 decision_table[INC_NEG_SIZE][INC_NEG_SIZE][FORM_POST_INC] = value; | |
215 } | |
216 | |
217 if (HAVE_POST_DECREMENT || HAVE_POST_MODIFY_DISP) | |
218 { | |
219 /* Prefer the simple form if both are available. */ | |
220 value = (HAVE_POST_DECREMENT) ? SIMPLE_POST_DEC : DISP_POST; | |
221 | |
222 decision_table[INC_NEG_SIZE][INC_ZERO][FORM_POST_ADD] = value; | |
223 decision_table[INC_NEG_SIZE][INC_ZERO][FORM_POST_INC] = value; | |
224 | |
225 decision_table[INC_NEG_SIZE][INC_POS_SIZE][FORM_PRE_ADD] = value; | |
226 decision_table[INC_NEG_SIZE][INC_POS_SIZE][FORM_PRE_INC] = value; | |
227 } | |
228 | |
229 if (HAVE_PRE_MODIFY_DISP) | |
230 { | |
231 decision_table[INC_POS_ANY][INC_ZERO][FORM_PRE_ADD] = DISP_PRE; | |
232 decision_table[INC_POS_ANY][INC_ZERO][FORM_PRE_INC] = DISP_PRE; | |
233 | |
234 decision_table[INC_POS_ANY][INC_POS_ANY][FORM_POST_ADD] = DISP_PRE; | |
235 decision_table[INC_POS_ANY][INC_POS_ANY][FORM_POST_INC] = DISP_PRE; | |
236 | |
237 decision_table[INC_NEG_ANY][INC_ZERO][FORM_PRE_ADD] = DISP_PRE; | |
238 decision_table[INC_NEG_ANY][INC_ZERO][FORM_PRE_INC] = DISP_PRE; | |
239 | |
240 decision_table[INC_NEG_ANY][INC_NEG_ANY][FORM_POST_ADD] = DISP_PRE; | |
241 decision_table[INC_NEG_ANY][INC_NEG_ANY][FORM_POST_INC] = DISP_PRE; | |
242 } | |
243 | |
244 if (HAVE_POST_MODIFY_DISP) | |
245 { | |
246 decision_table[INC_POS_ANY][INC_ZERO][FORM_POST_ADD] = DISP_POST; | |
247 decision_table[INC_POS_ANY][INC_ZERO][FORM_POST_INC] = DISP_POST; | |
248 | |
249 decision_table[INC_POS_ANY][INC_NEG_ANY][FORM_PRE_ADD] = DISP_POST; | |
250 decision_table[INC_POS_ANY][INC_NEG_ANY][FORM_PRE_INC] = DISP_POST; | |
251 | |
252 decision_table[INC_NEG_ANY][INC_ZERO][FORM_POST_ADD] = DISP_POST; | |
253 decision_table[INC_NEG_ANY][INC_ZERO][FORM_POST_INC] = DISP_POST; | |
254 | |
255 decision_table[INC_NEG_ANY][INC_POS_ANY][FORM_PRE_ADD] = DISP_POST; | |
256 decision_table[INC_NEG_ANY][INC_POS_ANY][FORM_PRE_INC] = DISP_POST; | |
257 } | |
258 | |
259 /* This is much simpler than the other cases because we do not look | |
260 for the reg1-reg2 case. Note that we do not have a INC_POS_REG | |
261 and INC_NEG_REG states. Most of the use of such states would be | |
262 on a target that had an R1 - R2 update address form. | |
263 | |
264 There is the remote possibility that you could also catch a = a + | |
265 b; *(a - b) as a postdecrement of (a + b). However, it is | |
266 unclear if *(a - b) would ever be generated on a machine that did | |
267 not have that kind of addressing mode. The IA-64 and RS6000 will | |
268 not do this, and I cannot speak for any other. If any | |
269 architecture does have an a-b update for, these cases should be | |
270 added. */ | |
271 if (HAVE_PRE_MODIFY_REG) | |
272 { | |
273 decision_table[INC_REG][INC_ZERO][FORM_PRE_ADD] = REG_PRE; | |
274 decision_table[INC_REG][INC_ZERO][FORM_PRE_INC] = REG_PRE; | |
275 | |
276 decision_table[INC_REG][INC_REG][FORM_POST_ADD] = REG_PRE; | |
277 decision_table[INC_REG][INC_REG][FORM_POST_INC] = REG_PRE; | |
278 } | |
279 | |
280 if (HAVE_POST_MODIFY_REG) | |
281 { | |
282 decision_table[INC_REG][INC_ZERO][FORM_POST_ADD] = REG_POST; | |
283 decision_table[INC_REG][INC_ZERO][FORM_POST_INC] = REG_POST; | |
284 } | |
285 | |
286 initialized = true; | |
287 } | |
288 | |
289 /* Parsed fields of an inc insn of the form "reg_res = reg0+reg1" or | |
290 "reg_res = reg0+c". */ | |
291 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
292 static struct inc_insn |
0 | 293 { |
111 | 294 rtx_insn *insn; /* The insn being parsed. */ |
0 | 295 rtx pat; /* The pattern of the insn. */ |
296 bool reg1_is_const; /* True if reg1 is const, false if reg1 is a reg. */ | |
297 enum form form; | |
298 rtx reg_res; | |
299 rtx reg0; | |
300 rtx reg1; | |
301 enum inc_state reg1_state;/* The form of the const if reg1 is a const. */ | |
302 HOST_WIDE_INT reg1_val;/* Value if reg1 is const. */ | |
303 } inc_insn; | |
304 | |
305 | |
306 /* Dump the parsed inc insn to FILE. */ | |
307 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
308 static void |
0 | 309 dump_inc_insn (FILE *file) |
310 { | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
311 const char *f = ((inc_insn.form == FORM_PRE_ADD) |
0 | 312 || (inc_insn.form == FORM_PRE_INC)) ? "pre" : "post"; |
313 | |
314 dump_insn_slim (file, inc_insn.insn); | |
315 | |
316 switch (inc_insn.form) | |
317 { | |
318 case FORM_PRE_ADD: | |
319 case FORM_POST_ADD: | |
320 if (inc_insn.reg1_is_const) | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
321 fprintf (file, "found %s add(%d) r[%d]=r[%d]+%d\n", |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
322 f, INSN_UID (inc_insn.insn), |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
323 REGNO (inc_insn.reg_res), |
0 | 324 REGNO (inc_insn.reg0), (int) inc_insn.reg1_val); |
325 else | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
326 fprintf (file, "found %s add(%d) r[%d]=r[%d]+r[%d]\n", |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
327 f, INSN_UID (inc_insn.insn), |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
328 REGNO (inc_insn.reg_res), |
0 | 329 REGNO (inc_insn.reg0), REGNO (inc_insn.reg1)); |
330 break; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
331 |
0 | 332 case FORM_PRE_INC: |
333 case FORM_POST_INC: | |
334 if (inc_insn.reg1_is_const) | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
335 fprintf (file, "found %s inc(%d) r[%d]+=%d\n", |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
336 f, INSN_UID (inc_insn.insn), |
0 | 337 REGNO (inc_insn.reg_res), (int) inc_insn.reg1_val); |
338 else | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
339 fprintf (file, "found %s inc(%d) r[%d]+=r[%d]\n", |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
340 f, INSN_UID (inc_insn.insn), |
0 | 341 REGNO (inc_insn.reg_res), REGNO (inc_insn.reg1)); |
342 break; | |
343 | |
344 default: | |
345 break; | |
346 } | |
347 } | |
348 | |
349 | |
350 /* Parsed fields of a mem ref of the form "*(reg0+reg1)" or "*(reg0+c)". */ | |
351 | |
352 static struct mem_insn | |
353 { | |
111 | 354 rtx_insn *insn; /* The insn being parsed. */ |
0 | 355 rtx pat; /* The pattern of the insn. */ |
356 rtx *mem_loc; /* The address of the field that holds the mem */ | |
357 /* that is to be replaced. */ | |
358 bool reg1_is_const; /* True if reg1 is const, false if reg1 is a reg. */ | |
359 rtx reg0; | |
360 rtx reg1; /* This is either a reg or a const depending on | |
361 reg1_is_const. */ | |
362 enum inc_state reg1_state;/* The form of the const if reg1 is a const. */ | |
363 HOST_WIDE_INT reg1_val;/* Value if reg1 is const. */ | |
364 } mem_insn; | |
365 | |
366 | |
367 /* Dump the parsed mem insn to FILE. */ | |
368 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
369 static void |
0 | 370 dump_mem_insn (FILE *file) |
371 { | |
372 dump_insn_slim (file, mem_insn.insn); | |
373 | |
374 if (mem_insn.reg1_is_const) | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
375 fprintf (file, "found mem(%d) *(r[%d]+%d)\n", |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
376 INSN_UID (mem_insn.insn), |
0 | 377 REGNO (mem_insn.reg0), (int) mem_insn.reg1_val); |
378 else | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
379 fprintf (file, "found mem(%d) *(r[%d]+r[%d])\n", |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
380 INSN_UID (mem_insn.insn), |
0 | 381 REGNO (mem_insn.reg0), REGNO (mem_insn.reg1)); |
382 } | |
383 | |
384 | |
385 /* The following three arrays contain pointers to instructions. They | |
386 are indexed by REGNO. At any point in the basic block where we are | |
387 looking these three arrays contain, respectively, the next insn | |
388 that uses REGNO, the next inc or add insn that uses REGNO and the | |
389 next insn that sets REGNO. | |
390 | |
391 The arrays are not cleared when we move from block to block so | |
392 whenever an insn is retrieved from these arrays, it's block number | |
393 must be compared with the current block. | |
394 */ | |
395 | |
111 | 396 static rtx_insn **reg_next_use = NULL; |
397 static rtx_insn **reg_next_inc_use = NULL; | |
398 static rtx_insn **reg_next_def = NULL; | |
0 | 399 |
400 | |
401 /* Move dead note that match PATTERN to TO_INSN from FROM_INSN. We do | |
402 not really care about moving any other notes from the inc or add | |
403 insn. Moving the REG_EQUAL and REG_EQUIV is clearly wrong and it | |
404 does not appear that there are any other kinds of relevant notes. */ | |
405 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
406 static void |
111 | 407 move_dead_notes (rtx_insn *to_insn, rtx_insn *from_insn, rtx pattern) |
0 | 408 { |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
409 rtx note; |
0 | 410 rtx next_note; |
411 rtx prev_note = NULL; | |
412 | |
413 for (note = REG_NOTES (from_insn); note; note = next_note) | |
414 { | |
415 next_note = XEXP (note, 1); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
416 |
0 | 417 if ((REG_NOTE_KIND (note) == REG_DEAD) |
418 && pattern == XEXP (note, 0)) | |
419 { | |
420 XEXP (note, 1) = REG_NOTES (to_insn); | |
421 REG_NOTES (to_insn) = note; | |
422 if (prev_note) | |
423 XEXP (prev_note, 1) = next_note; | |
424 else | |
425 REG_NOTES (from_insn) = next_note; | |
426 } | |
427 else prev_note = note; | |
428 } | |
429 } | |
430 | |
431 /* Change mem_insn.mem_loc so that uses NEW_ADDR which has an | |
432 increment of INC_REG. To have reached this point, the change is a | |
433 legitimate one from a dataflow point of view. The only questions | |
434 are is this a valid change to the instruction and is this a | |
435 profitable change to the instruction. */ | |
436 | |
437 static bool | |
438 attempt_change (rtx new_addr, rtx inc_reg) | |
439 { | |
440 /* There are four cases: For the two cases that involve an add | |
441 instruction, we are going to have to delete the add and insert a | |
442 mov. We are going to assume that the mov is free. This is | |
443 fairly early in the backend and there are a lot of opportunities | |
444 for removing that move later. In particular, there is the case | |
445 where the move may be dead, this is what dead code elimination | |
446 passes are for. The two cases where we have an inc insn will be | |
447 handled mov free. */ | |
448 | |
63
b7f97abdc517
update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
449 basic_block bb = BLOCK_FOR_INSN (mem_insn.insn); |
111 | 450 rtx_insn *mov_insn = NULL; |
0 | 451 int regno; |
452 rtx mem = *mem_insn.mem_loc; | |
111 | 453 machine_mode mode = GET_MODE (mem); |
0 | 454 rtx new_mem; |
455 int old_cost = 0; | |
456 int new_cost = 0; | |
457 bool speed = optimize_bb_for_speed_p (bb); | |
458 | |
459 PUT_MODE (mem_tmp, mode); | |
460 XEXP (mem_tmp, 0) = new_addr; | |
461 | |
111 | 462 old_cost = (set_src_cost (mem, mode, speed) |
463 + set_rtx_cost (PATTERN (inc_insn.insn), speed)); | |
464 | |
465 new_cost = set_src_cost (mem_tmp, mode, speed); | |
466 | |
467 /* In the FORM_PRE_ADD and FORM_POST_ADD cases we emit an extra move | |
468 whose cost we should account for. */ | |
469 if (inc_insn.form == FORM_PRE_ADD | |
470 || inc_insn.form == FORM_POST_ADD) | |
471 { | |
472 start_sequence (); | |
473 emit_move_insn (inc_insn.reg_res, inc_insn.reg0); | |
474 mov_insn = get_insns (); | |
475 end_sequence (); | |
476 new_cost += seq_cost (mov_insn, speed); | |
477 } | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
478 |
0 | 479 /* The first item of business is to see if this is profitable. */ |
480 if (old_cost < new_cost) | |
481 { | |
482 if (dump_file) | |
483 fprintf (dump_file, "cost failure old=%d new=%d\n", old_cost, new_cost); | |
484 return false; | |
485 } | |
486 | |
111 | 487 /* Jump through a lot of hoops to keep the attributes up to date. We |
0 | 488 do not want to call one of the change address variants that take |
489 an offset even though we know the offset in many cases. These | |
490 assume you are changing where the address is pointing by the | |
491 offset. */ | |
492 new_mem = replace_equiv_address_nv (mem, new_addr); | |
493 if (! validate_change (mem_insn.insn, mem_insn.mem_loc, new_mem, 0)) | |
494 { | |
495 if (dump_file) | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
496 fprintf (dump_file, "validation failure\n"); |
0 | 497 return false; |
498 } | |
499 | |
500 /* From here to the end of the function we are committed to the | |
501 change, i.e. nothing fails. Generate any necessary movs, move | |
502 any regnotes, and fix up the reg_next_{use,inc_use,def}. */ | |
503 switch (inc_insn.form) | |
504 { | |
505 case FORM_PRE_ADD: | |
506 /* Replace the addition with a move. Do it at the location of | |
507 the addition since the operand of the addition may change | |
508 before the memory reference. */ | |
111 | 509 gcc_assert (mov_insn); |
510 emit_insn_before (mov_insn, inc_insn.insn); | |
131 | 511 regno = REGNO (inc_insn.reg0); |
512 if (reg_next_use[regno] == mem_insn.insn) | |
513 move_dead_notes (mov_insn, mem_insn.insn, inc_insn.reg0); | |
514 else | |
515 move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0); | |
0 | 516 |
517 regno = REGNO (inc_insn.reg_res); | |
518 reg_next_def[regno] = mov_insn; | |
519 reg_next_use[regno] = NULL; | |
520 regno = REGNO (inc_insn.reg0); | |
521 reg_next_use[regno] = mov_insn; | |
522 df_recompute_luids (bb); | |
523 break; | |
524 | |
525 case FORM_POST_INC: | |
526 regno = REGNO (inc_insn.reg_res); | |
527 if (reg_next_use[regno] == reg_next_inc_use[regno]) | |
528 reg_next_inc_use[regno] = NULL; | |
529 | |
530 /* Fallthru. */ | |
531 case FORM_PRE_INC: | |
532 regno = REGNO (inc_insn.reg_res); | |
533 reg_next_def[regno] = mem_insn.insn; | |
534 reg_next_use[regno] = NULL; | |
535 | |
536 break; | |
537 | |
538 case FORM_POST_ADD: | |
111 | 539 gcc_assert (mov_insn); |
540 emit_insn_before (mov_insn, mem_insn.insn); | |
0 | 541 move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0); |
542 | |
543 /* Do not move anything to the mov insn because the instruction | |
544 pointer for the main iteration has not yet hit that. It is | |
545 still pointing to the mem insn. */ | |
546 regno = REGNO (inc_insn.reg_res); | |
547 reg_next_def[regno] = mem_insn.insn; | |
548 reg_next_use[regno] = NULL; | |
549 | |
550 regno = REGNO (inc_insn.reg0); | |
551 reg_next_use[regno] = mem_insn.insn; | |
552 if ((reg_next_use[regno] == reg_next_inc_use[regno]) | |
553 || (reg_next_inc_use[regno] == inc_insn.insn)) | |
554 reg_next_inc_use[regno] = NULL; | |
555 df_recompute_luids (bb); | |
556 break; | |
557 | |
558 case FORM_last: | |
559 default: | |
560 gcc_unreachable (); | |
561 } | |
562 | |
563 if (!inc_insn.reg1_is_const) | |
564 { | |
565 regno = REGNO (inc_insn.reg1); | |
566 reg_next_use[regno] = mem_insn.insn; | |
567 if ((reg_next_use[regno] == reg_next_inc_use[regno]) | |
568 || (reg_next_inc_use[regno] == inc_insn.insn)) | |
569 reg_next_inc_use[regno] = NULL; | |
570 } | |
571 | |
572 delete_insn (inc_insn.insn); | |
573 | |
574 if (dump_file && mov_insn) | |
575 { | |
576 fprintf (dump_file, "inserting mov "); | |
577 dump_insn_slim (dump_file, mov_insn); | |
578 } | |
579 | |
580 /* Record that this insn has an implicit side effect. */ | |
581 add_reg_note (mem_insn.insn, REG_INC, inc_reg); | |
582 | |
583 if (dump_file) | |
584 { | |
585 fprintf (dump_file, "****success "); | |
586 dump_insn_slim (dump_file, mem_insn.insn); | |
587 } | |
588 | |
589 return true; | |
590 } | |
591 | |
592 | |
593 /* Try to combine the instruction in INC_INSN with the instruction in | |
594 MEM_INSN. First the form is determined using the DECISION_TABLE | |
595 and the results of parsing the INC_INSN and the MEM_INSN. | |
596 Assuming the form is ok, a prototype new address is built which is | |
597 passed to ATTEMPT_CHANGE for final processing. */ | |
598 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
599 static bool |
0 | 600 try_merge (void) |
601 { | |
602 enum gen_form gen_form; | |
603 rtx mem = *mem_insn.mem_loc; | |
604 rtx inc_reg = inc_insn.form == FORM_POST_ADD ? | |
605 inc_insn.reg_res : mem_insn.reg0; | |
606 | |
607 /* The width of the mem being accessed. */ | |
131 | 608 poly_int64 size = GET_MODE_SIZE (GET_MODE (mem)); |
111 | 609 rtx_insn *last_insn = NULL; |
610 machine_mode reg_mode = GET_MODE (inc_reg); | |
0 | 611 |
612 switch (inc_insn.form) | |
613 { | |
614 case FORM_PRE_ADD: | |
615 case FORM_PRE_INC: | |
616 last_insn = mem_insn.insn; | |
617 break; | |
618 case FORM_POST_INC: | |
619 case FORM_POST_ADD: | |
620 last_insn = inc_insn.insn; | |
621 break; | |
622 case FORM_last: | |
623 default: | |
624 gcc_unreachable (); | |
625 } | |
626 | |
627 /* Cannot handle auto inc of the stack. */ | |
628 if (inc_reg == stack_pointer_rtx) | |
629 { | |
630 if (dump_file) | |
631 fprintf (dump_file, "cannot inc stack %d failure\n", REGNO (inc_reg)); | |
632 return false; | |
633 } | |
634 | |
635 /* Look to see if the inc register is dead after the memory | |
636 reference. If it is, do not do the combination. */ | |
637 if (find_regno_note (last_insn, REG_DEAD, REGNO (inc_reg))) | |
638 { | |
639 if (dump_file) | |
640 fprintf (dump_file, "dead failure %d\n", REGNO (inc_reg)); | |
641 return false; | |
642 } | |
643 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
644 mem_insn.reg1_state = (mem_insn.reg1_is_const) |
0 | 645 ? set_inc_state (mem_insn.reg1_val, size) : INC_REG; |
646 inc_insn.reg1_state = (inc_insn.reg1_is_const) | |
647 ? set_inc_state (inc_insn.reg1_val, size) : INC_REG; | |
648 | |
649 /* Now get the form that we are generating. */ | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
650 gen_form = decision_table |
0 | 651 [inc_insn.reg1_state][mem_insn.reg1_state][inc_insn.form]; |
652 | |
653 if (dbg_cnt (auto_inc_dec) == false) | |
654 return false; | |
655 | |
656 switch (gen_form) | |
657 { | |
658 default: | |
659 case NOTHING: | |
660 return false; | |
661 | |
662 case SIMPLE_PRE_INC: /* ++size */ | |
663 if (dump_file) | |
664 fprintf (dump_file, "trying SIMPLE_PRE_INC\n"); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
665 return attempt_change (gen_rtx_PRE_INC (reg_mode, inc_reg), inc_reg); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
666 |
0 | 667 case SIMPLE_POST_INC: /* size++ */ |
668 if (dump_file) | |
669 fprintf (dump_file, "trying SIMPLE_POST_INC\n"); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
670 return attempt_change (gen_rtx_POST_INC (reg_mode, inc_reg), inc_reg); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
671 |
0 | 672 case SIMPLE_PRE_DEC: /* --size */ |
673 if (dump_file) | |
674 fprintf (dump_file, "trying SIMPLE_PRE_DEC\n"); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
675 return attempt_change (gen_rtx_PRE_DEC (reg_mode, inc_reg), inc_reg); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
676 |
0 | 677 case SIMPLE_POST_DEC: /* size-- */ |
678 if (dump_file) | |
679 fprintf (dump_file, "trying SIMPLE_POST_DEC\n"); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
680 return attempt_change (gen_rtx_POST_DEC (reg_mode, inc_reg), inc_reg); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
681 |
0 | 682 case DISP_PRE: /* ++con */ |
683 if (dump_file) | |
684 fprintf (dump_file, "trying DISP_PRE\n"); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
685 return attempt_change (gen_rtx_PRE_MODIFY (reg_mode, |
0 | 686 inc_reg, |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
687 gen_rtx_PLUS (reg_mode, |
0 | 688 inc_reg, |
689 inc_insn.reg1)), | |
690 inc_reg); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
691 |
0 | 692 case DISP_POST: /* con++ */ |
693 if (dump_file) | |
694 fprintf (dump_file, "trying POST_DISP\n"); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
695 return attempt_change (gen_rtx_POST_MODIFY (reg_mode, |
0 | 696 inc_reg, |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
697 gen_rtx_PLUS (reg_mode, |
0 | 698 inc_reg, |
699 inc_insn.reg1)), | |
700 inc_reg); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
701 |
0 | 702 case REG_PRE: /* ++reg */ |
703 if (dump_file) | |
704 fprintf (dump_file, "trying PRE_REG\n"); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
705 return attempt_change (gen_rtx_PRE_MODIFY (reg_mode, |
0 | 706 inc_reg, |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
707 gen_rtx_PLUS (reg_mode, |
0 | 708 inc_reg, |
709 inc_insn.reg1)), | |
710 inc_reg); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
711 |
0 | 712 case REG_POST: /* reg++ */ |
713 if (dump_file) | |
714 fprintf (dump_file, "trying POST_REG\n"); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
715 return attempt_change (gen_rtx_POST_MODIFY (reg_mode, |
0 | 716 inc_reg, |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
717 gen_rtx_PLUS (reg_mode, |
0 | 718 inc_reg, |
719 inc_insn.reg1)), | |
720 inc_reg); | |
721 } | |
722 } | |
723 | |
724 /* Return the next insn that uses (if reg_next_use is passed in | |
725 NEXT_ARRAY) or defines (if reg_next_def is passed in NEXT_ARRAY) | |
726 REGNO in BB. */ | |
727 | |
111 | 728 static rtx_insn * |
729 get_next_ref (int regno, basic_block bb, rtx_insn **next_array) | |
0 | 730 { |
111 | 731 rtx_insn *insn = next_array[regno]; |
0 | 732 |
733 /* Lazy about cleaning out the next_arrays. */ | |
63
b7f97abdc517
update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
734 if (insn && BLOCK_FOR_INSN (insn) != bb) |
0 | 735 { |
736 next_array[regno] = NULL; | |
737 insn = NULL; | |
738 } | |
739 | |
740 return insn; | |
741 } | |
742 | |
743 | |
744 /* Return true if INSN is of a form "a = b op c" where a and b are | |
745 regs. op is + if c is a reg and +|- if c is a const. Fill in | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
746 INC_INSN with what is found. |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
747 |
0 | 748 This function is called in two contexts, if BEFORE_MEM is true, |
749 this is called for each insn in the basic block. If BEFORE_MEM is | |
750 false, it is called for the instruction in the block that uses the | |
751 index register for some memory reference that is currently being | |
752 processed. */ | |
753 | |
754 static bool | |
111 | 755 parse_add_or_inc (rtx_insn *insn, bool before_mem) |
0 | 756 { |
757 rtx pat = single_set (insn); | |
758 if (!pat) | |
759 return false; | |
760 | |
761 /* Result must be single reg. */ | |
762 if (!REG_P (SET_DEST (pat))) | |
763 return false; | |
764 | |
765 if ((GET_CODE (SET_SRC (pat)) != PLUS) | |
766 && (GET_CODE (SET_SRC (pat)) != MINUS)) | |
767 return false; | |
768 | |
769 if (!REG_P (XEXP (SET_SRC (pat), 0))) | |
770 return false; | |
771 | |
772 inc_insn.insn = insn; | |
773 inc_insn.pat = pat; | |
774 inc_insn.reg_res = SET_DEST (pat); | |
775 inc_insn.reg0 = XEXP (SET_SRC (pat), 0); | |
111 | 776 |
777 /* Block any auto increment of the frame pointer since it expands into | |
778 an addition and cannot be removed by copy propagation. */ | |
779 if (inc_insn.reg0 == frame_pointer_rtx) | |
780 return false; | |
781 | |
0 | 782 if (rtx_equal_p (inc_insn.reg_res, inc_insn.reg0)) |
783 inc_insn.form = before_mem ? FORM_PRE_INC : FORM_POST_INC; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
784 else |
0 | 785 inc_insn.form = before_mem ? FORM_PRE_ADD : FORM_POST_ADD; |
786 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
787 if (CONST_INT_P (XEXP (SET_SRC (pat), 1))) |
0 | 788 { |
789 /* Process a = b + c where c is a const. */ | |
790 inc_insn.reg1_is_const = true; | |
791 if (GET_CODE (SET_SRC (pat)) == PLUS) | |
792 { | |
793 inc_insn.reg1 = XEXP (SET_SRC (pat), 1); | |
794 inc_insn.reg1_val = INTVAL (inc_insn.reg1); | |
795 } | |
796 else | |
797 { | |
798 inc_insn.reg1_val = -INTVAL (XEXP (SET_SRC (pat), 1)); | |
799 inc_insn.reg1 = GEN_INT (inc_insn.reg1_val); | |
800 } | |
801 return true; | |
802 } | |
803 else if ((HAVE_PRE_MODIFY_REG || HAVE_POST_MODIFY_REG) | |
804 && (REG_P (XEXP (SET_SRC (pat), 1))) | |
805 && GET_CODE (SET_SRC (pat)) == PLUS) | |
806 { | |
807 /* Process a = b + c where c is a reg. */ | |
808 inc_insn.reg1 = XEXP (SET_SRC (pat), 1); | |
809 inc_insn.reg1_is_const = false; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
810 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
811 if (inc_insn.form == FORM_PRE_INC |
0 | 812 || inc_insn.form == FORM_POST_INC) |
813 return true; | |
814 else if (rtx_equal_p (inc_insn.reg_res, inc_insn.reg1)) | |
815 { | |
816 /* Reverse the two operands and turn *_ADD into *_INC since | |
817 a = c + a. */ | |
111 | 818 std::swap (inc_insn.reg0, inc_insn.reg1); |
0 | 819 inc_insn.form = before_mem ? FORM_PRE_INC : FORM_POST_INC; |
820 return true; | |
821 } | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
822 else |
0 | 823 return true; |
824 } | |
825 | |
826 return false; | |
827 } | |
828 | |
829 | |
830 /* A recursive function that checks all of the mem uses in | |
831 ADDRESS_OF_X to see if any single one of them is compatible with | |
131 | 832 what has been found in inc_insn. To avoid accidental matches, we |
833 will only find MEMs with FINDREG, be it inc_insn.reg_res, be it | |
834 inc_insn.reg0. | |
0 | 835 |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
836 -1 is returned for success. 0 is returned if nothing was found and |
0 | 837 1 is returned for failure. */ |
838 | |
839 static int | |
131 | 840 find_address (rtx *address_of_x, rtx findreg) |
0 | 841 { |
842 rtx x = *address_of_x; | |
843 enum rtx_code code = GET_CODE (x); | |
844 const char *const fmt = GET_RTX_FORMAT (code); | |
845 int i; | |
846 int value = 0; | |
847 int tem; | |
848 | |
131 | 849 if (code == MEM && findreg == inc_insn.reg_res |
850 && rtx_equal_p (XEXP (x, 0), inc_insn.reg_res)) | |
0 | 851 { |
131 | 852 /* Match with *reg_res. */ |
0 | 853 mem_insn.mem_loc = address_of_x; |
854 mem_insn.reg0 = inc_insn.reg_res; | |
855 mem_insn.reg1_is_const = true; | |
856 mem_insn.reg1_val = 0; | |
857 mem_insn.reg1 = GEN_INT (0); | |
858 return -1; | |
859 } | |
131 | 860 if (code == MEM && inc_insn.reg1_is_const && inc_insn.reg0 |
861 && findreg == inc_insn.reg0 | |
862 && rtx_equal_p (XEXP (x, 0), inc_insn.reg0)) | |
863 { | |
864 /* Match with *reg0, assumed to be equivalent to | |
865 *(reg_res - reg1_val); callers must check whether this is the case. */ | |
866 mem_insn.mem_loc = address_of_x; | |
867 mem_insn.reg0 = inc_insn.reg_res; | |
868 mem_insn.reg1_is_const = true; | |
869 mem_insn.reg1_val = -inc_insn.reg1_val; | |
870 mem_insn.reg1 = GEN_INT (mem_insn.reg1_val); | |
871 return -1; | |
872 } | |
873 if (code == MEM && findreg == inc_insn.reg_res | |
874 && GET_CODE (XEXP (x, 0)) == PLUS | |
0 | 875 && rtx_equal_p (XEXP (XEXP (x, 0), 0), inc_insn.reg_res)) |
876 { | |
877 rtx b = XEXP (XEXP (x, 0), 1); | |
878 mem_insn.mem_loc = address_of_x; | |
879 mem_insn.reg0 = inc_insn.reg_res; | |
880 mem_insn.reg1 = b; | |
881 mem_insn.reg1_is_const = inc_insn.reg1_is_const; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
882 if (CONST_INT_P (b)) |
0 | 883 { |
884 /* Match with *(reg0 + reg1) where reg1 is a const. */ | |
885 HOST_WIDE_INT val = INTVAL (b); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
886 if (inc_insn.reg1_is_const |
0 | 887 && (inc_insn.reg1_val == val || inc_insn.reg1_val == -val)) |
888 { | |
889 mem_insn.reg1_val = val; | |
890 return -1; | |
891 } | |
892 } | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
893 else if (!inc_insn.reg1_is_const |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
894 && rtx_equal_p (inc_insn.reg1, b)) |
0 | 895 /* Match with *(reg0 + reg1). */ |
896 return -1; | |
897 } | |
898 | |
899 if (code == SIGN_EXTRACT || code == ZERO_EXTRACT) | |
900 { | |
901 /* If REG occurs inside a MEM used in a bit-field reference, | |
902 that is unacceptable. */ | |
131 | 903 if (find_address (&XEXP (x, 0), findreg)) |
0 | 904 return 1; |
905 } | |
906 | |
907 if (x == inc_insn.reg_res) | |
908 return 1; | |
909 | |
910 /* Time for some deep diving. */ | |
911 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) | |
912 { | |
913 if (fmt[i] == 'e') | |
914 { | |
131 | 915 tem = find_address (&XEXP (x, i), findreg); |
0 | 916 /* If this is the first use, let it go so the rest of the |
917 insn can be checked. */ | |
918 if (value == 0) | |
919 value = tem; | |
920 else if (tem != 0) | |
921 /* More than one match was found. */ | |
922 return 1; | |
923 } | |
924 else if (fmt[i] == 'E') | |
925 { | |
926 int j; | |
927 for (j = XVECLEN (x, i) - 1; j >= 0; j--) | |
928 { | |
131 | 929 tem = find_address (&XVECEXP (x, i, j), findreg); |
0 | 930 /* If this is the first use, let it go so the rest of |
931 the insn can be checked. */ | |
932 if (value == 0) | |
933 value = tem; | |
934 else if (tem != 0) | |
935 /* More than one match was found. */ | |
936 return 1; | |
937 } | |
938 } | |
939 } | |
940 return value; | |
941 } | |
942 | |
943 /* Once a suitable mem reference has been found and the MEM_INSN | |
944 structure has been filled in, FIND_INC is called to see if there is | |
945 a suitable add or inc insn that follows the mem reference and | |
946 determine if it is suitable to merge. | |
947 | |
948 In the case where the MEM_INSN has two registers in the reference, | |
949 this function may be called recursively. The first time looking | |
950 for an add of the first register, and if that fails, looking for an | |
951 add of the second register. The FIRST_TRY parameter is used to | |
952 only allow the parameters to be reversed once. */ | |
953 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
954 static bool |
0 | 955 find_inc (bool first_try) |
956 { | |
111 | 957 rtx_insn *insn; |
63
b7f97abdc517
update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
958 basic_block bb = BLOCK_FOR_INSN (mem_insn.insn); |
111 | 959 rtx_insn *other_insn; |
960 df_ref def; | |
0 | 961 |
962 /* Make sure this reg appears only once in this insn. */ | |
963 if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg0, 1) != 1) | |
964 { | |
965 if (dump_file) | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
966 fprintf (dump_file, "mem count failure\n"); |
0 | 967 return false; |
968 } | |
969 | |
970 if (dump_file) | |
971 dump_mem_insn (dump_file); | |
972 | |
973 /* Find the next use that is an inc. */ | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
974 insn = get_next_ref (REGNO (mem_insn.reg0), |
63
b7f97abdc517
update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
975 BLOCK_FOR_INSN (mem_insn.insn), |
0 | 976 reg_next_inc_use); |
977 if (!insn) | |
978 return false; | |
979 | |
980 /* Even though we know the next use is an add or inc because it came | |
981 from the reg_next_inc_use, we must still reparse. */ | |
982 if (!parse_add_or_inc (insn, false)) | |
983 { | |
984 /* Next use was not an add. Look for one extra case. It could be | |
985 that we have: | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
986 |
0 | 987 *(a + b) |
988 ...= a; | |
989 ...= b + a | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
990 |
0 | 991 if we reverse the operands in the mem ref we would |
992 find this. Only try it once though. */ | |
993 if (first_try && !mem_insn.reg1_is_const) | |
994 { | |
111 | 995 std::swap (mem_insn.reg0, mem_insn.reg1); |
0 | 996 return find_inc (false); |
997 } | |
998 else | |
999 return false; | |
1000 } | |
1001 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1002 /* Need to assure that none of the operands of the inc instruction are |
0 | 1003 assigned to by the mem insn. */ |
111 | 1004 FOR_EACH_INSN_DEF (def, mem_insn.insn) |
0 | 1005 { |
1006 unsigned int regno = DF_REF_REGNO (def); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1007 if ((regno == REGNO (inc_insn.reg0)) |
0 | 1008 || (regno == REGNO (inc_insn.reg_res))) |
1009 { | |
1010 if (dump_file) | |
1011 fprintf (dump_file, "inc conflicts with store failure.\n"); | |
1012 return false; | |
1013 } | |
1014 if (!inc_insn.reg1_is_const && (regno == REGNO (inc_insn.reg1))) | |
1015 { | |
1016 if (dump_file) | |
1017 fprintf (dump_file, "inc conflicts with store failure.\n"); | |
1018 return false; | |
1019 } | |
1020 } | |
1021 | |
1022 if (dump_file) | |
1023 dump_inc_insn (dump_file); | |
1024 | |
1025 if (inc_insn.form == FORM_POST_ADD) | |
1026 { | |
1027 /* Make sure that there is no insn that assigns to inc_insn.res | |
1028 between the mem_insn and the inc_insn. */ | |
111 | 1029 rtx_insn *other_insn = get_next_ref (REGNO (inc_insn.reg_res), |
1030 BLOCK_FOR_INSN (mem_insn.insn), | |
1031 reg_next_def); | |
0 | 1032 if (other_insn != inc_insn.insn) |
1033 { | |
1034 if (dump_file) | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1035 fprintf (dump_file, |
0 | 1036 "result of add is assigned to between mem and inc insns.\n"); |
1037 return false; | |
1038 } | |
1039 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1040 other_insn = get_next_ref (REGNO (inc_insn.reg_res), |
63
b7f97abdc517
update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
1041 BLOCK_FOR_INSN (mem_insn.insn), |
0 | 1042 reg_next_use); |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1043 if (other_insn |
0 | 1044 && (other_insn != inc_insn.insn) |
1045 && (DF_INSN_LUID (inc_insn.insn) > DF_INSN_LUID (other_insn))) | |
1046 { | |
1047 if (dump_file) | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1048 fprintf (dump_file, |
0 | 1049 "result of add is used between mem and inc insns.\n"); |
1050 return false; | |
1051 } | |
1052 | |
1053 /* For the post_add to work, the result_reg of the inc must not be | |
1054 used in the mem insn since this will become the new index | |
1055 register. */ | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
63
diff
changeset
|
1056 if (reg_overlap_mentioned_p (inc_insn.reg_res, PATTERN (mem_insn.insn))) |
0 | 1057 { |
1058 if (dump_file) | |
1059 fprintf (dump_file, "base reg replacement failure.\n"); | |
1060 return false; | |
1061 } | |
1062 } | |
1063 | |
1064 if (mem_insn.reg1_is_const) | |
1065 { | |
1066 if (mem_insn.reg1_val == 0) | |
1067 { | |
1068 if (!inc_insn.reg1_is_const) | |
1069 { | |
1070 /* The mem looks like *r0 and the rhs of the add has two | |
1071 registers. */ | |
1072 int luid = DF_INSN_LUID (inc_insn.insn); | |
1073 if (inc_insn.form == FORM_POST_ADD) | |
1074 { | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1075 /* The trick is that we are not going to increment r0, |
0 | 1076 we are going to increment the result of the add insn. |
1077 For this trick to be correct, the result reg of | |
1078 the inc must be a valid addressing reg. */ | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1079 addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1080 if (GET_MODE (inc_insn.reg_res) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1081 != targetm.addr_space.address_mode (as)) |
0 | 1082 { |
1083 if (dump_file) | |
1084 fprintf (dump_file, "base reg mode failure.\n"); | |
1085 return false; | |
1086 } | |
1087 | |
1088 /* We also need to make sure that the next use of | |
1089 inc result is after the inc. */ | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1090 other_insn |
0 | 1091 = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_use); |
1092 if (other_insn && luid > DF_INSN_LUID (other_insn)) | |
1093 return false; | |
1094 | |
1095 if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0)) | |
111 | 1096 std::swap (inc_insn.reg0, inc_insn.reg1); |
0 | 1097 } |
1098 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1099 other_insn |
0 | 1100 = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def); |
1101 if (other_insn && luid > DF_INSN_LUID (other_insn)) | |
1102 return false; | |
1103 } | |
1104 } | |
1105 /* Both the inc/add and the mem have a constant. Need to check | |
1106 that the constants are ok. */ | |
1107 else if ((mem_insn.reg1_val != inc_insn.reg1_val) | |
1108 && (mem_insn.reg1_val != -inc_insn.reg1_val)) | |
1109 return false; | |
1110 } | |
1111 else | |
1112 { | |
1113 /* The mem insn is of the form *(a + b) where a and b are both | |
1114 regs. It may be that in order to match the add or inc we | |
1115 need to treat it as if it was *(b + a). It may also be that | |
1116 the add is of the form a + c where c does not match b and | |
1117 then we just abandon this. */ | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1118 |
0 | 1119 int luid = DF_INSN_LUID (inc_insn.insn); |
111 | 1120 rtx_insn *other_insn; |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1121 |
0 | 1122 /* Make sure this reg appears only once in this insn. */ |
1123 if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg1, 1) != 1) | |
1124 return false; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1125 |
0 | 1126 if (inc_insn.form == FORM_POST_ADD) |
1127 { | |
1128 /* For this trick to be correct, the result reg of the inc | |
1129 must be a valid addressing reg. */ | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1130 addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1131 if (GET_MODE (inc_insn.reg_res) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1132 != targetm.addr_space.address_mode (as)) |
0 | 1133 { |
1134 if (dump_file) | |
1135 fprintf (dump_file, "base reg mode failure.\n"); | |
1136 return false; | |
1137 } | |
1138 | |
1139 if (rtx_equal_p (mem_insn.reg0, inc_insn.reg0)) | |
1140 { | |
1141 if (!rtx_equal_p (mem_insn.reg1, inc_insn.reg1)) | |
1142 { | |
1143 /* See comment above on find_inc (false) call. */ | |
1144 if (first_try) | |
1145 { | |
111 | 1146 std::swap (mem_insn.reg0, mem_insn.reg1); |
0 | 1147 return find_inc (false); |
1148 } | |
1149 else | |
1150 return false; | |
1151 } | |
1152 | |
1153 /* Need to check that there are no assignments to b | |
1154 before the add insn. */ | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1155 other_insn |
0 | 1156 = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def); |
1157 if (other_insn && luid > DF_INSN_LUID (other_insn)) | |
1158 return false; | |
1159 /* All ok for the next step. */ | |
1160 } | |
1161 else | |
1162 { | |
1163 /* We know that mem_insn.reg0 must equal inc_insn.reg1 | |
1164 or else we would not have found the inc insn. */ | |
111 | 1165 std::swap (mem_insn.reg0, mem_insn.reg1); |
0 | 1166 if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0)) |
1167 { | |
1168 /* See comment above on find_inc (false) call. */ | |
1169 if (first_try) | |
1170 return find_inc (false); | |
1171 else | |
1172 return false; | |
1173 } | |
1174 /* To have gotten here know that. | |
1175 *(b + a) | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1176 |
0 | 1177 ... = (b + a) |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1178 |
0 | 1179 We also know that the lhs of the inc is not b or a. We |
1180 need to make sure that there are no assignments to b | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1181 between the mem ref and the inc. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1182 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1183 other_insn |
0 | 1184 = get_next_ref (REGNO (inc_insn.reg0), bb, reg_next_def); |
1185 if (other_insn && luid > DF_INSN_LUID (other_insn)) | |
1186 return false; | |
1187 } | |
1188 | |
1189 /* Need to check that the next use of the add result is later than | |
1190 add insn since this will be the reg incremented. */ | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1191 other_insn |
0 | 1192 = get_next_ref (REGNO (inc_insn.reg_res), bb, reg_next_use); |
1193 if (other_insn && luid > DF_INSN_LUID (other_insn)) | |
1194 return false; | |
1195 } | |
1196 else /* FORM_POST_INC. There is less to check here because we | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1197 know that operands must line up. */ |
0 | 1198 { |
1199 if (!rtx_equal_p (mem_insn.reg1, inc_insn.reg1)) | |
1200 /* See comment above on find_inc (false) call. */ | |
1201 { | |
1202 if (first_try) | |
1203 { | |
111 | 1204 std::swap (mem_insn.reg0, mem_insn.reg1); |
0 | 1205 return find_inc (false); |
1206 } | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1207 else |
0 | 1208 return false; |
1209 } | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1210 |
0 | 1211 /* To have gotten here know that. |
1212 *(a + b) | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1213 |
0 | 1214 ... = (a + b) |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1215 |
0 | 1216 We also know that the lhs of the inc is not b. We need to make |
1217 sure that there are no assignments to b between the mem ref and | |
1218 the inc. */ | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1219 other_insn |
0 | 1220 = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def); |
1221 if (other_insn && luid > DF_INSN_LUID (other_insn)) | |
1222 return false; | |
1223 } | |
1224 } | |
1225 | |
1226 if (inc_insn.form == FORM_POST_INC) | |
1227 { | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1228 other_insn |
0 | 1229 = get_next_ref (REGNO (inc_insn.reg0), bb, reg_next_use); |
1230 /* When we found inc_insn, we were looking for the | |
1231 next add or inc, not the next insn that used the | |
1232 reg. Because we are going to increment the reg | |
1233 in this form, we need to make sure that there | |
1234 were no intervening uses of reg. */ | |
1235 if (inc_insn.insn != other_insn) | |
1236 return false; | |
1237 } | |
1238 | |
1239 return try_merge (); | |
1240 } | |
1241 | |
1242 | |
1243 /* A recursive function that walks ADDRESS_OF_X to find all of the mem | |
1244 uses in pat that could be used as an auto inc or dec. It then | |
1245 calls FIND_INC for each one. */ | |
1246 | |
1247 static bool | |
1248 find_mem (rtx *address_of_x) | |
1249 { | |
1250 rtx x = *address_of_x; | |
1251 enum rtx_code code = GET_CODE (x); | |
1252 const char *const fmt = GET_RTX_FORMAT (code); | |
1253 int i; | |
1254 | |
1255 if (code == MEM && REG_P (XEXP (x, 0))) | |
1256 { | |
1257 /* Match with *reg0. */ | |
1258 mem_insn.mem_loc = address_of_x; | |
1259 mem_insn.reg0 = XEXP (x, 0); | |
1260 mem_insn.reg1_is_const = true; | |
1261 mem_insn.reg1_val = 0; | |
1262 mem_insn.reg1 = GEN_INT (0); | |
1263 if (find_inc (true)) | |
1264 return true; | |
1265 } | |
1266 if (code == MEM && GET_CODE (XEXP (x, 0)) == PLUS | |
1267 && REG_P (XEXP (XEXP (x, 0), 0))) | |
1268 { | |
1269 rtx reg1 = XEXP (XEXP (x, 0), 1); | |
1270 mem_insn.mem_loc = address_of_x; | |
1271 mem_insn.reg0 = XEXP (XEXP (x, 0), 0); | |
1272 mem_insn.reg1 = reg1; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1273 if (CONST_INT_P (reg1)) |
0 | 1274 { |
1275 mem_insn.reg1_is_const = true; | |
1276 /* Match with *(reg0 + c) where c is a const. */ | |
1277 mem_insn.reg1_val = INTVAL (reg1); | |
1278 if (find_inc (true)) | |
1279 return true; | |
1280 } | |
1281 else if (REG_P (reg1)) | |
1282 { | |
1283 /* Match with *(reg0 + reg1). */ | |
1284 mem_insn.reg1_is_const = false; | |
1285 if (find_inc (true)) | |
1286 return true; | |
1287 } | |
1288 } | |
1289 | |
1290 if (code == SIGN_EXTRACT || code == ZERO_EXTRACT) | |
1291 { | |
1292 /* If REG occurs inside a MEM used in a bit-field reference, | |
1293 that is unacceptable. */ | |
1294 return false; | |
1295 } | |
1296 | |
1297 /* Time for some deep diving. */ | |
1298 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) | |
1299 { | |
1300 if (fmt[i] == 'e') | |
1301 { | |
1302 if (find_mem (&XEXP (x, i))) | |
1303 return true; | |
1304 } | |
1305 else if (fmt[i] == 'E') | |
1306 { | |
1307 int j; | |
1308 for (j = XVECLEN (x, i) - 1; j >= 0; j--) | |
1309 if (find_mem (&XVECEXP (x, i, j))) | |
1310 return true; | |
1311 } | |
1312 } | |
1313 return false; | |
1314 } | |
1315 | |
1316 | |
1317 /* Try to combine all incs and decs by constant values with memory | |
1318 references in BB. */ | |
1319 | |
1320 static void | |
1321 merge_in_block (int max_reg, basic_block bb) | |
1322 { | |
111 | 1323 rtx_insn *insn; |
1324 rtx_insn *curr; | |
0 | 1325 int success_in_block = 0; |
1326 | |
1327 if (dump_file) | |
1328 fprintf (dump_file, "\n\nstarting bb %d\n", bb->index); | |
1329 | |
1330 FOR_BB_INSNS_REVERSE_SAFE (bb, insn, curr) | |
1331 { | |
1332 bool insn_is_add_or_inc = true; | |
1333 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1334 if (!NONDEBUG_INSN_P (insn)) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1335 continue; |
0 | 1336 |
1337 /* This continue is deliberate. We do not want the uses of the | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1338 jump put into reg_next_use because it is not considered safe to |
0 | 1339 combine a preincrement with a jump. */ |
1340 if (JUMP_P (insn)) | |
1341 continue; | |
1342 | |
1343 if (dump_file) | |
1344 dump_insn_slim (dump_file, insn); | |
1345 | |
1346 /* Does this instruction increment or decrement a register? */ | |
1347 if (parse_add_or_inc (insn, true)) | |
1348 { | |
1349 int regno = REGNO (inc_insn.reg_res); | |
1350 /* Cannot handle case where there are three separate regs | |
1351 before a mem ref. Too many moves would be needed to be | |
1352 profitable. */ | |
1353 if ((inc_insn.form == FORM_PRE_INC) || inc_insn.reg1_is_const) | |
1354 { | |
1355 mem_insn.insn = get_next_ref (regno, bb, reg_next_use); | |
1356 if (mem_insn.insn) | |
1357 { | |
1358 bool ok = true; | |
1359 if (!inc_insn.reg1_is_const) | |
1360 { | |
1361 /* We are only here if we are going to try a | |
1362 HAVE_*_MODIFY_REG type transformation. c is a | |
1363 reg and we must sure that the path from the | |
1364 inc_insn to the mem_insn.insn is both def and use | |
1365 clear of c because the inc insn is going to move | |
1366 into the mem_insn.insn. */ | |
1367 int luid = DF_INSN_LUID (mem_insn.insn); | |
111 | 1368 rtx_insn *other_insn |
0 | 1369 = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_use); |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1370 |
0 | 1371 if (other_insn && luid > DF_INSN_LUID (other_insn)) |
1372 ok = false; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1373 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1374 other_insn |
0 | 1375 = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def); |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1376 |
0 | 1377 if (other_insn && luid > DF_INSN_LUID (other_insn)) |
1378 ok = false; | |
1379 } | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1380 |
0 | 1381 if (dump_file) |
1382 dump_inc_insn (dump_file); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1383 |
131 | 1384 if (ok && find_address (&PATTERN (mem_insn.insn), |
1385 inc_insn.reg_res) == -1) | |
1386 { | |
1387 if (dump_file) | |
1388 dump_mem_insn (dump_file); | |
1389 if (try_merge ()) | |
1390 { | |
1391 success_in_block++; | |
1392 insn_is_add_or_inc = false; | |
1393 } | |
1394 } | |
1395 } | |
1396 | |
1397 if (insn_is_add_or_inc | |
1398 /* find_address will only recognize an address | |
1399 with a reg0 that's not reg_res when | |
1400 reg1_is_const, so cut it off early if we | |
1401 already know it won't match. */ | |
1402 && inc_insn.reg1_is_const | |
1403 && inc_insn.reg0 | |
1404 && inc_insn.reg0 != inc_insn.reg_res) | |
1405 { | |
1406 /* If we identified an inc_insn that uses two | |
1407 different pseudos, it's of the form | |
1408 | |
1409 (set reg_res (plus reg0 reg1)) | |
1410 | |
1411 where reg1 is a constant (*). | |
1412 | |
1413 The next use of reg_res was not idenfied by | |
1414 find_address as a mem_insn that we could turn | |
1415 into auto-inc, so see if we find a suitable | |
1416 MEM in the next use of reg0, as long as it's | |
1417 before any subsequent use of reg_res: | |
1418 | |
1419 ... (mem (... reg0 ...)) ... | |
1420 | |
1421 ... reg_res ... | |
1422 | |
1423 In this case, we can turn the plus into a | |
1424 copy, and the reg0 in the MEM address into a | |
1425 post_inc of reg_res: | |
1426 | |
1427 (set reg_res reg0) | |
1428 | |
1429 ... (mem (... (post_add reg_res reg1) ...)) ... | |
1430 | |
1431 reg_res will then have the correct value at | |
1432 subsequent uses, and reg0 will remain | |
1433 unchanged. | |
1434 | |
1435 (*) We could support non-const reg1, but then | |
1436 we'd have to check that reg1 remains | |
1437 unchanged all the way to the modified MEM, | |
1438 and we'd have to extend find_address to | |
1439 represent a non-const negated reg1. */ | |
1440 regno = REGNO (inc_insn.reg0); | |
1441 rtx_insn *reg0_use = get_next_ref (regno, bb, | |
1442 reg_next_use); | |
1443 | |
1444 /* Give up if the next use of reg0 is after the next | |
1445 use of reg_res (same insn is ok; we might have | |
1446 found a MEM with reg_res before, and that failed, | |
1447 but now we try reg0, which might work), or defs | |
1448 of reg_res (same insn is not ok, we'd introduce | |
1449 another def in the same insn) or reg0. */ | |
1450 if (reg0_use) | |
1451 { | |
1452 int luid = DF_INSN_LUID (reg0_use); | |
1453 | |
1454 /* It might seem pointless to introduce an | |
1455 auto-inc if there's no subsequent use of | |
1456 reg_res (i.e., mem_insn.insn == NULL), but | |
1457 the next use might be in the next iteration | |
1458 of a loop, and it won't hurt if we make the | |
1459 change even if it's not needed. */ | |
1460 if (mem_insn.insn | |
1461 && luid > DF_INSN_LUID (mem_insn.insn)) | |
1462 reg0_use = NULL; | |
1463 | |
1464 rtx_insn *other_insn | |
1465 = get_next_ref (REGNO (inc_insn.reg_res), bb, | |
1466 reg_next_def); | |
1467 | |
1468 if (other_insn && luid >= DF_INSN_LUID (other_insn)) | |
1469 reg0_use = NULL; | |
1470 | |
1471 other_insn | |
1472 = get_next_ref (REGNO (inc_insn.reg0), bb, | |
1473 reg_next_def); | |
1474 | |
1475 if (other_insn && luid > DF_INSN_LUID (other_insn)) | |
1476 reg0_use = NULL; | |
1477 } | |
1478 | |
1479 mem_insn.insn = reg0_use; | |
1480 | |
1481 if (mem_insn.insn | |
1482 && find_address (&PATTERN (mem_insn.insn), | |
1483 inc_insn.reg0) == -1) | |
0 | 1484 { |
1485 if (dump_file) | |
1486 dump_mem_insn (dump_file); | |
1487 if (try_merge ()) | |
1488 { | |
1489 success_in_block++; | |
1490 insn_is_add_or_inc = false; | |
1491 } | |
1492 } | |
1493 } | |
1494 } | |
1495 } | |
1496 else | |
1497 { | |
1498 insn_is_add_or_inc = false; | |
1499 mem_insn.insn = insn; | |
1500 if (find_mem (&PATTERN (insn))) | |
1501 success_in_block++; | |
1502 } | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1503 |
0 | 1504 /* If the inc insn was merged with a mem, the inc insn is gone |
1505 and there is noting to update. */ | |
111 | 1506 if (df_insn_info *insn_info = DF_INSN_INFO_GET (insn)) |
0 | 1507 { |
111 | 1508 df_ref def, use; |
1509 | |
0 | 1510 /* Need to update next use. */ |
111 | 1511 FOR_EACH_INSN_INFO_DEF (def, insn_info) |
0 | 1512 { |
1513 reg_next_use[DF_REF_REGNO (def)] = NULL; | |
1514 reg_next_inc_use[DF_REF_REGNO (def)] = NULL; | |
1515 reg_next_def[DF_REF_REGNO (def)] = insn; | |
1516 } | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1517 |
111 | 1518 FOR_EACH_INSN_INFO_USE (use, insn_info) |
0 | 1519 { |
1520 reg_next_use[DF_REF_REGNO (use)] = insn; | |
1521 if (insn_is_add_or_inc) | |
1522 reg_next_inc_use[DF_REF_REGNO (use)] = insn; | |
1523 else | |
1524 reg_next_inc_use[DF_REF_REGNO (use)] = NULL; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1525 } |
0 | 1526 } |
1527 else if (dump_file) | |
111 | 1528 fprintf (dump_file, "skipping update of deleted insn %d\n", |
1529 INSN_UID (insn)); | |
0 | 1530 } |
1531 | |
1532 /* If we were successful, try again. There may have been several | |
1533 opportunities that were interleaved. This is rare but | |
1534 gcc.c-torture/compile/pr17273.c actually exhibits this. */ | |
1535 if (success_in_block) | |
1536 { | |
1537 /* In this case, we must clear these vectors since the trick of | |
1538 testing if the stale insn in the block will not work. */ | |
111 | 1539 memset (reg_next_use, 0, max_reg * sizeof (rtx)); |
1540 memset (reg_next_inc_use, 0, max_reg * sizeof (rtx)); | |
1541 memset (reg_next_def, 0, max_reg * sizeof (rtx)); | |
0 | 1542 df_recompute_luids (bb); |
1543 merge_in_block (max_reg, bb); | |
1544 } | |
1545 } | |
1546 | |
111 | 1547 /* Discover auto-inc auto-dec instructions. */ |
1548 | |
1549 namespace { | |
1550 | |
1551 const pass_data pass_data_inc_dec = | |
1552 { | |
1553 RTL_PASS, /* type */ | |
1554 "auto_inc_dec", /* name */ | |
1555 OPTGROUP_NONE, /* optinfo_flags */ | |
1556 TV_AUTO_INC_DEC, /* tv_id */ | |
1557 0, /* properties_required */ | |
1558 0, /* properties_provided */ | |
1559 0, /* properties_destroyed */ | |
1560 0, /* todo_flags_start */ | |
1561 TODO_df_finish, /* todo_flags_finish */ | |
1562 }; | |
0 | 1563 |
111 | 1564 class pass_inc_dec : public rtl_opt_pass |
0 | 1565 { |
111 | 1566 public: |
1567 pass_inc_dec (gcc::context *ctxt) | |
1568 : rtl_opt_pass (pass_data_inc_dec, ctxt) | |
1569 {} | |
1570 | |
1571 /* opt_pass methods: */ | |
1572 virtual bool gate (function *) | |
1573 { | |
1574 if (!AUTO_INC_DEC) | |
1575 return false; | |
1576 | |
1577 return (optimize > 0 && flag_auto_inc_dec); | |
1578 } | |
1579 | |
1580 | |
1581 unsigned int execute (function *); | |
1582 | |
1583 }; // class pass_inc_dec | |
1584 | |
1585 unsigned int | |
1586 pass_inc_dec::execute (function *fun ATTRIBUTE_UNUSED) | |
1587 { | |
1588 if (!AUTO_INC_DEC) | |
1589 return 0; | |
1590 | |
0 | 1591 basic_block bb; |
1592 int max_reg = max_reg_num (); | |
1593 | |
1594 if (!initialized) | |
1595 init_decision_table (); | |
1596 | |
1597 mem_tmp = gen_rtx_MEM (Pmode, NULL_RTX); | |
1598 | |
1599 df_note_add_problem (); | |
1600 df_analyze (); | |
1601 | |
111 | 1602 reg_next_use = XCNEWVEC (rtx_insn *, max_reg); |
1603 reg_next_inc_use = XCNEWVEC (rtx_insn *, max_reg); | |
1604 reg_next_def = XCNEWVEC (rtx_insn *, max_reg); | |
1605 FOR_EACH_BB_FN (bb, fun) | |
0 | 1606 merge_in_block (max_reg, bb); |
1607 | |
1608 free (reg_next_use); | |
1609 free (reg_next_inc_use); | |
1610 free (reg_next_def); | |
1611 | |
1612 mem_tmp = NULL; | |
111 | 1613 |
0 | 1614 return 0; |
1615 } | |
1616 | |
111 | 1617 } // anon namespace |
0 | 1618 |
111 | 1619 rtl_opt_pass * |
1620 make_pass_inc_dec (gcc::context *ctxt) | |
0 | 1621 { |
111 | 1622 return new pass_inc_dec (ctxt); |
1623 } |