OSDN Git Service

* regmove.c (perhaps_ends_bb_p): Remove.
[pf3gnuchains/gcc-fork.git] / gcc / regmove.c
1 /* Move registers around to reduce number of move instructions needed.
2    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
3    1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
4    Free Software Foundation, Inc.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3.  If not see
20 <http://www.gnu.org/licenses/>.  */
21
22
23 /* This module makes some simple RTL code transformations which
24    improve the subsequent register allocation.  */
25
26 #include "config.h"
27 #include "system.h"
28 #include "coretypes.h"
29 #include "tm.h"
30 #include "rtl.h" /* stdio.h must precede rtl.h for FFS.  */
31 #include "tm_p.h"
32 #include "insn-config.h"
33 #include "recog.h"
34 #include "output.h"
35 #include "regs.h"
36 #include "hard-reg-set.h"
37 #include "flags.h"
38 #include "function.h"
39 #include "expr.h"
40 #include "basic-block.h"
41 #include "except.h"
42 #include "toplev.h"
43 #include "reload.h"
44 #include "timevar.h"
45 #include "tree-pass.h"
46 #include "df.h"
47
48 static int optimize_reg_copy_1 (rtx, rtx, rtx);
49 static void optimize_reg_copy_2 (rtx, rtx, rtx);
50 static void optimize_reg_copy_3 (rtx, rtx, rtx);
51 static void copy_src_to_dest (rtx, rtx, rtx);
52
53 struct match {
54   int with[MAX_RECOG_OPERANDS];
55   enum { READ, WRITE, READWRITE } use[MAX_RECOG_OPERANDS];
56   int commutative[MAX_RECOG_OPERANDS];
57   int early_clobber[MAX_RECOG_OPERANDS];
58 };
59
60 static int find_matches (rtx, struct match *);
61 static int regclass_compatible_p (int, int);
62 static int fixup_match_2 (rtx, rtx, rtx, rtx);
63
64 /* Return nonzero if registers with CLASS1 and CLASS2 can be merged without
65    causing too much register allocation problems.  */
66 static int
67 regclass_compatible_p (int class0, int class1)
68 {
69   return (class0 == class1
70           || (reg_class_subset_p (class0, class1)
71               && ! CLASS_LIKELY_SPILLED_P (class0))
72           || (reg_class_subset_p (class1, class0)
73               && ! CLASS_LIKELY_SPILLED_P (class1)));
74 }
75
76 \f
77 #ifdef AUTO_INC_DEC
78
79 /* Find the place in the rtx X where REG is used as a memory address.
80    Return the MEM rtx that so uses it.
81    If PLUSCONST is nonzero, search instead for a memory address equivalent to
82    (plus REG (const_int PLUSCONST)).
83
84    If such an address does not appear, return 0.
85    If REG appears more than once, or is used other than in such an address,
86    return (rtx) 1.  */
87
88 static rtx
89 find_use_as_address (rtx x, rtx reg, HOST_WIDE_INT plusconst)
90 {
91   enum rtx_code code = GET_CODE (x);
92   const char * const fmt = GET_RTX_FORMAT (code);
93   int i;
94   rtx value = 0;
95   rtx tem;
96
97   if (code == MEM && XEXP (x, 0) == reg && plusconst == 0)
98     return x;
99
100   if (code == MEM && GET_CODE (XEXP (x, 0)) == PLUS
101       && XEXP (XEXP (x, 0), 0) == reg
102       && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
103       && INTVAL (XEXP (XEXP (x, 0), 1)) == plusconst)
104     return x;
105
106   if (code == SIGN_EXTRACT || code == ZERO_EXTRACT)
107     {
108       /* If REG occurs inside a MEM used in a bit-field reference,
109          that is unacceptable.  */
110       if (find_use_as_address (XEXP (x, 0), reg, 0) != 0)
111         return (rtx) (size_t) 1;
112     }
113
114   if (x == reg)
115     return (rtx) (size_t) 1;
116
117   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
118     {
119       if (fmt[i] == 'e')
120         {
121           tem = find_use_as_address (XEXP (x, i), reg, plusconst);
122           if (value == 0)
123             value = tem;
124           else if (tem != 0)
125             return (rtx) (size_t) 1;
126         }
127       else if (fmt[i] == 'E')
128         {
129           int j;
130           for (j = XVECLEN (x, i) - 1; j >= 0; j--)
131             {
132               tem = find_use_as_address (XVECEXP (x, i, j), reg, plusconst);
133               if (value == 0)
134                 value = tem;
135               else if (tem != 0)
136                 return (rtx) (size_t) 1;
137             }
138         }
139     }
140
141   return value;
142 }
143
144
145 /* INC_INSN is an instruction that adds INCREMENT to REG.
146    Try to fold INC_INSN as a post/pre in/decrement into INSN.
147    Iff INC_INSN_SET is nonzero, inc_insn has a destination different from src.
148    Return nonzero for success.  */
149 static int
150 try_auto_increment (rtx insn, rtx inc_insn, rtx inc_insn_set, rtx reg,
151                     HOST_WIDE_INT increment, int pre)
152 {
153   enum rtx_code inc_code;
154
155   rtx pset = single_set (insn);
156   if (pset)
157     {
158       /* Can't use the size of SET_SRC, we might have something like
159          (sign_extend:SI (mem:QI ...  */
160       rtx use = find_use_as_address (pset, reg, 0);
161       if (use != 0 && use != (rtx) (size_t) 1)
162         {
163           int size = GET_MODE_SIZE (GET_MODE (use));
164           if (0
165               || (HAVE_POST_INCREMENT
166                   && pre == 0 && (inc_code = POST_INC, increment == size))
167               || (HAVE_PRE_INCREMENT
168                   && pre == 1 && (inc_code = PRE_INC, increment == size))
169               || (HAVE_POST_DECREMENT
170                   && pre == 0 && (inc_code = POST_DEC, increment == -size))
171               || (HAVE_PRE_DECREMENT
172                   && pre == 1 && (inc_code = PRE_DEC, increment == -size))
173           )
174             {
175               if (inc_insn_set)
176                 validate_change
177                   (inc_insn,
178                    &SET_SRC (inc_insn_set),
179                    XEXP (SET_SRC (inc_insn_set), 0), 1);
180               validate_change (insn, &XEXP (use, 0),
181                                gen_rtx_fmt_e (inc_code, Pmode, reg), 1);
182               if (apply_change_group ())
183                 {
184                   /* If there is a REG_DEAD note on this insn, we must
185                      change this not to REG_UNUSED meaning that the register
186                      is set, but the value is dead.  Failure to do so will
187                      result in sched1 dying -- when it recomputes lifetime
188                      information, the number of REG_DEAD notes will have
189                      changed.  */
190                   rtx note = find_reg_note (insn, REG_DEAD, reg);
191                   if (note)
192                     PUT_MODE (note, REG_UNUSED);
193
194                   add_reg_note (insn, REG_INC, reg);
195
196                   if (! inc_insn_set)
197                     delete_insn (inc_insn);
198                   return 1;
199                 }
200             }
201         }
202     }
203   return 0;
204 }
205 #endif
206
207 \f
208 static int *regno_src_regno;
209
210 /* INSN is a copy from SRC to DEST, both registers, and SRC does not die
211    in INSN.
212
213    Search forward to see if SRC dies before either it or DEST is modified,
214    but don't scan past the end of a basic block.  If so, we can replace SRC
215    with DEST and let SRC die in INSN.
216
217    This will reduce the number of registers live in that range and may enable
218    DEST to be tied to SRC, thus often saving one register in addition to a
219    register-register copy.  */
220
221 static int
222 optimize_reg_copy_1 (rtx insn, rtx dest, rtx src)
223 {
224   rtx p, q;
225   rtx note;
226   rtx dest_death = 0;
227   int sregno = REGNO (src);
228   int dregno = REGNO (dest);
229   basic_block bb = BLOCK_FOR_INSN (insn);
230
231   /* We don't want to mess with hard regs if register classes are small.  */
232   if (sregno == dregno
233       || (SMALL_REGISTER_CLASSES
234           && (sregno < FIRST_PSEUDO_REGISTER
235               || dregno < FIRST_PSEUDO_REGISTER))
236       /* We don't see all updates to SP if they are in an auto-inc memory
237          reference, so we must disallow this optimization on them.  */
238       || sregno == STACK_POINTER_REGNUM || dregno == STACK_POINTER_REGNUM)
239     return 0;
240
241   for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
242     {
243       if (! INSN_P (p))
244         continue;
245       if (BLOCK_FOR_INSN (p) != bb)
246         break;
247
248       if (reg_set_p (src, p) || reg_set_p (dest, p)
249           /* If SRC is an asm-declared register, it must not be replaced
250              in any asm.  Unfortunately, the REG_EXPR tree for the asm
251              variable may be absent in the SRC rtx, so we can't check the
252              actual register declaration easily (the asm operand will have
253              it, though).  To avoid complicating the test for a rare case,
254              we just don't perform register replacement for a hard reg
255              mentioned in an asm.  */
256           || (sregno < FIRST_PSEUDO_REGISTER
257               && asm_noperands (PATTERN (p)) >= 0
258               && reg_overlap_mentioned_p (src, PATTERN (p)))
259           /* Don't change hard registers used by a call.  */
260           || (CALL_P (p) && sregno < FIRST_PSEUDO_REGISTER
261               && find_reg_fusage (p, USE, src))
262           /* Don't change a USE of a register.  */
263           || (GET_CODE (PATTERN (p)) == USE
264               && reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0))))
265         break;
266
267       /* See if all of SRC dies in P.  This test is slightly more
268          conservative than it needs to be.  */
269       if ((note = find_regno_note (p, REG_DEAD, sregno)) != 0
270           && GET_MODE (XEXP (note, 0)) == GET_MODE (src))
271         {
272           int failed = 0;
273           int d_length = 0;
274           int s_length = 0;
275           int d_n_calls = 0;
276           int s_n_calls = 0;
277           int s_freq_calls = 0;
278           int d_freq_calls = 0;
279
280           /* We can do the optimization.  Scan forward from INSN again,
281              replacing regs as we go.  Set FAILED if a replacement can't
282              be done.  In that case, we can't move the death note for SRC.
283              This should be rare.  */
284
285           /* Set to stop at next insn.  */
286           for (q = next_real_insn (insn);
287                q != next_real_insn (p);
288                q = next_real_insn (q))
289             {
290               if (reg_overlap_mentioned_p (src, PATTERN (q)))
291                 {
292                   /* If SRC is a hard register, we might miss some
293                      overlapping registers with validate_replace_rtx,
294                      so we would have to undo it.  We can't if DEST is
295                      present in the insn, so fail in that combination
296                      of cases.  */
297                   if (sregno < FIRST_PSEUDO_REGISTER
298                       && reg_mentioned_p (dest, PATTERN (q)))
299                     failed = 1;
300                   
301                   /* Attempt to replace all uses.  */
302                   else if (!validate_replace_rtx (src, dest, q))
303                     failed = 1;
304
305                   /* If this succeeded, but some part of the register
306                      is still present, undo the replacement.  */
307                   else if (sregno < FIRST_PSEUDO_REGISTER
308                            && reg_overlap_mentioned_p (src, PATTERN (q)))
309                     {
310                       validate_replace_rtx (dest, src, q);
311                       failed = 1;
312                     }
313                 }
314
315               /* For SREGNO, count the total number of insns scanned.
316                  For DREGNO, count the total number of insns scanned after
317                  passing the death note for DREGNO.  */
318               s_length++;
319               if (dest_death)
320                 d_length++;
321
322               /* If the insn in which SRC dies is a CALL_INSN, don't count it
323                  as a call that has been crossed.  Otherwise, count it.  */
324               if (q != p && CALL_P (q))
325                 {
326                   /* Similarly, total calls for SREGNO, total calls beyond
327                      the death note for DREGNO.  */
328                   s_n_calls++;
329                   s_freq_calls += REG_FREQ_FROM_BB  (BLOCK_FOR_INSN (q));
330                   if (dest_death)
331                     {
332                       d_n_calls++;
333                       d_freq_calls += REG_FREQ_FROM_BB  (BLOCK_FOR_INSN (q));
334                     }
335                 }
336
337               /* If DEST dies here, remove the death note and save it for
338                  later.  Make sure ALL of DEST dies here; again, this is
339                  overly conservative.  */
340               if (dest_death == 0
341                   && (dest_death = find_regno_note (q, REG_DEAD, dregno)) != 0)
342                 {
343                   if (GET_MODE (XEXP (dest_death, 0)) != GET_MODE (dest))
344                     failed = 1, dest_death = 0;
345                   else
346                     remove_note (q, dest_death);
347                 }
348             }
349
350           if (! failed)
351             {
352               /* These counters need to be updated if and only if we are
353                  going to move the REG_DEAD note.  */
354               if (sregno >= FIRST_PSEUDO_REGISTER)
355                 {
356                   if (REG_LIVE_LENGTH (sregno) >= 0)
357                     {
358                       REG_LIVE_LENGTH (sregno) -= s_length;
359                       /* REG_LIVE_LENGTH is only an approximation after
360                          combine if sched is not run, so make sure that we
361                          still have a reasonable value.  */
362                       if (REG_LIVE_LENGTH (sregno) < 2)
363                         REG_LIVE_LENGTH (sregno) = 2;
364                     }
365
366                   REG_N_CALLS_CROSSED (sregno) -= s_n_calls;
367                   REG_FREQ_CALLS_CROSSED (sregno) -= s_freq_calls;
368                 }
369
370               /* Move death note of SRC from P to INSN.  */
371               remove_note (p, note);
372               XEXP (note, 1) = REG_NOTES (insn);
373               REG_NOTES (insn) = note;
374             }
375
376           /* DEST is also dead if INSN has a REG_UNUSED note for DEST.  */
377           if (! dest_death
378               && (dest_death = find_regno_note (insn, REG_UNUSED, dregno)))
379             {
380               PUT_REG_NOTE_KIND (dest_death, REG_DEAD);
381               remove_note (insn, dest_death);
382             }
383
384           /* Put death note of DEST on P if we saw it die.  */
385           if (dest_death)
386             {
387               XEXP (dest_death, 1) = REG_NOTES (p);
388               REG_NOTES (p) = dest_death;
389
390               if (dregno >= FIRST_PSEUDO_REGISTER)
391                 {
392                   /* If and only if we are moving the death note for DREGNO,
393                      then we need to update its counters.  */
394                   if (REG_LIVE_LENGTH (dregno) >= 0)
395                     REG_LIVE_LENGTH (dregno) += d_length;
396                   REG_N_CALLS_CROSSED (dregno) += d_n_calls;
397                   REG_FREQ_CALLS_CROSSED (dregno) += d_freq_calls;
398                 }
399             }
400
401           return ! failed;
402         }
403
404       /* If SRC is a hard register which is set or killed in some other
405          way, we can't do this optimization.  */
406       else if (sregno < FIRST_PSEUDO_REGISTER
407                && dead_or_set_p (p, src))
408         break;
409     }
410   return 0;
411 }
412 \f
413 /* INSN is a copy of SRC to DEST, in which SRC dies.  See if we now have
414    a sequence of insns that modify DEST followed by an insn that sets
415    SRC to DEST in which DEST dies, with no prior modification of DEST.
416    (There is no need to check if the insns in between actually modify
417    DEST.  We should not have cases where DEST is not modified, but
418    the optimization is safe if no such modification is detected.)
419    In that case, we can replace all uses of DEST, starting with INSN and
420    ending with the set of SRC to DEST, with SRC.  We do not do this
421    optimization if a CALL_INSN is crossed unless SRC already crosses a
422    call or if DEST dies before the copy back to SRC.
423
424    It is assumed that DEST and SRC are pseudos; it is too complicated to do
425    this for hard registers since the substitutions we may make might fail.  */
426
427 static void
428 optimize_reg_copy_2 (rtx insn, rtx dest, rtx src)
429 {
430   rtx p, q;
431   rtx set;
432   int sregno = REGNO (src);
433   int dregno = REGNO (dest);
434   basic_block bb = BLOCK_FOR_INSN (insn);
435
436   for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
437     {
438       if (! INSN_P (p))
439         continue;
440       if (BLOCK_FOR_INSN (p) != bb)
441         break;
442
443       set = single_set (p);
444       if (set && SET_SRC (set) == dest && SET_DEST (set) == src
445           && find_reg_note (p, REG_DEAD, dest))
446         {
447           /* We can do the optimization.  Scan forward from INSN again,
448              replacing regs as we go.  */
449
450           /* Set to stop at next insn.  */
451           for (q = insn; q != NEXT_INSN (p); q = NEXT_INSN (q))
452             if (INSN_P (q))
453               {
454                 if (reg_mentioned_p (dest, PATTERN (q)))
455                   {
456                     rtx note;
457
458                     PATTERN (q) = replace_rtx (PATTERN (q), dest, src);
459                     note = FIND_REG_INC_NOTE (q, dest);
460                     if (note)
461                       {
462                         remove_note (q, note);
463                         add_reg_note (q, REG_INC, src);
464                       }
465                     df_insn_rescan (q);
466                   }
467
468                 if (CALL_P (q))
469                   {
470                     int freq = REG_FREQ_FROM_BB  (BLOCK_FOR_INSN (q));
471                     REG_N_CALLS_CROSSED (dregno)--;
472                     REG_N_CALLS_CROSSED (sregno)++;
473                     REG_FREQ_CALLS_CROSSED (dregno) -= freq;
474                     REG_FREQ_CALLS_CROSSED (sregno) += freq;
475                   }
476               }
477
478           remove_note (p, find_reg_note (p, REG_DEAD, dest));
479           REG_N_DEATHS (dregno)--;
480           remove_note (insn, find_reg_note (insn, REG_DEAD, src));
481           REG_N_DEATHS (sregno)--;
482           return;
483         }
484
485       if (reg_set_p (src, p)
486           || find_reg_note (p, REG_DEAD, dest)
487           || (CALL_P (p) && REG_N_CALLS_CROSSED (sregno) == 0))
488         break;
489     }
490 }
491
492 /* INSN is a ZERO_EXTEND or SIGN_EXTEND of SRC to DEST.
493    Look if SRC dies there, and if it is only set once, by loading
494    it from memory.  If so, try to incorporate the zero/sign extension
495    into the memory read, change SRC to the mode of DEST, and alter
496    the remaining accesses to use the appropriate SUBREG.  This allows
497    SRC and DEST to be tied later.  */
498 static void
499 optimize_reg_copy_3 (rtx insn, rtx dest, rtx src)
500 {
501   rtx src_reg = XEXP (src, 0);
502   int src_no = REGNO (src_reg);
503   int dst_no = REGNO (dest);
504   rtx p, set;
505   enum machine_mode old_mode;
506   basic_block bb = BLOCK_FOR_INSN (insn);
507
508   if (src_no < FIRST_PSEUDO_REGISTER
509       || dst_no < FIRST_PSEUDO_REGISTER
510       || ! find_reg_note (insn, REG_DEAD, src_reg)
511       || REG_N_DEATHS (src_no) != 1
512       || REG_N_SETS (src_no) != 1)
513     return;
514
515   for (p = PREV_INSN (insn); p && ! reg_set_p (src_reg, p); p = PREV_INSN (p))
516     if (INSN_P (p) && BLOCK_FOR_INSN (p) != bb)
517       break;
518   
519   if (! p || BLOCK_FOR_INSN (p) != bb)
520     return;
521
522   if (! (set = single_set (p))
523       || !MEM_P (SET_SRC (set))
524       /* If there's a REG_EQUIV note, this must be an insn that loads an
525          argument.  Prefer keeping the note over doing this optimization.  */
526       || find_reg_note (p, REG_EQUIV, NULL_RTX)
527       || SET_DEST (set) != src_reg)
528     return;
529
530   /* Be conservative: although this optimization is also valid for
531      volatile memory references, that could cause trouble in later passes.  */
532   if (MEM_VOLATILE_P (SET_SRC (set)))
533     return;
534
535   /* Do not use a SUBREG to truncate from one mode to another if truncation
536      is not a nop.  */
537   if (GET_MODE_BITSIZE (GET_MODE (src_reg)) <= GET_MODE_BITSIZE (GET_MODE (src))
538       && !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (src)),
539                                  GET_MODE_BITSIZE (GET_MODE (src_reg))))
540     return;
541
542   old_mode = GET_MODE (src_reg);
543   PUT_MODE (src_reg, GET_MODE (src));
544   XEXP (src, 0) = SET_SRC (set);
545
546   /* Include this change in the group so that it's easily undone if
547      one of the changes in the group is invalid.  */
548   validate_change (p, &SET_SRC (set), src, 1);
549
550   /* Now walk forward making additional replacements.  We want to be able
551      to undo all the changes if a later substitution fails.  */
552   while (p = NEXT_INSN (p), p != insn)
553     {
554       if (! INSN_P (p))
555         continue;
556
557       /* Make a tentative change.  */
558       validate_replace_rtx_group (src_reg,
559                                   gen_lowpart_SUBREG (old_mode, src_reg),
560                                   p);
561     }
562
563   validate_replace_rtx_group (src, src_reg, insn);
564
565   /* Now see if all the changes are valid.  */
566   if (! apply_change_group ())
567     {
568       /* One or more changes were no good.  Back out everything.  */
569       PUT_MODE (src_reg, old_mode);
570       XEXP (src, 0) = src_reg;
571     }
572   else
573     {
574       rtx note = find_reg_note (p, REG_EQUAL, NULL_RTX);
575       if (note)
576         remove_note (p, note);
577     }
578 }
579
580 \f
581 /* If we were not able to update the users of src to use dest directly, try
582    instead moving the value to dest directly before the operation.  */
583
584 static void
585 copy_src_to_dest (rtx insn, rtx src, rtx dest)
586 {
587   rtx seq;
588   rtx link;
589   rtx next;
590   rtx set;
591   rtx move_insn;
592   rtx *p_insn_notes;
593   rtx *p_move_notes;
594   int src_regno;
595   int dest_regno;
596   int insn_uid;
597   int move_uid;
598
599   /* A REG_LIVE_LENGTH of -1 indicates the register is equivalent to a constant
600      or memory location and is used infrequently; a REG_LIVE_LENGTH of -2 is
601      parameter when there is no frame pointer that is not allocated a register.
602      For now, we just reject them, rather than incrementing the live length.  */
603
604   if (REG_P (src)
605       && REG_LIVE_LENGTH (REGNO (src)) > 0
606       && REG_P (dest)
607       && REG_LIVE_LENGTH (REGNO (dest)) > 0
608       && (set = single_set (insn)) != NULL_RTX
609       && !reg_mentioned_p (dest, SET_SRC (set))
610       && GET_MODE (src) == GET_MODE (dest))
611     {
612       int old_num_regs = reg_rtx_no;
613
614       /* Generate the src->dest move.  */
615       start_sequence ();
616       emit_move_insn (dest, src);
617       seq = get_insns ();
618       end_sequence ();
619       /* If this sequence uses new registers, we may not use it.  */
620       if (old_num_regs != reg_rtx_no
621           || ! validate_replace_rtx (src, dest, insn))
622         {
623           /* We have to restore reg_rtx_no to its old value, lest
624              recompute_reg_usage will try to compute the usage of the
625              new regs, yet reg_n_info is not valid for them.  */
626           reg_rtx_no = old_num_regs;
627           return;
628         }
629       emit_insn_before (seq, insn);
630       move_insn = PREV_INSN (insn);
631       p_move_notes = &REG_NOTES (move_insn);
632       p_insn_notes = &REG_NOTES (insn);
633
634       /* Move any notes mentioning src to the move instruction.  */
635       for (link = REG_NOTES (insn); link != NULL_RTX; link = next)
636         {
637           next = XEXP (link, 1);
638           if (XEXP (link, 0) == src)
639             {
640               *p_move_notes = link;
641               p_move_notes = &XEXP (link, 1);
642             }
643           else
644             {
645               *p_insn_notes = link;
646               p_insn_notes = &XEXP (link, 1);
647             }
648         }
649
650       *p_move_notes = NULL_RTX;
651       *p_insn_notes = NULL_RTX;
652
653       insn_uid = INSN_UID (insn);
654       move_uid = INSN_UID (move_insn);
655
656       /* Update the various register tables.  */
657       dest_regno = REGNO (dest);
658       INC_REG_N_SETS (dest_regno, 1);
659       REG_LIVE_LENGTH (dest_regno)++;
660       src_regno = REGNO (src);
661       if (! find_reg_note (move_insn, REG_DEAD, src))
662         REG_LIVE_LENGTH (src_regno)++;
663     }
664 }
665
666 /* reg_set_in_bb[REGNO] points to basic block iff the register is set
667    only once in the given block and has REG_EQUAL note.  */
668
669 static basic_block *reg_set_in_bb;
670
671 /* Size of reg_set_in_bb array.  */
672 static unsigned int max_reg_computed;
673
674 \f
675 /* Return whether REG is set in only one location, and is set to a
676    constant, but is set in a different basic block from INSN (an
677    instructions which uses REG).  In this case REG is equivalent to a
678    constant, and we don't want to break that equivalence, because that
679    may increase register pressure and make reload harder.  If REG is
680    set in the same basic block as INSN, we don't worry about it,
681    because we'll probably need a register anyhow (??? but what if REG
682    is used in a different basic block as well as this one?).  */
683
684 static bool
685 reg_is_remote_constant_p (rtx reg, rtx insn)
686 {
687   basic_block bb;
688   rtx p;
689   int max;
690
691   if (!reg_set_in_bb)
692     {
693       max_reg_computed = max = max_reg_num ();
694       reg_set_in_bb = XCNEWVEC (basic_block, max);
695
696       FOR_EACH_BB (bb)
697         FOR_BB_INSNS (bb, p)
698           {
699             rtx s;
700
701             if (!INSN_P (p))
702               continue;
703             s = single_set (p);
704             /* This is the instruction which sets REG.  If there is a
705                REG_EQUAL note, then REG is equivalent to a constant.  */
706             if (s != 0
707                 && REG_P (SET_DEST (s))
708                 && REG_N_SETS (REGNO (SET_DEST (s))) == 1
709                 && find_reg_note (p, REG_EQUAL, NULL_RTX))
710               reg_set_in_bb[REGNO (SET_DEST (s))] = bb;
711           }
712     }
713
714   gcc_assert (REGNO (reg) < max_reg_computed);
715   if (reg_set_in_bb[REGNO (reg)] == NULL)
716     return false;
717   return (reg_set_in_bb[REGNO (reg)] != BLOCK_FOR_INSN (insn));
718 }
719
720 /* INSN is adding a CONST_INT to a REG.  We search backwards looking for
721    another add immediate instruction with the same source and dest registers,
722    and if we find one, we change INSN to an increment, and return 1.  If
723    no changes are made, we return 0.
724
725    This changes
726      (set (reg100) (plus reg1 offset1))
727      ...
728      (set (reg100) (plus reg1 offset2))
729    to
730      (set (reg100) (plus reg1 offset1))
731      ...
732      (set (reg100) (plus reg100 offset2-offset1))  */
733
734 /* ??? What does this comment mean?  */
735 /* cse disrupts preincrement / postdecrement sequences when it finds a
736    hard register as ultimate source, like the frame pointer.  */
737
738 static int
739 fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset)
740 {
741   rtx p, dst_death = 0;
742   int length, num_calls = 0, freq_calls = 0;
743   basic_block bb = BLOCK_FOR_INSN (insn);
744
745   /* If SRC dies in INSN, we'd have to move the death note.  This is
746      considered to be very unlikely, so we just skip the optimization
747      in this case.  */
748   if (find_regno_note (insn, REG_DEAD, REGNO (src)))
749     return 0;
750
751   /* Scan backward to find the first instruction that sets DST.  */
752
753   for (length = 0, p = PREV_INSN (insn); p; p = PREV_INSN (p))
754     {
755       rtx pset;
756
757       if (! INSN_P (p))
758         continue;
759       if (BLOCK_FOR_INSN (p) != bb)
760         break;
761
762       if (find_regno_note (p, REG_DEAD, REGNO (dst)))
763         dst_death = p;
764       if (! dst_death)
765         length++;
766
767       pset = single_set (p);
768       if (pset && SET_DEST (pset) == dst
769           && GET_CODE (SET_SRC (pset)) == PLUS
770           && XEXP (SET_SRC (pset), 0) == src
771           && GET_CODE (XEXP (SET_SRC (pset), 1)) == CONST_INT)
772         {
773           HOST_WIDE_INT newconst
774             = INTVAL (offset) - INTVAL (XEXP (SET_SRC (pset), 1));
775           rtx add = gen_add3_insn (dst, dst, GEN_INT (newconst));
776
777           if (add && validate_change (insn, &PATTERN (insn), add, 0))
778             {
779               /* Remove the death note for DST from DST_DEATH.  */
780               if (dst_death)
781                 {
782                   remove_death (REGNO (dst), dst_death);
783                   REG_LIVE_LENGTH (REGNO (dst)) += length;
784                   REG_N_CALLS_CROSSED (REGNO (dst)) += num_calls;
785                   REG_FREQ_CALLS_CROSSED (REGNO (dst)) += freq_calls;
786                 }
787
788               if (dump_file)
789                 fprintf (dump_file,
790                          "Fixed operand of insn %d.\n",
791                           INSN_UID (insn));
792
793 #ifdef AUTO_INC_DEC
794               for (p = PREV_INSN (insn); p; p = PREV_INSN (p))
795                 {
796                   if (! INSN_P (p))
797                     continue;
798                   if (BLOCK_FOR_INSN (p) != bb)
799                     break;
800                   if (reg_overlap_mentioned_p (dst, PATTERN (p)))
801                     {
802                       if (try_auto_increment (p, insn, 0, dst, newconst, 0))
803                         return 1;
804                       break;
805                     }
806                 }
807               for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
808                 {
809                   if (! INSN_P (p))
810                     continue;
811                   if (BLOCK_FOR_INSN (p) != bb)
812                     break;
813                   if (reg_overlap_mentioned_p (dst, PATTERN (p)))
814                     {
815                       try_auto_increment (p, insn, 0, dst, newconst, 1);
816                       break;
817                     }
818                 }
819 #endif
820               return 1;
821             }
822         }
823
824       if (reg_set_p (dst, PATTERN (p)))
825         break;
826
827       /* If we have passed a call instruction, and the
828          pseudo-reg SRC is not already live across a call,
829          then don't perform the optimization.  */
830       /* reg_set_p is overly conservative for CALL_INSNS, thinks that all
831          hard regs are clobbered.  Thus, we only use it for src for
832          non-call insns.  */
833       if (CALL_P (p))
834         {
835           if (! dst_death)
836             {
837               num_calls++;
838               freq_calls += REG_FREQ_FROM_BB  (BLOCK_FOR_INSN (p));
839             }
840
841           if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
842             break;
843
844           if (call_used_regs [REGNO (dst)]
845               || find_reg_fusage (p, CLOBBER, dst))
846             break;
847         }
848       else if (reg_set_p (src, PATTERN (p)))
849         break;
850     }
851
852   return 0;
853 }
854
855 /* A forward pass.  Replace output operands with input operands.  */
856
857 static void
858 regmove_forward_pass (void)
859 {
860   basic_block bb;
861   rtx insn;
862
863   if (! flag_expensive_optimizations)
864     return;
865
866   if (dump_file)
867     fprintf (dump_file, "Starting forward pass...\n");
868
869   FOR_EACH_BB (bb)
870     {
871       FOR_BB_INSNS (bb, insn)
872         {
873           rtx set = single_set (insn);
874           if (! set)
875             continue;
876
877           if ((GET_CODE (SET_SRC (set)) == SIGN_EXTEND
878                || GET_CODE (SET_SRC (set)) == ZERO_EXTEND)
879               && REG_P (XEXP (SET_SRC (set), 0))
880               && REG_P (SET_DEST (set)))
881             optimize_reg_copy_3 (insn, SET_DEST (set), SET_SRC (set));
882
883           if (REG_P (SET_SRC (set))
884               && REG_P (SET_DEST (set)))
885             {
886               /* If this is a register-register copy where SRC is not dead,
887                  see if we can optimize it.  If this optimization succeeds,
888                  it will become a copy where SRC is dead.  */
889               if ((find_reg_note (insn, REG_DEAD, SET_SRC (set))
890                    || optimize_reg_copy_1 (insn, SET_DEST (set), SET_SRC (set)))
891                   && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER)
892                 {
893                   /* Similarly for a pseudo-pseudo copy when SRC is dead.  */
894                   if (REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER)
895                     optimize_reg_copy_2 (insn, SET_DEST (set), SET_SRC (set));
896                   if (regno_src_regno[REGNO (SET_DEST (set))] < 0
897                       && SET_SRC (set) != SET_DEST (set))
898                     {
899                       int srcregno = REGNO (SET_SRC (set));
900                       if (regno_src_regno[srcregno] >= 0)
901                         srcregno = regno_src_regno[srcregno];
902                       regno_src_regno[REGNO (SET_DEST (set))] = srcregno;
903                     }
904                 }
905             }
906         }
907     }
908 }
909
910 /* A backward pass.  Replace input operands with output operands.  */
911
912 static void
913 regmove_backward_pass (void)
914 {
915   basic_block bb;
916   rtx insn, prev;
917
918   if (dump_file)
919     fprintf (dump_file, "Starting backward pass...\n");
920
921   FOR_EACH_BB_REVERSE (bb)
922     {
923       /* ??? Use the safe iterator because fixup_match_2 can remove
924              insns via try_auto_increment.  */ 
925       FOR_BB_INSNS_REVERSE_SAFE (bb, insn, prev)
926         {
927           struct match match;
928           rtx copy_src, copy_dst;
929           int op_no, match_no;
930           int success = 0;
931
932           if (! INSN_P (insn))
933             continue;
934
935           if (! find_matches (insn, &match))
936             continue;
937
938           /* Now scan through the operands looking for a destination operand
939              which is supposed to match a source operand.
940              Then scan backward for an instruction which sets the source
941              operand.  If safe, then replace the source operand with the
942              dest operand in both instructions.  */
943
944           copy_src = NULL_RTX;
945           copy_dst = NULL_RTX;
946           for (op_no = 0; op_no < recog_data.n_operands; op_no++)
947             {
948               rtx set, p, src, dst;
949               rtx src_note, dst_note;
950               int num_calls = 0, freq_calls = 0;
951               enum reg_class src_class, dst_class;
952               int length;
953
954               match_no = match.with[op_no];
955
956               /* Nothing to do if the two operands aren't supposed to match.  */
957               if (match_no < 0)
958                 continue;
959
960               dst = recog_data.operand[match_no];
961               src = recog_data.operand[op_no];
962
963               if (!REG_P (src))
964                 continue;
965
966               if (!REG_P (dst)
967                   || REGNO (dst) < FIRST_PSEUDO_REGISTER
968                   || REG_LIVE_LENGTH (REGNO (dst)) < 0
969                   || GET_MODE (src) != GET_MODE (dst))
970                 continue;
971
972               /* If the operands already match, then there is nothing to do.  */
973               if (operands_match_p (src, dst))
974                 continue;
975
976               if (match.commutative[op_no] >= 0)
977                 {
978                   rtx comm = recog_data.operand[match.commutative[op_no]];
979                   if (operands_match_p (comm, dst))
980                     continue;
981                 }
982
983               set = single_set (insn);
984               if (! set)
985                 continue;
986
987               /* Note that single_set ignores parts of a parallel set for
988                  which one of the destinations is REG_UNUSED.  We can't
989                  handle that here, since we can wind up rewriting things
990                  such that a single register is set twice within a single
991                  parallel.  */
992               if (reg_set_p (src, insn))
993                 continue;
994
995               /* match_no/dst must be a write-only operand, and
996                  operand_operand/src must be a read-only operand.  */
997               if (match.use[op_no] != READ
998                   || match.use[match_no] != WRITE)
999                 continue;
1000
1001               if (match.early_clobber[match_no]
1002                   && count_occurrences (PATTERN (insn), src, 0) > 1)
1003                 continue;
1004
1005               /* Make sure match_no is the destination.  */
1006               if (recog_data.operand[match_no] != SET_DEST (set))
1007                 continue;
1008
1009               if (REGNO (src) < FIRST_PSEUDO_REGISTER)
1010                 {
1011                   if (GET_CODE (SET_SRC (set)) == PLUS
1012                       && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT
1013                       && XEXP (SET_SRC (set), 0) == src
1014                       && fixup_match_2 (insn, dst, src,
1015                                         XEXP (SET_SRC (set), 1)))
1016                     break;
1017                   continue;
1018                 }
1019               src_class = reg_preferred_class (REGNO (src));
1020               dst_class = reg_preferred_class (REGNO (dst));
1021
1022               if (! (src_note = find_reg_note (insn, REG_DEAD, src)))
1023                 {
1024                   /* We used to force the copy here like in other cases, but
1025                      it produces worse code, as it eliminates no copy
1026                      instructions and the copy emitted will be produced by
1027                      reload anyway.  On patterns with multiple alternatives,
1028                      there may be better solution available.
1029
1030                      In particular this change produced slower code for numeric
1031                      i387 programs.  */
1032
1033                   continue;
1034                 }
1035
1036               if (! regclass_compatible_p (src_class, dst_class))
1037                 {
1038                   if (!copy_src)
1039                     {
1040                       copy_src = src;
1041                       copy_dst = dst;
1042                     }
1043                   continue;
1044                 }
1045
1046               /* Can not modify an earlier insn to set dst if this insn
1047                  uses an old value in the source.  */
1048               if (reg_overlap_mentioned_p (dst, SET_SRC (set)))
1049                 {
1050                   if (!copy_src)
1051                     {
1052                       copy_src = src;
1053                       copy_dst = dst;
1054                     }
1055                   continue;
1056                 }
1057
1058               /* If src is set once in a different basic block,
1059                  and is set equal to a constant, then do not use
1060                  it for this optimization, as this would make it
1061                  no longer equivalent to a constant.  */
1062
1063               if (reg_is_remote_constant_p (src, insn))
1064                 {
1065                   if (!copy_src)
1066                     {
1067                       copy_src = src;
1068                       copy_dst = dst;
1069                     }
1070                   continue;
1071                 }
1072
1073
1074               if (dump_file)
1075                 fprintf (dump_file,
1076                          "Could fix operand %d of insn %d matching operand %d.\n",
1077                          op_no, INSN_UID (insn), match_no);
1078
1079               /* Scan backward to find the first instruction that uses
1080                  the input operand.  If the operand is set here, then
1081                  replace it in both instructions with match_no.  */
1082
1083               for (length = 0, p = PREV_INSN (insn); p; p = PREV_INSN (p))
1084                 {
1085                   rtx pset;
1086
1087                   if (! INSN_P (p))
1088                     continue;
1089                   if (BLOCK_FOR_INSN (p) != bb)
1090                     break;
1091
1092                   length++;
1093
1094                   /* ??? See if all of SRC is set in P.  This test is much
1095                      more conservative than it needs to be.  */
1096                   pset = single_set (p);
1097                   if (pset && SET_DEST (pset) == src)
1098                     {
1099                       /* We use validate_replace_rtx, in case there
1100                          are multiple identical source operands.  All of
1101                          them have to be changed at the same time.  */
1102                       if (validate_replace_rtx (src, dst, insn))
1103                         {
1104                           if (validate_change (p, &SET_DEST (pset),
1105                                                dst, 0))
1106                             success = 1;
1107                           else
1108                             {
1109                               /* Change all source operands back.
1110                                  This modifies the dst as a side-effect.  */
1111                               validate_replace_rtx (dst, src, insn);
1112                               /* Now make sure the dst is right.  */
1113                               validate_change (insn,
1114                                                recog_data.operand_loc[match_no],
1115                                                dst, 0);
1116                             }
1117                         }
1118                       break;
1119                     }
1120
1121                   /* We can't make this change if SRC is read or
1122                      partially written in P, since we are going to
1123                      eliminate SRC. We can't make this change 
1124                      if DST is mentioned at all in P,
1125                      since we are going to change its value.  */
1126                   if (reg_overlap_mentioned_p (src, PATTERN (p))
1127                       || reg_mentioned_p (dst, PATTERN (p)))
1128                     break;
1129
1130                   /* If we have passed a call instruction, and the
1131                      pseudo-reg DST is not already live across a call,
1132                      then don't perform the optimization.  */
1133                   if (CALL_P (p))
1134                     {
1135                       num_calls++;
1136                       freq_calls += REG_FREQ_FROM_BB  (BLOCK_FOR_INSN (p));
1137
1138                       if (REG_N_CALLS_CROSSED (REGNO (dst)) == 0)
1139                         break;
1140                     }
1141                 }
1142
1143               if (success)
1144                 {
1145                   int dstno, srcno;
1146
1147                   /* Remove the death note for SRC from INSN.  */
1148                   remove_note (insn, src_note);
1149                   /* Move the death note for SRC to P if it is used
1150                      there.  */
1151                   if (reg_overlap_mentioned_p (src, PATTERN (p)))
1152                     {
1153                       XEXP (src_note, 1) = REG_NOTES (p);
1154                       REG_NOTES (p) = src_note;
1155                     }
1156                   /* If there is a REG_DEAD note for DST on P, then remove
1157                      it, because DST is now set there.  */
1158                   if ((dst_note = find_reg_note (p, REG_DEAD, dst)))
1159                     remove_note (p, dst_note);
1160
1161                   dstno = REGNO (dst);
1162                   srcno = REGNO (src);
1163
1164                   INC_REG_N_SETS (dstno, 1);
1165                   INC_REG_N_SETS (srcno, -1);
1166
1167                   REG_N_CALLS_CROSSED (dstno) += num_calls;
1168                   REG_N_CALLS_CROSSED (srcno) -= num_calls;
1169                   REG_FREQ_CALLS_CROSSED (dstno) += freq_calls;
1170                   REG_FREQ_CALLS_CROSSED (srcno) -= freq_calls;
1171
1172                   REG_LIVE_LENGTH (dstno) += length;
1173                   if (REG_LIVE_LENGTH (srcno) >= 0)
1174                     {
1175                       REG_LIVE_LENGTH (srcno) -= length;
1176                       /* REG_LIVE_LENGTH is only an approximation after
1177                          combine if sched is not run, so make sure that we
1178                          still have a reasonable value.  */
1179                       if (REG_LIVE_LENGTH (srcno) < 2)
1180                         REG_LIVE_LENGTH (srcno) = 2;
1181                     }
1182
1183                   if (dump_file)
1184                     fprintf (dump_file,
1185                              "Fixed operand %d of insn %d matching operand %d.\n",
1186                              op_no, INSN_UID (insn), match_no);
1187
1188                   break;
1189                 }
1190             }
1191
1192           /* If we weren't able to replace any of the alternatives, try an
1193              alternative approach of copying the source to the destination.  */
1194           if (!success && copy_src != NULL_RTX)
1195             copy_src_to_dest (insn, copy_src, copy_dst);
1196         }
1197     }
1198 }
1199
1200 /* Main entry for the register move optimization.  */
1201
1202 static unsigned int
1203 regmove_optimize (void)
1204 {
1205   int i;
1206   int nregs = max_reg_num ();
1207
1208   df_note_add_problem ();
1209   df_analyze ();
1210
1211   regstat_init_n_sets_and_refs ();
1212   regstat_compute_ri ();
1213
1214   regno_src_regno = XNEWVEC (int, nregs);
1215   for (i = nregs; --i >= 0; )
1216     regno_src_regno[i] = -1;
1217
1218   /* A forward pass.  Replace output operands with input operands.  */
1219   regmove_forward_pass ();
1220
1221   /* A backward pass.  Replace input operands with output operands.  */
1222   regmove_backward_pass ();
1223
1224   /* Clean up.  */
1225   free (regno_src_regno);
1226   if (reg_set_in_bb)
1227     {
1228       free (reg_set_in_bb);
1229       reg_set_in_bb = NULL;
1230     }
1231   regstat_free_n_sets_and_refs ();
1232   regstat_free_ri ();
1233   return 0;
1234 }
1235
1236 /* Returns nonzero if INSN's pattern has matching constraints for any operand.
1237    Returns 0 if INSN can't be recognized, or if the alternative can't be
1238    determined.
1239
1240    Initialize the info in MATCHP based on the constraints.  */
1241
1242 static int
1243 find_matches (rtx insn, struct match *matchp)
1244 {
1245   int likely_spilled[MAX_RECOG_OPERANDS];
1246   int op_no;
1247   int any_matches = 0;
1248
1249   extract_insn (insn);
1250   if (! constrain_operands (0))
1251     return 0;
1252
1253   /* Must initialize this before main loop, because the code for
1254      the commutative case may set matches for operands other than
1255      the current one.  */
1256   for (op_no = recog_data.n_operands; --op_no >= 0; )
1257     matchp->with[op_no] = matchp->commutative[op_no] = -1;
1258
1259   for (op_no = 0; op_no < recog_data.n_operands; op_no++)
1260     {
1261       const char *p;
1262       char c;
1263       int i = 0;
1264
1265       p = recog_data.constraints[op_no];
1266
1267       likely_spilled[op_no] = 0;
1268       matchp->use[op_no] = READ;
1269       matchp->early_clobber[op_no] = 0;
1270       if (*p == '=')
1271         matchp->use[op_no] = WRITE;
1272       else if (*p == '+')
1273         matchp->use[op_no] = READWRITE;
1274
1275       for (;*p && i < which_alternative; p++)
1276         if (*p == ',')
1277           i++;
1278
1279       while ((c = *p) != '\0' && c != ',')
1280         {
1281           switch (c)
1282             {
1283             case '=':
1284               break;
1285             case '+':
1286               break;
1287             case '&':
1288               matchp->early_clobber[op_no] = 1;
1289               break;
1290             case '%':
1291               matchp->commutative[op_no] = op_no + 1;
1292               matchp->commutative[op_no + 1] = op_no;
1293               break;
1294
1295             case '0': case '1': case '2': case '3': case '4':
1296             case '5': case '6': case '7': case '8': case '9':
1297               {
1298                 char *end;
1299                 unsigned long match_ul = strtoul (p, &end, 10);
1300                 int match = match_ul;
1301
1302                 p = end;
1303
1304                 if (match < op_no && likely_spilled[match])
1305                   continue;
1306                 matchp->with[op_no] = match;
1307                 any_matches = 1;
1308                 if (matchp->commutative[op_no] >= 0)
1309                   matchp->with[matchp->commutative[op_no]] = match;
1310               }
1311             continue;
1312
1313           case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h':
1314           case 'j': case 'k': case 'l': case 'p': case 'q': case 't': case 'u':
1315           case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B':
1316           case 'C': case 'D': case 'W': case 'Y': case 'Z':
1317             if (CLASS_LIKELY_SPILLED_P (REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p) ))
1318               likely_spilled[op_no] = 1;
1319             break;
1320           }
1321           p += CONSTRAINT_LEN (c, p);
1322         }
1323     }
1324   return any_matches;
1325 }
1326
1327 \f
1328
1329 static bool
1330 gate_handle_regmove (void)
1331 {
1332   return (optimize > 0 && flag_regmove);
1333 }
1334
1335
1336 struct rtl_opt_pass pass_regmove =
1337 {
1338  {
1339   RTL_PASS,
1340   "regmove",                            /* name */
1341   gate_handle_regmove,                  /* gate */
1342   regmove_optimize,                     /* execute */
1343   NULL,                                 /* sub */
1344   NULL,                                 /* next */
1345   0,                                    /* static_pass_number */
1346   TV_REGMOVE,                           /* tv_id */
1347   0,                                    /* properties_required */
1348   0,                                    /* properties_provided */
1349   0,                                    /* properties_destroyed */
1350   0,                                    /* todo_flags_start */
1351   TODO_df_finish | TODO_verify_rtl_sharing |
1352   TODO_dump_func |
1353   TODO_ggc_collect                      /* todo_flags_finish */
1354  }
1355 };
1356