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