xref: /dflybsd-src/contrib/gcc-4.7/gcc/auto-inc-dec.c (revision 04febcfb30580676d3e95f58a16c5137ee478b32)
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