1*e4b17023SJohn Marino /* Convert a program in SSA form into Normal form.
2*e4b17023SJohn Marino Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
3*e4b17023SJohn Marino Free Software Foundation, Inc.
4*e4b17023SJohn Marino Contributed by Andrew Macleod <amacleod@redhat.com>
5*e4b17023SJohn Marino
6*e4b17023SJohn Marino This file is part of GCC.
7*e4b17023SJohn Marino
8*e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify
9*e4b17023SJohn Marino it under the terms of the GNU General Public License as published by
10*e4b17023SJohn Marino the Free Software Foundation; either version 3, or (at your option)
11*e4b17023SJohn Marino any later version.
12*e4b17023SJohn Marino
13*e4b17023SJohn Marino GCC is distributed in the hope that it will be useful,
14*e4b17023SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
15*e4b17023SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*e4b17023SJohn Marino GNU General Public License for more details.
17*e4b17023SJohn Marino
18*e4b17023SJohn Marino You should have received a copy of the GNU General Public License
19*e4b17023SJohn Marino along with GCC; see the file COPYING3. If not see
20*e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */
21*e4b17023SJohn Marino
22*e4b17023SJohn Marino #include "config.h"
23*e4b17023SJohn Marino #include "system.h"
24*e4b17023SJohn Marino #include "coretypes.h"
25*e4b17023SJohn Marino #include "tm.h"
26*e4b17023SJohn Marino #include "tree.h"
27*e4b17023SJohn Marino #include "ggc.h"
28*e4b17023SJohn Marino #include "basic-block.h"
29*e4b17023SJohn Marino #include "tree-pretty-print.h"
30*e4b17023SJohn Marino #include "gimple-pretty-print.h"
31*e4b17023SJohn Marino #include "bitmap.h"
32*e4b17023SJohn Marino #include "tree-flow.h"
33*e4b17023SJohn Marino #include "timevar.h"
34*e4b17023SJohn Marino #include "tree-dump.h"
35*e4b17023SJohn Marino #include "tree-pass.h"
36*e4b17023SJohn Marino #include "diagnostic-core.h"
37*e4b17023SJohn Marino #include "ssaexpand.h"
38*e4b17023SJohn Marino
39*e4b17023SJohn Marino /* FIXME: A lot of code here deals with expanding to RTL. All that code
40*e4b17023SJohn Marino should be in cfgexpand.c. */
41*e4b17023SJohn Marino #include "expr.h"
42*e4b17023SJohn Marino
43*e4b17023SJohn Marino
44*e4b17023SJohn Marino DEF_VEC_I(source_location);
45*e4b17023SJohn Marino DEF_VEC_ALLOC_I(source_location,heap);
46*e4b17023SJohn Marino
47*e4b17023SJohn Marino /* Used to hold all the components required to do SSA PHI elimination.
48*e4b17023SJohn Marino The node and pred/succ list is a simple linear list of nodes and
49*e4b17023SJohn Marino edges represented as pairs of nodes.
50*e4b17023SJohn Marino
51*e4b17023SJohn Marino The predecessor and successor list: Nodes are entered in pairs, where
52*e4b17023SJohn Marino [0] ->PRED, [1]->SUCC. All the even indexes in the array represent
53*e4b17023SJohn Marino predecessors, all the odd elements are successors.
54*e4b17023SJohn Marino
55*e4b17023SJohn Marino Rationale:
56*e4b17023SJohn Marino When implemented as bitmaps, very large programs SSA->Normal times were
57*e4b17023SJohn Marino being dominated by clearing the interference graph.
58*e4b17023SJohn Marino
59*e4b17023SJohn Marino Typically this list of edges is extremely small since it only includes
60*e4b17023SJohn Marino PHI results and uses from a single edge which have not coalesced with
61*e4b17023SJohn Marino each other. This means that no virtual PHI nodes are included, and
62*e4b17023SJohn Marino empirical evidence suggests that the number of edges rarely exceed
63*e4b17023SJohn Marino 3, and in a bootstrap of GCC, the maximum size encountered was 7.
64*e4b17023SJohn Marino This also limits the number of possible nodes that are involved to
65*e4b17023SJohn Marino rarely more than 6, and in the bootstrap of gcc, the maximum number
66*e4b17023SJohn Marino of nodes encountered was 12. */
67*e4b17023SJohn Marino
68*e4b17023SJohn Marino typedef struct _elim_graph {
69*e4b17023SJohn Marino /* Size of the elimination vectors. */
70*e4b17023SJohn Marino int size;
71*e4b17023SJohn Marino
72*e4b17023SJohn Marino /* List of nodes in the elimination graph. */
73*e4b17023SJohn Marino VEC(int,heap) *nodes;
74*e4b17023SJohn Marino
75*e4b17023SJohn Marino /* The predecessor and successor edge list. */
76*e4b17023SJohn Marino VEC(int,heap) *edge_list;
77*e4b17023SJohn Marino
78*e4b17023SJohn Marino /* Source locus on each edge */
79*e4b17023SJohn Marino VEC(source_location,heap) *edge_locus;
80*e4b17023SJohn Marino
81*e4b17023SJohn Marino /* Visited vector. */
82*e4b17023SJohn Marino sbitmap visited;
83*e4b17023SJohn Marino
84*e4b17023SJohn Marino /* Stack for visited nodes. */
85*e4b17023SJohn Marino VEC(int,heap) *stack;
86*e4b17023SJohn Marino
87*e4b17023SJohn Marino /* The variable partition map. */
88*e4b17023SJohn Marino var_map map;
89*e4b17023SJohn Marino
90*e4b17023SJohn Marino /* Edge being eliminated by this graph. */
91*e4b17023SJohn Marino edge e;
92*e4b17023SJohn Marino
93*e4b17023SJohn Marino /* List of constant copies to emit. These are pushed on in pairs. */
94*e4b17023SJohn Marino VEC(int,heap) *const_dests;
95*e4b17023SJohn Marino VEC(tree,heap) *const_copies;
96*e4b17023SJohn Marino
97*e4b17023SJohn Marino /* Source locations for any constant copies. */
98*e4b17023SJohn Marino VEC(source_location,heap) *copy_locus;
99*e4b17023SJohn Marino } *elim_graph;
100*e4b17023SJohn Marino
101*e4b17023SJohn Marino
102*e4b17023SJohn Marino /* For an edge E find out a good source location to associate with
103*e4b17023SJohn Marino instructions inserted on edge E. If E has an implicit goto set,
104*e4b17023SJohn Marino use its location. Otherwise search instructions in predecessors
105*e4b17023SJohn Marino of E for a location, and use that one. That makes sense because
106*e4b17023SJohn Marino we insert on edges for PHI nodes, and effects of PHIs happen on
107*e4b17023SJohn Marino the end of the predecessor conceptually. */
108*e4b17023SJohn Marino
109*e4b17023SJohn Marino static void
set_location_for_edge(edge e)110*e4b17023SJohn Marino set_location_for_edge (edge e)
111*e4b17023SJohn Marino {
112*e4b17023SJohn Marino if (e->goto_locus)
113*e4b17023SJohn Marino {
114*e4b17023SJohn Marino set_curr_insn_source_location (e->goto_locus);
115*e4b17023SJohn Marino set_curr_insn_block (e->goto_block);
116*e4b17023SJohn Marino }
117*e4b17023SJohn Marino else
118*e4b17023SJohn Marino {
119*e4b17023SJohn Marino basic_block bb = e->src;
120*e4b17023SJohn Marino gimple_stmt_iterator gsi;
121*e4b17023SJohn Marino
122*e4b17023SJohn Marino do
123*e4b17023SJohn Marino {
124*e4b17023SJohn Marino for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
125*e4b17023SJohn Marino {
126*e4b17023SJohn Marino gimple stmt = gsi_stmt (gsi);
127*e4b17023SJohn Marino if (is_gimple_debug (stmt))
128*e4b17023SJohn Marino continue;
129*e4b17023SJohn Marino if (gimple_has_location (stmt) || gimple_block (stmt))
130*e4b17023SJohn Marino {
131*e4b17023SJohn Marino set_curr_insn_source_location (gimple_location (stmt));
132*e4b17023SJohn Marino set_curr_insn_block (gimple_block (stmt));
133*e4b17023SJohn Marino return;
134*e4b17023SJohn Marino }
135*e4b17023SJohn Marino }
136*e4b17023SJohn Marino /* Nothing found in this basic block. Make a half-assed attempt
137*e4b17023SJohn Marino to continue with another block. */
138*e4b17023SJohn Marino if (single_pred_p (bb))
139*e4b17023SJohn Marino bb = single_pred (bb);
140*e4b17023SJohn Marino else
141*e4b17023SJohn Marino bb = e->src;
142*e4b17023SJohn Marino }
143*e4b17023SJohn Marino while (bb != e->src);
144*e4b17023SJohn Marino }
145*e4b17023SJohn Marino }
146*e4b17023SJohn Marino
147*e4b17023SJohn Marino /* Emit insns to copy SRC into DEST converting SRC if necessary. As
148*e4b17023SJohn Marino SRC/DEST might be BLKmode memory locations SIZEEXP is a tree from
149*e4b17023SJohn Marino which we deduce the size to copy in that case. */
150*e4b17023SJohn Marino
151*e4b17023SJohn Marino static inline rtx
emit_partition_copy(rtx dest,rtx src,int unsignedsrcp,tree sizeexp)152*e4b17023SJohn Marino emit_partition_copy (rtx dest, rtx src, int unsignedsrcp, tree sizeexp)
153*e4b17023SJohn Marino {
154*e4b17023SJohn Marino rtx seq;
155*e4b17023SJohn Marino
156*e4b17023SJohn Marino start_sequence ();
157*e4b17023SJohn Marino
158*e4b17023SJohn Marino if (GET_MODE (src) != VOIDmode && GET_MODE (src) != GET_MODE (dest))
159*e4b17023SJohn Marino src = convert_to_mode (GET_MODE (dest), src, unsignedsrcp);
160*e4b17023SJohn Marino if (GET_MODE (src) == BLKmode)
161*e4b17023SJohn Marino {
162*e4b17023SJohn Marino gcc_assert (GET_MODE (dest) == BLKmode);
163*e4b17023SJohn Marino emit_block_move (dest, src, expr_size (sizeexp), BLOCK_OP_NORMAL);
164*e4b17023SJohn Marino }
165*e4b17023SJohn Marino else
166*e4b17023SJohn Marino emit_move_insn (dest, src);
167*e4b17023SJohn Marino
168*e4b17023SJohn Marino seq = get_insns ();
169*e4b17023SJohn Marino end_sequence ();
170*e4b17023SJohn Marino
171*e4b17023SJohn Marino return seq;
172*e4b17023SJohn Marino }
173*e4b17023SJohn Marino
174*e4b17023SJohn Marino /* Insert a copy instruction from partition SRC to DEST onto edge E. */
175*e4b17023SJohn Marino
176*e4b17023SJohn Marino static void
insert_partition_copy_on_edge(edge e,int dest,int src,source_location locus)177*e4b17023SJohn Marino insert_partition_copy_on_edge (edge e, int dest, int src, source_location locus)
178*e4b17023SJohn Marino {
179*e4b17023SJohn Marino tree var;
180*e4b17023SJohn Marino rtx seq;
181*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS))
182*e4b17023SJohn Marino {
183*e4b17023SJohn Marino fprintf (dump_file,
184*e4b17023SJohn Marino "Inserting a partition copy on edge BB%d->BB%d :"
185*e4b17023SJohn Marino "PART.%d = PART.%d",
186*e4b17023SJohn Marino e->src->index,
187*e4b17023SJohn Marino e->dest->index, dest, src);
188*e4b17023SJohn Marino fprintf (dump_file, "\n");
189*e4b17023SJohn Marino }
190*e4b17023SJohn Marino
191*e4b17023SJohn Marino gcc_assert (SA.partition_to_pseudo[dest]);
192*e4b17023SJohn Marino gcc_assert (SA.partition_to_pseudo[src]);
193*e4b17023SJohn Marino
194*e4b17023SJohn Marino set_location_for_edge (e);
195*e4b17023SJohn Marino /* If a locus is provided, override the default. */
196*e4b17023SJohn Marino if (locus)
197*e4b17023SJohn Marino set_curr_insn_source_location (locus);
198*e4b17023SJohn Marino
199*e4b17023SJohn Marino var = partition_to_var (SA.map, src);
200*e4b17023SJohn Marino seq = emit_partition_copy (SA.partition_to_pseudo[dest],
201*e4b17023SJohn Marino SA.partition_to_pseudo[src],
202*e4b17023SJohn Marino TYPE_UNSIGNED (TREE_TYPE (var)),
203*e4b17023SJohn Marino var);
204*e4b17023SJohn Marino
205*e4b17023SJohn Marino insert_insn_on_edge (seq, e);
206*e4b17023SJohn Marino }
207*e4b17023SJohn Marino
208*e4b17023SJohn Marino /* Insert a copy instruction from expression SRC to partition DEST
209*e4b17023SJohn Marino onto edge E. */
210*e4b17023SJohn Marino
211*e4b17023SJohn Marino static void
insert_value_copy_on_edge(edge e,int dest,tree src,source_location locus)212*e4b17023SJohn Marino insert_value_copy_on_edge (edge e, int dest, tree src, source_location locus)
213*e4b17023SJohn Marino {
214*e4b17023SJohn Marino rtx seq, x;
215*e4b17023SJohn Marino enum machine_mode dest_mode, src_mode;
216*e4b17023SJohn Marino int unsignedp;
217*e4b17023SJohn Marino tree var;
218*e4b17023SJohn Marino
219*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS))
220*e4b17023SJohn Marino {
221*e4b17023SJohn Marino fprintf (dump_file,
222*e4b17023SJohn Marino "Inserting a value copy on edge BB%d->BB%d : PART.%d = ",
223*e4b17023SJohn Marino e->src->index,
224*e4b17023SJohn Marino e->dest->index, dest);
225*e4b17023SJohn Marino print_generic_expr (dump_file, src, TDF_SLIM);
226*e4b17023SJohn Marino fprintf (dump_file, "\n");
227*e4b17023SJohn Marino }
228*e4b17023SJohn Marino
229*e4b17023SJohn Marino gcc_assert (SA.partition_to_pseudo[dest]);
230*e4b17023SJohn Marino
231*e4b17023SJohn Marino set_location_for_edge (e);
232*e4b17023SJohn Marino /* If a locus is provided, override the default. */
233*e4b17023SJohn Marino if (locus)
234*e4b17023SJohn Marino set_curr_insn_source_location (locus);
235*e4b17023SJohn Marino
236*e4b17023SJohn Marino start_sequence ();
237*e4b17023SJohn Marino
238*e4b17023SJohn Marino var = SSA_NAME_VAR (partition_to_var (SA.map, dest));
239*e4b17023SJohn Marino src_mode = TYPE_MODE (TREE_TYPE (src));
240*e4b17023SJohn Marino dest_mode = GET_MODE (SA.partition_to_pseudo[dest]);
241*e4b17023SJohn Marino gcc_assert (src_mode == TYPE_MODE (TREE_TYPE (var)));
242*e4b17023SJohn Marino gcc_assert (!REG_P (SA.partition_to_pseudo[dest])
243*e4b17023SJohn Marino || dest_mode == promote_decl_mode (var, &unsignedp));
244*e4b17023SJohn Marino
245*e4b17023SJohn Marino if (src_mode != dest_mode)
246*e4b17023SJohn Marino {
247*e4b17023SJohn Marino x = expand_expr (src, NULL, src_mode, EXPAND_NORMAL);
248*e4b17023SJohn Marino x = convert_modes (dest_mode, src_mode, x, unsignedp);
249*e4b17023SJohn Marino }
250*e4b17023SJohn Marino else if (src_mode == BLKmode)
251*e4b17023SJohn Marino {
252*e4b17023SJohn Marino x = SA.partition_to_pseudo[dest];
253*e4b17023SJohn Marino store_expr (src, x, 0, false);
254*e4b17023SJohn Marino }
255*e4b17023SJohn Marino else
256*e4b17023SJohn Marino x = expand_expr (src, SA.partition_to_pseudo[dest],
257*e4b17023SJohn Marino dest_mode, EXPAND_NORMAL);
258*e4b17023SJohn Marino
259*e4b17023SJohn Marino if (x != SA.partition_to_pseudo[dest])
260*e4b17023SJohn Marino emit_move_insn (SA.partition_to_pseudo[dest], x);
261*e4b17023SJohn Marino seq = get_insns ();
262*e4b17023SJohn Marino end_sequence ();
263*e4b17023SJohn Marino
264*e4b17023SJohn Marino insert_insn_on_edge (seq, e);
265*e4b17023SJohn Marino }
266*e4b17023SJohn Marino
267*e4b17023SJohn Marino /* Insert a copy instruction from RTL expression SRC to partition DEST
268*e4b17023SJohn Marino onto edge E. */
269*e4b17023SJohn Marino
270*e4b17023SJohn Marino static void
insert_rtx_to_part_on_edge(edge e,int dest,rtx src,int unsignedsrcp,source_location locus)271*e4b17023SJohn Marino insert_rtx_to_part_on_edge (edge e, int dest, rtx src, int unsignedsrcp,
272*e4b17023SJohn Marino source_location locus)
273*e4b17023SJohn Marino {
274*e4b17023SJohn Marino rtx seq;
275*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS))
276*e4b17023SJohn Marino {
277*e4b17023SJohn Marino fprintf (dump_file,
278*e4b17023SJohn Marino "Inserting a temp copy on edge BB%d->BB%d : PART.%d = ",
279*e4b17023SJohn Marino e->src->index,
280*e4b17023SJohn Marino e->dest->index, dest);
281*e4b17023SJohn Marino print_simple_rtl (dump_file, src);
282*e4b17023SJohn Marino fprintf (dump_file, "\n");
283*e4b17023SJohn Marino }
284*e4b17023SJohn Marino
285*e4b17023SJohn Marino gcc_assert (SA.partition_to_pseudo[dest]);
286*e4b17023SJohn Marino
287*e4b17023SJohn Marino set_location_for_edge (e);
288*e4b17023SJohn Marino /* If a locus is provided, override the default. */
289*e4b17023SJohn Marino if (locus)
290*e4b17023SJohn Marino set_curr_insn_source_location (locus);
291*e4b17023SJohn Marino
292*e4b17023SJohn Marino /* We give the destination as sizeexp in case src/dest are BLKmode
293*e4b17023SJohn Marino mems. Usually we give the source. As we result from SSA names
294*e4b17023SJohn Marino the left and right size should be the same (and no WITH_SIZE_EXPR
295*e4b17023SJohn Marino involved), so it doesn't matter. */
296*e4b17023SJohn Marino seq = emit_partition_copy (SA.partition_to_pseudo[dest],
297*e4b17023SJohn Marino src, unsignedsrcp,
298*e4b17023SJohn Marino partition_to_var (SA.map, dest));
299*e4b17023SJohn Marino
300*e4b17023SJohn Marino insert_insn_on_edge (seq, e);
301*e4b17023SJohn Marino }
302*e4b17023SJohn Marino
303*e4b17023SJohn Marino /* Insert a copy instruction from partition SRC to RTL lvalue DEST
304*e4b17023SJohn Marino onto edge E. */
305*e4b17023SJohn Marino
306*e4b17023SJohn Marino static void
insert_part_to_rtx_on_edge(edge e,rtx dest,int src,source_location locus)307*e4b17023SJohn Marino insert_part_to_rtx_on_edge (edge e, rtx dest, int src, source_location locus)
308*e4b17023SJohn Marino {
309*e4b17023SJohn Marino tree var;
310*e4b17023SJohn Marino rtx seq;
311*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS))
312*e4b17023SJohn Marino {
313*e4b17023SJohn Marino fprintf (dump_file,
314*e4b17023SJohn Marino "Inserting a temp copy on edge BB%d->BB%d : ",
315*e4b17023SJohn Marino e->src->index,
316*e4b17023SJohn Marino e->dest->index);
317*e4b17023SJohn Marino print_simple_rtl (dump_file, dest);
318*e4b17023SJohn Marino fprintf (dump_file, "= PART.%d\n", src);
319*e4b17023SJohn Marino }
320*e4b17023SJohn Marino
321*e4b17023SJohn Marino gcc_assert (SA.partition_to_pseudo[src]);
322*e4b17023SJohn Marino
323*e4b17023SJohn Marino set_location_for_edge (e);
324*e4b17023SJohn Marino /* If a locus is provided, override the default. */
325*e4b17023SJohn Marino if (locus)
326*e4b17023SJohn Marino set_curr_insn_source_location (locus);
327*e4b17023SJohn Marino
328*e4b17023SJohn Marino var = partition_to_var (SA.map, src);
329*e4b17023SJohn Marino seq = emit_partition_copy (dest,
330*e4b17023SJohn Marino SA.partition_to_pseudo[src],
331*e4b17023SJohn Marino TYPE_UNSIGNED (TREE_TYPE (var)),
332*e4b17023SJohn Marino var);
333*e4b17023SJohn Marino
334*e4b17023SJohn Marino insert_insn_on_edge (seq, e);
335*e4b17023SJohn Marino }
336*e4b17023SJohn Marino
337*e4b17023SJohn Marino
338*e4b17023SJohn Marino /* Create an elimination graph with SIZE nodes and associated data
339*e4b17023SJohn Marino structures. */
340*e4b17023SJohn Marino
341*e4b17023SJohn Marino static elim_graph
new_elim_graph(int size)342*e4b17023SJohn Marino new_elim_graph (int size)
343*e4b17023SJohn Marino {
344*e4b17023SJohn Marino elim_graph g = (elim_graph) xmalloc (sizeof (struct _elim_graph));
345*e4b17023SJohn Marino
346*e4b17023SJohn Marino g->nodes = VEC_alloc (int, heap, 30);
347*e4b17023SJohn Marino g->const_dests = VEC_alloc (int, heap, 20);
348*e4b17023SJohn Marino g->const_copies = VEC_alloc (tree, heap, 20);
349*e4b17023SJohn Marino g->copy_locus = VEC_alloc (source_location, heap, 10);
350*e4b17023SJohn Marino g->edge_list = VEC_alloc (int, heap, 20);
351*e4b17023SJohn Marino g->edge_locus = VEC_alloc (source_location, heap, 10);
352*e4b17023SJohn Marino g->stack = VEC_alloc (int, heap, 30);
353*e4b17023SJohn Marino
354*e4b17023SJohn Marino g->visited = sbitmap_alloc (size);
355*e4b17023SJohn Marino
356*e4b17023SJohn Marino return g;
357*e4b17023SJohn Marino }
358*e4b17023SJohn Marino
359*e4b17023SJohn Marino
360*e4b17023SJohn Marino /* Empty elimination graph G. */
361*e4b17023SJohn Marino
362*e4b17023SJohn Marino static inline void
clear_elim_graph(elim_graph g)363*e4b17023SJohn Marino clear_elim_graph (elim_graph g)
364*e4b17023SJohn Marino {
365*e4b17023SJohn Marino VEC_truncate (int, g->nodes, 0);
366*e4b17023SJohn Marino VEC_truncate (int, g->edge_list, 0);
367*e4b17023SJohn Marino VEC_truncate (source_location, g->edge_locus, 0);
368*e4b17023SJohn Marino }
369*e4b17023SJohn Marino
370*e4b17023SJohn Marino
371*e4b17023SJohn Marino /* Delete elimination graph G. */
372*e4b17023SJohn Marino
373*e4b17023SJohn Marino static inline void
delete_elim_graph(elim_graph g)374*e4b17023SJohn Marino delete_elim_graph (elim_graph g)
375*e4b17023SJohn Marino {
376*e4b17023SJohn Marino sbitmap_free (g->visited);
377*e4b17023SJohn Marino VEC_free (int, heap, g->stack);
378*e4b17023SJohn Marino VEC_free (int, heap, g->edge_list);
379*e4b17023SJohn Marino VEC_free (tree, heap, g->const_copies);
380*e4b17023SJohn Marino VEC_free (int, heap, g->const_dests);
381*e4b17023SJohn Marino VEC_free (int, heap, g->nodes);
382*e4b17023SJohn Marino VEC_free (source_location, heap, g->copy_locus);
383*e4b17023SJohn Marino VEC_free (source_location, heap, g->edge_locus);
384*e4b17023SJohn Marino
385*e4b17023SJohn Marino free (g);
386*e4b17023SJohn Marino }
387*e4b17023SJohn Marino
388*e4b17023SJohn Marino
389*e4b17023SJohn Marino /* Return the number of nodes in graph G. */
390*e4b17023SJohn Marino
391*e4b17023SJohn Marino static inline int
elim_graph_size(elim_graph g)392*e4b17023SJohn Marino elim_graph_size (elim_graph g)
393*e4b17023SJohn Marino {
394*e4b17023SJohn Marino return VEC_length (int, g->nodes);
395*e4b17023SJohn Marino }
396*e4b17023SJohn Marino
397*e4b17023SJohn Marino
398*e4b17023SJohn Marino /* Add NODE to graph G, if it doesn't exist already. */
399*e4b17023SJohn Marino
400*e4b17023SJohn Marino static inline void
elim_graph_add_node(elim_graph g,int node)401*e4b17023SJohn Marino elim_graph_add_node (elim_graph g, int node)
402*e4b17023SJohn Marino {
403*e4b17023SJohn Marino int x;
404*e4b17023SJohn Marino int t;
405*e4b17023SJohn Marino
406*e4b17023SJohn Marino FOR_EACH_VEC_ELT (int, g->nodes, x, t)
407*e4b17023SJohn Marino if (t == node)
408*e4b17023SJohn Marino return;
409*e4b17023SJohn Marino VEC_safe_push (int, heap, g->nodes, node);
410*e4b17023SJohn Marino }
411*e4b17023SJohn Marino
412*e4b17023SJohn Marino
413*e4b17023SJohn Marino /* Add the edge PRED->SUCC to graph G. */
414*e4b17023SJohn Marino
415*e4b17023SJohn Marino static inline void
elim_graph_add_edge(elim_graph g,int pred,int succ,source_location locus)416*e4b17023SJohn Marino elim_graph_add_edge (elim_graph g, int pred, int succ, source_location locus)
417*e4b17023SJohn Marino {
418*e4b17023SJohn Marino VEC_safe_push (int, heap, g->edge_list, pred);
419*e4b17023SJohn Marino VEC_safe_push (int, heap, g->edge_list, succ);
420*e4b17023SJohn Marino VEC_safe_push (source_location, heap, g->edge_locus, locus);
421*e4b17023SJohn Marino }
422*e4b17023SJohn Marino
423*e4b17023SJohn Marino
424*e4b17023SJohn Marino /* Remove an edge from graph G for which NODE is the predecessor, and
425*e4b17023SJohn Marino return the successor node. -1 is returned if there is no such edge. */
426*e4b17023SJohn Marino
427*e4b17023SJohn Marino static inline int
elim_graph_remove_succ_edge(elim_graph g,int node,source_location * locus)428*e4b17023SJohn Marino elim_graph_remove_succ_edge (elim_graph g, int node, source_location *locus)
429*e4b17023SJohn Marino {
430*e4b17023SJohn Marino int y;
431*e4b17023SJohn Marino unsigned x;
432*e4b17023SJohn Marino for (x = 0; x < VEC_length (int, g->edge_list); x += 2)
433*e4b17023SJohn Marino if (VEC_index (int, g->edge_list, x) == node)
434*e4b17023SJohn Marino {
435*e4b17023SJohn Marino VEC_replace (int, g->edge_list, x, -1);
436*e4b17023SJohn Marino y = VEC_index (int, g->edge_list, x + 1);
437*e4b17023SJohn Marino VEC_replace (int, g->edge_list, x + 1, -1);
438*e4b17023SJohn Marino *locus = VEC_index (source_location, g->edge_locus, x / 2);
439*e4b17023SJohn Marino VEC_replace (source_location, g->edge_locus, x / 2, UNKNOWN_LOCATION);
440*e4b17023SJohn Marino return y;
441*e4b17023SJohn Marino }
442*e4b17023SJohn Marino *locus = UNKNOWN_LOCATION;
443*e4b17023SJohn Marino return -1;
444*e4b17023SJohn Marino }
445*e4b17023SJohn Marino
446*e4b17023SJohn Marino
447*e4b17023SJohn Marino /* Find all the nodes in GRAPH which are successors to NODE in the
448*e4b17023SJohn Marino edge list. VAR will hold the partition number found. CODE is the
449*e4b17023SJohn Marino code fragment executed for every node found. */
450*e4b17023SJohn Marino
451*e4b17023SJohn Marino #define FOR_EACH_ELIM_GRAPH_SUCC(GRAPH, NODE, VAR, LOCUS, CODE) \
452*e4b17023SJohn Marino do { \
453*e4b17023SJohn Marino unsigned x_; \
454*e4b17023SJohn Marino int y_; \
455*e4b17023SJohn Marino for (x_ = 0; x_ < VEC_length (int, (GRAPH)->edge_list); x_ += 2) \
456*e4b17023SJohn Marino { \
457*e4b17023SJohn Marino y_ = VEC_index (int, (GRAPH)->edge_list, x_); \
458*e4b17023SJohn Marino if (y_ != (NODE)) \
459*e4b17023SJohn Marino continue; \
460*e4b17023SJohn Marino (void) ((VAR) = VEC_index (int, (GRAPH)->edge_list, x_ + 1)); \
461*e4b17023SJohn Marino (void) ((LOCUS) = VEC_index (source_location, \
462*e4b17023SJohn Marino (GRAPH)->edge_locus, x_ / 2)); \
463*e4b17023SJohn Marino CODE; \
464*e4b17023SJohn Marino } \
465*e4b17023SJohn Marino } while (0)
466*e4b17023SJohn Marino
467*e4b17023SJohn Marino
468*e4b17023SJohn Marino /* Find all the nodes which are predecessors of NODE in the edge list for
469*e4b17023SJohn Marino GRAPH. VAR will hold the partition number found. CODE is the
470*e4b17023SJohn Marino code fragment executed for every node found. */
471*e4b17023SJohn Marino
472*e4b17023SJohn Marino #define FOR_EACH_ELIM_GRAPH_PRED(GRAPH, NODE, VAR, LOCUS, CODE) \
473*e4b17023SJohn Marino do { \
474*e4b17023SJohn Marino unsigned x_; \
475*e4b17023SJohn Marino int y_; \
476*e4b17023SJohn Marino for (x_ = 0; x_ < VEC_length (int, (GRAPH)->edge_list); x_ += 2) \
477*e4b17023SJohn Marino { \
478*e4b17023SJohn Marino y_ = VEC_index (int, (GRAPH)->edge_list, x_ + 1); \
479*e4b17023SJohn Marino if (y_ != (NODE)) \
480*e4b17023SJohn Marino continue; \
481*e4b17023SJohn Marino (void) ((VAR) = VEC_index (int, (GRAPH)->edge_list, x_)); \
482*e4b17023SJohn Marino (void) ((LOCUS) = VEC_index (source_location, \
483*e4b17023SJohn Marino (GRAPH)->edge_locus, x_ / 2)); \
484*e4b17023SJohn Marino CODE; \
485*e4b17023SJohn Marino } \
486*e4b17023SJohn Marino } while (0)
487*e4b17023SJohn Marino
488*e4b17023SJohn Marino
489*e4b17023SJohn Marino /* Add T to elimination graph G. */
490*e4b17023SJohn Marino
491*e4b17023SJohn Marino static inline void
eliminate_name(elim_graph g,int T)492*e4b17023SJohn Marino eliminate_name (elim_graph g, int T)
493*e4b17023SJohn Marino {
494*e4b17023SJohn Marino elim_graph_add_node (g, T);
495*e4b17023SJohn Marino }
496*e4b17023SJohn Marino
497*e4b17023SJohn Marino
498*e4b17023SJohn Marino /* Build elimination graph G for basic block BB on incoming PHI edge
499*e4b17023SJohn Marino G->e. */
500*e4b17023SJohn Marino
501*e4b17023SJohn Marino static void
eliminate_build(elim_graph g)502*e4b17023SJohn Marino eliminate_build (elim_graph g)
503*e4b17023SJohn Marino {
504*e4b17023SJohn Marino tree Ti;
505*e4b17023SJohn Marino int p0, pi;
506*e4b17023SJohn Marino gimple_stmt_iterator gsi;
507*e4b17023SJohn Marino
508*e4b17023SJohn Marino clear_elim_graph (g);
509*e4b17023SJohn Marino
510*e4b17023SJohn Marino for (gsi = gsi_start_phis (g->e->dest); !gsi_end_p (gsi); gsi_next (&gsi))
511*e4b17023SJohn Marino {
512*e4b17023SJohn Marino gimple phi = gsi_stmt (gsi);
513*e4b17023SJohn Marino source_location locus;
514*e4b17023SJohn Marino
515*e4b17023SJohn Marino p0 = var_to_partition (g->map, gimple_phi_result (phi));
516*e4b17023SJohn Marino /* Ignore results which are not in partitions. */
517*e4b17023SJohn Marino if (p0 == NO_PARTITION)
518*e4b17023SJohn Marino continue;
519*e4b17023SJohn Marino
520*e4b17023SJohn Marino Ti = PHI_ARG_DEF (phi, g->e->dest_idx);
521*e4b17023SJohn Marino locus = gimple_phi_arg_location_from_edge (phi, g->e);
522*e4b17023SJohn Marino
523*e4b17023SJohn Marino /* If this argument is a constant, or a SSA_NAME which is being
524*e4b17023SJohn Marino left in SSA form, just queue a copy to be emitted on this
525*e4b17023SJohn Marino edge. */
526*e4b17023SJohn Marino if (!phi_ssa_name_p (Ti)
527*e4b17023SJohn Marino || (TREE_CODE (Ti) == SSA_NAME
528*e4b17023SJohn Marino && var_to_partition (g->map, Ti) == NO_PARTITION))
529*e4b17023SJohn Marino {
530*e4b17023SJohn Marino /* Save constant copies until all other copies have been emitted
531*e4b17023SJohn Marino on this edge. */
532*e4b17023SJohn Marino VEC_safe_push (int, heap, g->const_dests, p0);
533*e4b17023SJohn Marino VEC_safe_push (tree, heap, g->const_copies, Ti);
534*e4b17023SJohn Marino VEC_safe_push (source_location, heap, g->copy_locus, locus);
535*e4b17023SJohn Marino }
536*e4b17023SJohn Marino else
537*e4b17023SJohn Marino {
538*e4b17023SJohn Marino pi = var_to_partition (g->map, Ti);
539*e4b17023SJohn Marino if (p0 != pi)
540*e4b17023SJohn Marino {
541*e4b17023SJohn Marino eliminate_name (g, p0);
542*e4b17023SJohn Marino eliminate_name (g, pi);
543*e4b17023SJohn Marino elim_graph_add_edge (g, p0, pi, locus);
544*e4b17023SJohn Marino }
545*e4b17023SJohn Marino }
546*e4b17023SJohn Marino }
547*e4b17023SJohn Marino }
548*e4b17023SJohn Marino
549*e4b17023SJohn Marino
550*e4b17023SJohn Marino /* Push successors of T onto the elimination stack for G. */
551*e4b17023SJohn Marino
552*e4b17023SJohn Marino static void
elim_forward(elim_graph g,int T)553*e4b17023SJohn Marino elim_forward (elim_graph g, int T)
554*e4b17023SJohn Marino {
555*e4b17023SJohn Marino int S;
556*e4b17023SJohn Marino source_location locus;
557*e4b17023SJohn Marino
558*e4b17023SJohn Marino SET_BIT (g->visited, T);
559*e4b17023SJohn Marino FOR_EACH_ELIM_GRAPH_SUCC (g, T, S, locus,
560*e4b17023SJohn Marino {
561*e4b17023SJohn Marino if (!TEST_BIT (g->visited, S))
562*e4b17023SJohn Marino elim_forward (g, S);
563*e4b17023SJohn Marino });
564*e4b17023SJohn Marino VEC_safe_push (int, heap, g->stack, T);
565*e4b17023SJohn Marino }
566*e4b17023SJohn Marino
567*e4b17023SJohn Marino
568*e4b17023SJohn Marino /* Return 1 if there unvisited predecessors of T in graph G. */
569*e4b17023SJohn Marino
570*e4b17023SJohn Marino static int
elim_unvisited_predecessor(elim_graph g,int T)571*e4b17023SJohn Marino elim_unvisited_predecessor (elim_graph g, int T)
572*e4b17023SJohn Marino {
573*e4b17023SJohn Marino int P;
574*e4b17023SJohn Marino source_location locus;
575*e4b17023SJohn Marino
576*e4b17023SJohn Marino FOR_EACH_ELIM_GRAPH_PRED (g, T, P, locus,
577*e4b17023SJohn Marino {
578*e4b17023SJohn Marino if (!TEST_BIT (g->visited, P))
579*e4b17023SJohn Marino return 1;
580*e4b17023SJohn Marino });
581*e4b17023SJohn Marino return 0;
582*e4b17023SJohn Marino }
583*e4b17023SJohn Marino
584*e4b17023SJohn Marino /* Process predecessors first, and insert a copy. */
585*e4b17023SJohn Marino
586*e4b17023SJohn Marino static void
elim_backward(elim_graph g,int T)587*e4b17023SJohn Marino elim_backward (elim_graph g, int T)
588*e4b17023SJohn Marino {
589*e4b17023SJohn Marino int P;
590*e4b17023SJohn Marino source_location locus;
591*e4b17023SJohn Marino
592*e4b17023SJohn Marino SET_BIT (g->visited, T);
593*e4b17023SJohn Marino FOR_EACH_ELIM_GRAPH_PRED (g, T, P, locus,
594*e4b17023SJohn Marino {
595*e4b17023SJohn Marino if (!TEST_BIT (g->visited, P))
596*e4b17023SJohn Marino {
597*e4b17023SJohn Marino elim_backward (g, P);
598*e4b17023SJohn Marino insert_partition_copy_on_edge (g->e, P, T, locus);
599*e4b17023SJohn Marino }
600*e4b17023SJohn Marino });
601*e4b17023SJohn Marino }
602*e4b17023SJohn Marino
603*e4b17023SJohn Marino /* Allocate a new pseudo register usable for storing values sitting
604*e4b17023SJohn Marino in NAME (a decl or SSA name), i.e. with matching mode and attributes. */
605*e4b17023SJohn Marino
606*e4b17023SJohn Marino static rtx
get_temp_reg(tree name)607*e4b17023SJohn Marino get_temp_reg (tree name)
608*e4b17023SJohn Marino {
609*e4b17023SJohn Marino tree var = TREE_CODE (name) == SSA_NAME ? SSA_NAME_VAR (name) : name;
610*e4b17023SJohn Marino tree type = TREE_TYPE (var);
611*e4b17023SJohn Marino int unsignedp;
612*e4b17023SJohn Marino enum machine_mode reg_mode = promote_decl_mode (var, &unsignedp);
613*e4b17023SJohn Marino rtx x = gen_reg_rtx (reg_mode);
614*e4b17023SJohn Marino if (POINTER_TYPE_P (type))
615*e4b17023SJohn Marino mark_reg_pointer (x, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (var))));
616*e4b17023SJohn Marino return x;
617*e4b17023SJohn Marino }
618*e4b17023SJohn Marino
619*e4b17023SJohn Marino /* Insert required copies for T in graph G. Check for a strongly connected
620*e4b17023SJohn Marino region, and create a temporary to break the cycle if one is found. */
621*e4b17023SJohn Marino
622*e4b17023SJohn Marino static void
elim_create(elim_graph g,int T)623*e4b17023SJohn Marino elim_create (elim_graph g, int T)
624*e4b17023SJohn Marino {
625*e4b17023SJohn Marino int P, S;
626*e4b17023SJohn Marino source_location locus;
627*e4b17023SJohn Marino
628*e4b17023SJohn Marino if (elim_unvisited_predecessor (g, T))
629*e4b17023SJohn Marino {
630*e4b17023SJohn Marino tree var = partition_to_var (g->map, T);
631*e4b17023SJohn Marino rtx U = get_temp_reg (var);
632*e4b17023SJohn Marino int unsignedsrcp = TYPE_UNSIGNED (TREE_TYPE (var));
633*e4b17023SJohn Marino
634*e4b17023SJohn Marino insert_part_to_rtx_on_edge (g->e, U, T, UNKNOWN_LOCATION);
635*e4b17023SJohn Marino FOR_EACH_ELIM_GRAPH_PRED (g, T, P, locus,
636*e4b17023SJohn Marino {
637*e4b17023SJohn Marino if (!TEST_BIT (g->visited, P))
638*e4b17023SJohn Marino {
639*e4b17023SJohn Marino elim_backward (g, P);
640*e4b17023SJohn Marino insert_rtx_to_part_on_edge (g->e, P, U, unsignedsrcp, locus);
641*e4b17023SJohn Marino }
642*e4b17023SJohn Marino });
643*e4b17023SJohn Marino }
644*e4b17023SJohn Marino else
645*e4b17023SJohn Marino {
646*e4b17023SJohn Marino S = elim_graph_remove_succ_edge (g, T, &locus);
647*e4b17023SJohn Marino if (S != -1)
648*e4b17023SJohn Marino {
649*e4b17023SJohn Marino SET_BIT (g->visited, T);
650*e4b17023SJohn Marino insert_partition_copy_on_edge (g->e, T, S, locus);
651*e4b17023SJohn Marino }
652*e4b17023SJohn Marino }
653*e4b17023SJohn Marino }
654*e4b17023SJohn Marino
655*e4b17023SJohn Marino
656*e4b17023SJohn Marino /* Eliminate all the phi nodes on edge E in graph G. */
657*e4b17023SJohn Marino
658*e4b17023SJohn Marino static void
eliminate_phi(edge e,elim_graph g)659*e4b17023SJohn Marino eliminate_phi (edge e, elim_graph g)
660*e4b17023SJohn Marino {
661*e4b17023SJohn Marino int x;
662*e4b17023SJohn Marino
663*e4b17023SJohn Marino gcc_assert (VEC_length (tree, g->const_copies) == 0);
664*e4b17023SJohn Marino gcc_assert (VEC_length (source_location, g->copy_locus) == 0);
665*e4b17023SJohn Marino
666*e4b17023SJohn Marino /* Abnormal edges already have everything coalesced. */
667*e4b17023SJohn Marino if (e->flags & EDGE_ABNORMAL)
668*e4b17023SJohn Marino return;
669*e4b17023SJohn Marino
670*e4b17023SJohn Marino g->e = e;
671*e4b17023SJohn Marino
672*e4b17023SJohn Marino eliminate_build (g);
673*e4b17023SJohn Marino
674*e4b17023SJohn Marino if (elim_graph_size (g) != 0)
675*e4b17023SJohn Marino {
676*e4b17023SJohn Marino int part;
677*e4b17023SJohn Marino
678*e4b17023SJohn Marino sbitmap_zero (g->visited);
679*e4b17023SJohn Marino VEC_truncate (int, g->stack, 0);
680*e4b17023SJohn Marino
681*e4b17023SJohn Marino FOR_EACH_VEC_ELT (int, g->nodes, x, part)
682*e4b17023SJohn Marino {
683*e4b17023SJohn Marino if (!TEST_BIT (g->visited, part))
684*e4b17023SJohn Marino elim_forward (g, part);
685*e4b17023SJohn Marino }
686*e4b17023SJohn Marino
687*e4b17023SJohn Marino sbitmap_zero (g->visited);
688*e4b17023SJohn Marino while (VEC_length (int, g->stack) > 0)
689*e4b17023SJohn Marino {
690*e4b17023SJohn Marino x = VEC_pop (int, g->stack);
691*e4b17023SJohn Marino if (!TEST_BIT (g->visited, x))
692*e4b17023SJohn Marino elim_create (g, x);
693*e4b17023SJohn Marino }
694*e4b17023SJohn Marino }
695*e4b17023SJohn Marino
696*e4b17023SJohn Marino /* If there are any pending constant copies, issue them now. */
697*e4b17023SJohn Marino while (VEC_length (tree, g->const_copies) > 0)
698*e4b17023SJohn Marino {
699*e4b17023SJohn Marino int dest;
700*e4b17023SJohn Marino tree src;
701*e4b17023SJohn Marino source_location locus;
702*e4b17023SJohn Marino
703*e4b17023SJohn Marino src = VEC_pop (tree, g->const_copies);
704*e4b17023SJohn Marino dest = VEC_pop (int, g->const_dests);
705*e4b17023SJohn Marino locus = VEC_pop (source_location, g->copy_locus);
706*e4b17023SJohn Marino insert_value_copy_on_edge (e, dest, src, locus);
707*e4b17023SJohn Marino }
708*e4b17023SJohn Marino }
709*e4b17023SJohn Marino
710*e4b17023SJohn Marino
711*e4b17023SJohn Marino /* Remove each argument from PHI. If an arg was the last use of an SSA_NAME,
712*e4b17023SJohn Marino check to see if this allows another PHI node to be removed. */
713*e4b17023SJohn Marino
714*e4b17023SJohn Marino static void
remove_gimple_phi_args(gimple phi)715*e4b17023SJohn Marino remove_gimple_phi_args (gimple phi)
716*e4b17023SJohn Marino {
717*e4b17023SJohn Marino use_operand_p arg_p;
718*e4b17023SJohn Marino ssa_op_iter iter;
719*e4b17023SJohn Marino
720*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS))
721*e4b17023SJohn Marino {
722*e4b17023SJohn Marino fprintf (dump_file, "Removing Dead PHI definition: ");
723*e4b17023SJohn Marino print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
724*e4b17023SJohn Marino }
725*e4b17023SJohn Marino
726*e4b17023SJohn Marino FOR_EACH_PHI_ARG (arg_p, phi, iter, SSA_OP_USE)
727*e4b17023SJohn Marino {
728*e4b17023SJohn Marino tree arg = USE_FROM_PTR (arg_p);
729*e4b17023SJohn Marino if (TREE_CODE (arg) == SSA_NAME)
730*e4b17023SJohn Marino {
731*e4b17023SJohn Marino /* Remove the reference to the existing argument. */
732*e4b17023SJohn Marino SET_USE (arg_p, NULL_TREE);
733*e4b17023SJohn Marino if (has_zero_uses (arg))
734*e4b17023SJohn Marino {
735*e4b17023SJohn Marino gimple stmt;
736*e4b17023SJohn Marino gimple_stmt_iterator gsi;
737*e4b17023SJohn Marino
738*e4b17023SJohn Marino stmt = SSA_NAME_DEF_STMT (arg);
739*e4b17023SJohn Marino
740*e4b17023SJohn Marino /* Also remove the def if it is a PHI node. */
741*e4b17023SJohn Marino if (gimple_code (stmt) == GIMPLE_PHI)
742*e4b17023SJohn Marino {
743*e4b17023SJohn Marino remove_gimple_phi_args (stmt);
744*e4b17023SJohn Marino gsi = gsi_for_stmt (stmt);
745*e4b17023SJohn Marino remove_phi_node (&gsi, true);
746*e4b17023SJohn Marino }
747*e4b17023SJohn Marino
748*e4b17023SJohn Marino }
749*e4b17023SJohn Marino }
750*e4b17023SJohn Marino }
751*e4b17023SJohn Marino }
752*e4b17023SJohn Marino
753*e4b17023SJohn Marino /* Remove any PHI node which is a virtual PHI, or a PHI with no uses. */
754*e4b17023SJohn Marino
755*e4b17023SJohn Marino static void
eliminate_useless_phis(void)756*e4b17023SJohn Marino eliminate_useless_phis (void)
757*e4b17023SJohn Marino {
758*e4b17023SJohn Marino basic_block bb;
759*e4b17023SJohn Marino gimple_stmt_iterator gsi;
760*e4b17023SJohn Marino tree result;
761*e4b17023SJohn Marino
762*e4b17023SJohn Marino FOR_EACH_BB (bb)
763*e4b17023SJohn Marino {
764*e4b17023SJohn Marino for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); )
765*e4b17023SJohn Marino {
766*e4b17023SJohn Marino gimple phi = gsi_stmt (gsi);
767*e4b17023SJohn Marino result = gimple_phi_result (phi);
768*e4b17023SJohn Marino if (!is_gimple_reg (SSA_NAME_VAR (result)))
769*e4b17023SJohn Marino {
770*e4b17023SJohn Marino #ifdef ENABLE_CHECKING
771*e4b17023SJohn Marino size_t i;
772*e4b17023SJohn Marino /* There should be no arguments which are not virtual, or the
773*e4b17023SJohn Marino results will be incorrect. */
774*e4b17023SJohn Marino for (i = 0; i < gimple_phi_num_args (phi); i++)
775*e4b17023SJohn Marino {
776*e4b17023SJohn Marino tree arg = PHI_ARG_DEF (phi, i);
777*e4b17023SJohn Marino if (TREE_CODE (arg) == SSA_NAME
778*e4b17023SJohn Marino && is_gimple_reg (SSA_NAME_VAR (arg)))
779*e4b17023SJohn Marino {
780*e4b17023SJohn Marino fprintf (stderr, "Argument of PHI is not virtual (");
781*e4b17023SJohn Marino print_generic_expr (stderr, arg, TDF_SLIM);
782*e4b17023SJohn Marino fprintf (stderr, "), but the result is :");
783*e4b17023SJohn Marino print_gimple_stmt (stderr, phi, 0, TDF_SLIM);
784*e4b17023SJohn Marino internal_error ("SSA corruption");
785*e4b17023SJohn Marino }
786*e4b17023SJohn Marino }
787*e4b17023SJohn Marino #endif
788*e4b17023SJohn Marino remove_phi_node (&gsi, true);
789*e4b17023SJohn Marino }
790*e4b17023SJohn Marino else
791*e4b17023SJohn Marino {
792*e4b17023SJohn Marino /* Also remove real PHIs with no uses. */
793*e4b17023SJohn Marino if (has_zero_uses (result))
794*e4b17023SJohn Marino {
795*e4b17023SJohn Marino remove_gimple_phi_args (phi);
796*e4b17023SJohn Marino remove_phi_node (&gsi, true);
797*e4b17023SJohn Marino }
798*e4b17023SJohn Marino else
799*e4b17023SJohn Marino gsi_next (&gsi);
800*e4b17023SJohn Marino }
801*e4b17023SJohn Marino }
802*e4b17023SJohn Marino }
803*e4b17023SJohn Marino }
804*e4b17023SJohn Marino
805*e4b17023SJohn Marino
806*e4b17023SJohn Marino /* This function will rewrite the current program using the variable mapping
807*e4b17023SJohn Marino found in MAP. If the replacement vector VALUES is provided, any
808*e4b17023SJohn Marino occurrences of partitions with non-null entries in the vector will be
809*e4b17023SJohn Marino replaced with the expression in the vector instead of its mapped
810*e4b17023SJohn Marino variable. */
811*e4b17023SJohn Marino
812*e4b17023SJohn Marino static void
rewrite_trees(var_map map ATTRIBUTE_UNUSED)813*e4b17023SJohn Marino rewrite_trees (var_map map ATTRIBUTE_UNUSED)
814*e4b17023SJohn Marino {
815*e4b17023SJohn Marino #ifdef ENABLE_CHECKING
816*e4b17023SJohn Marino basic_block bb;
817*e4b17023SJohn Marino /* Search for PHIs where the destination has no partition, but one
818*e4b17023SJohn Marino or more arguments has a partition. This should not happen and can
819*e4b17023SJohn Marino create incorrect code. */
820*e4b17023SJohn Marino FOR_EACH_BB (bb)
821*e4b17023SJohn Marino {
822*e4b17023SJohn Marino gimple_stmt_iterator gsi;
823*e4b17023SJohn Marino for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
824*e4b17023SJohn Marino {
825*e4b17023SJohn Marino gimple phi = gsi_stmt (gsi);
826*e4b17023SJohn Marino tree T0 = var_to_partition_to_var (map, gimple_phi_result (phi));
827*e4b17023SJohn Marino if (T0 == NULL_TREE)
828*e4b17023SJohn Marino {
829*e4b17023SJohn Marino size_t i;
830*e4b17023SJohn Marino for (i = 0; i < gimple_phi_num_args (phi); i++)
831*e4b17023SJohn Marino {
832*e4b17023SJohn Marino tree arg = PHI_ARG_DEF (phi, i);
833*e4b17023SJohn Marino
834*e4b17023SJohn Marino if (TREE_CODE (arg) == SSA_NAME
835*e4b17023SJohn Marino && var_to_partition (map, arg) != NO_PARTITION)
836*e4b17023SJohn Marino {
837*e4b17023SJohn Marino fprintf (stderr, "Argument of PHI is in a partition :(");
838*e4b17023SJohn Marino print_generic_expr (stderr, arg, TDF_SLIM);
839*e4b17023SJohn Marino fprintf (stderr, "), but the result is not :");
840*e4b17023SJohn Marino print_gimple_stmt (stderr, phi, 0, TDF_SLIM);
841*e4b17023SJohn Marino internal_error ("SSA corruption");
842*e4b17023SJohn Marino }
843*e4b17023SJohn Marino }
844*e4b17023SJohn Marino }
845*e4b17023SJohn Marino }
846*e4b17023SJohn Marino }
847*e4b17023SJohn Marino #endif
848*e4b17023SJohn Marino }
849*e4b17023SJohn Marino
850*e4b17023SJohn Marino /* Given the out-of-ssa info object SA (with prepared partitions)
851*e4b17023SJohn Marino eliminate all phi nodes in all basic blocks. Afterwards no
852*e4b17023SJohn Marino basic block will have phi nodes anymore and there are possibly
853*e4b17023SJohn Marino some RTL instructions inserted on edges. */
854*e4b17023SJohn Marino
855*e4b17023SJohn Marino void
expand_phi_nodes(struct ssaexpand * sa)856*e4b17023SJohn Marino expand_phi_nodes (struct ssaexpand *sa)
857*e4b17023SJohn Marino {
858*e4b17023SJohn Marino basic_block bb;
859*e4b17023SJohn Marino elim_graph g = new_elim_graph (sa->map->num_partitions);
860*e4b17023SJohn Marino g->map = sa->map;
861*e4b17023SJohn Marino
862*e4b17023SJohn Marino FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb, EXIT_BLOCK_PTR, next_bb)
863*e4b17023SJohn Marino if (!gimple_seq_empty_p (phi_nodes (bb)))
864*e4b17023SJohn Marino {
865*e4b17023SJohn Marino edge e;
866*e4b17023SJohn Marino edge_iterator ei;
867*e4b17023SJohn Marino FOR_EACH_EDGE (e, ei, bb->preds)
868*e4b17023SJohn Marino eliminate_phi (e, g);
869*e4b17023SJohn Marino set_phi_nodes (bb, NULL);
870*e4b17023SJohn Marino /* We can't redirect EH edges in RTL land, so we need to do this
871*e4b17023SJohn Marino here. Redirection happens only when splitting is necessary,
872*e4b17023SJohn Marino which it is only for critical edges, normally. For EH edges
873*e4b17023SJohn Marino it might also be necessary when the successor has more than
874*e4b17023SJohn Marino one predecessor. In that case the edge is either required to
875*e4b17023SJohn Marino be fallthru (which EH edges aren't), or the predecessor needs
876*e4b17023SJohn Marino to end with a jump (which again, isn't the case with EH edges).
877*e4b17023SJohn Marino Hence, split all EH edges on which we inserted instructions
878*e4b17023SJohn Marino and whose successor has multiple predecessors. */
879*e4b17023SJohn Marino for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
880*e4b17023SJohn Marino {
881*e4b17023SJohn Marino if (e->insns.r && (e->flags & EDGE_EH)
882*e4b17023SJohn Marino && !single_pred_p (e->dest))
883*e4b17023SJohn Marino {
884*e4b17023SJohn Marino rtx insns = e->insns.r;
885*e4b17023SJohn Marino basic_block bb;
886*e4b17023SJohn Marino e->insns.r = NULL_RTX;
887*e4b17023SJohn Marino bb = split_edge (e);
888*e4b17023SJohn Marino single_pred_edge (bb)->insns.r = insns;
889*e4b17023SJohn Marino }
890*e4b17023SJohn Marino else
891*e4b17023SJohn Marino ei_next (&ei);
892*e4b17023SJohn Marino }
893*e4b17023SJohn Marino }
894*e4b17023SJohn Marino
895*e4b17023SJohn Marino delete_elim_graph (g);
896*e4b17023SJohn Marino }
897*e4b17023SJohn Marino
898*e4b17023SJohn Marino
899*e4b17023SJohn Marino /* Remove the ssa-names in the current function and translate them into normal
900*e4b17023SJohn Marino compiler variables. PERFORM_TER is true if Temporary Expression Replacement
901*e4b17023SJohn Marino should also be used. */
902*e4b17023SJohn Marino
903*e4b17023SJohn Marino static void
remove_ssa_form(bool perform_ter,struct ssaexpand * sa)904*e4b17023SJohn Marino remove_ssa_form (bool perform_ter, struct ssaexpand *sa)
905*e4b17023SJohn Marino {
906*e4b17023SJohn Marino bitmap values = NULL;
907*e4b17023SJohn Marino var_map map;
908*e4b17023SJohn Marino unsigned i;
909*e4b17023SJohn Marino
910*e4b17023SJohn Marino map = coalesce_ssa_name ();
911*e4b17023SJohn Marino
912*e4b17023SJohn Marino /* Return to viewing the variable list as just all reference variables after
913*e4b17023SJohn Marino coalescing has been performed. */
914*e4b17023SJohn Marino partition_view_normal (map, false);
915*e4b17023SJohn Marino
916*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS))
917*e4b17023SJohn Marino {
918*e4b17023SJohn Marino fprintf (dump_file, "After Coalescing:\n");
919*e4b17023SJohn Marino dump_var_map (dump_file, map);
920*e4b17023SJohn Marino }
921*e4b17023SJohn Marino
922*e4b17023SJohn Marino if (perform_ter)
923*e4b17023SJohn Marino {
924*e4b17023SJohn Marino values = find_replaceable_exprs (map);
925*e4b17023SJohn Marino if (values && dump_file && (dump_flags & TDF_DETAILS))
926*e4b17023SJohn Marino dump_replaceable_exprs (dump_file, values);
927*e4b17023SJohn Marino }
928*e4b17023SJohn Marino
929*e4b17023SJohn Marino rewrite_trees (map);
930*e4b17023SJohn Marino
931*e4b17023SJohn Marino sa->map = map;
932*e4b17023SJohn Marino sa->values = values;
933*e4b17023SJohn Marino sa->partition_has_default_def = BITMAP_ALLOC (NULL);
934*e4b17023SJohn Marino for (i = 1; i < num_ssa_names; i++)
935*e4b17023SJohn Marino {
936*e4b17023SJohn Marino tree t = ssa_name (i);
937*e4b17023SJohn Marino if (t && SSA_NAME_IS_DEFAULT_DEF (t))
938*e4b17023SJohn Marino {
939*e4b17023SJohn Marino int p = var_to_partition (map, t);
940*e4b17023SJohn Marino if (p != NO_PARTITION)
941*e4b17023SJohn Marino bitmap_set_bit (sa->partition_has_default_def, p);
942*e4b17023SJohn Marino }
943*e4b17023SJohn Marino }
944*e4b17023SJohn Marino }
945*e4b17023SJohn Marino
946*e4b17023SJohn Marino
947*e4b17023SJohn Marino /* If not already done so for basic block BB, assign increasing uids
948*e4b17023SJohn Marino to each of its instructions. */
949*e4b17023SJohn Marino
950*e4b17023SJohn Marino static void
maybe_renumber_stmts_bb(basic_block bb)951*e4b17023SJohn Marino maybe_renumber_stmts_bb (basic_block bb)
952*e4b17023SJohn Marino {
953*e4b17023SJohn Marino unsigned i = 0;
954*e4b17023SJohn Marino gimple_stmt_iterator gsi;
955*e4b17023SJohn Marino
956*e4b17023SJohn Marino if (!bb->aux)
957*e4b17023SJohn Marino return;
958*e4b17023SJohn Marino bb->aux = NULL;
959*e4b17023SJohn Marino for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
960*e4b17023SJohn Marino {
961*e4b17023SJohn Marino gimple stmt = gsi_stmt (gsi);
962*e4b17023SJohn Marino gimple_set_uid (stmt, i);
963*e4b17023SJohn Marino i++;
964*e4b17023SJohn Marino }
965*e4b17023SJohn Marino }
966*e4b17023SJohn Marino
967*e4b17023SJohn Marino
968*e4b17023SJohn Marino /* Return true if we can determine that the SSA_NAMEs RESULT (a result
969*e4b17023SJohn Marino of a PHI node) and ARG (one of its arguments) conflict. Return false
970*e4b17023SJohn Marino otherwise, also when we simply aren't sure. */
971*e4b17023SJohn Marino
972*e4b17023SJohn Marino static bool
trivially_conflicts_p(basic_block bb,tree result,tree arg)973*e4b17023SJohn Marino trivially_conflicts_p (basic_block bb, tree result, tree arg)
974*e4b17023SJohn Marino {
975*e4b17023SJohn Marino use_operand_p use;
976*e4b17023SJohn Marino imm_use_iterator imm_iter;
977*e4b17023SJohn Marino gimple defa = SSA_NAME_DEF_STMT (arg);
978*e4b17023SJohn Marino
979*e4b17023SJohn Marino /* If ARG isn't defined in the same block it's too complicated for
980*e4b17023SJohn Marino our little mind. */
981*e4b17023SJohn Marino if (gimple_bb (defa) != bb)
982*e4b17023SJohn Marino return false;
983*e4b17023SJohn Marino
984*e4b17023SJohn Marino FOR_EACH_IMM_USE_FAST (use, imm_iter, result)
985*e4b17023SJohn Marino {
986*e4b17023SJohn Marino gimple use_stmt = USE_STMT (use);
987*e4b17023SJohn Marino if (is_gimple_debug (use_stmt))
988*e4b17023SJohn Marino continue;
989*e4b17023SJohn Marino /* Now, if there's a use of RESULT that lies outside this basic block,
990*e4b17023SJohn Marino then there surely is a conflict with ARG. */
991*e4b17023SJohn Marino if (gimple_bb (use_stmt) != bb)
992*e4b17023SJohn Marino return true;
993*e4b17023SJohn Marino if (gimple_code (use_stmt) == GIMPLE_PHI)
994*e4b17023SJohn Marino continue;
995*e4b17023SJohn Marino /* The use now is in a real stmt of BB, so if ARG was defined
996*e4b17023SJohn Marino in a PHI node (like RESULT) both conflict. */
997*e4b17023SJohn Marino if (gimple_code (defa) == GIMPLE_PHI)
998*e4b17023SJohn Marino return true;
999*e4b17023SJohn Marino maybe_renumber_stmts_bb (bb);
1000*e4b17023SJohn Marino /* If the use of RESULT occurs after the definition of ARG,
1001*e4b17023SJohn Marino the two conflict too. */
1002*e4b17023SJohn Marino if (gimple_uid (defa) < gimple_uid (use_stmt))
1003*e4b17023SJohn Marino return true;
1004*e4b17023SJohn Marino }
1005*e4b17023SJohn Marino
1006*e4b17023SJohn Marino return false;
1007*e4b17023SJohn Marino }
1008*e4b17023SJohn Marino
1009*e4b17023SJohn Marino
1010*e4b17023SJohn Marino /* Search every PHI node for arguments associated with backedges which
1011*e4b17023SJohn Marino we can trivially determine will need a copy (the argument is either
1012*e4b17023SJohn Marino not an SSA_NAME or the argument has a different underlying variable
1013*e4b17023SJohn Marino than the PHI result).
1014*e4b17023SJohn Marino
1015*e4b17023SJohn Marino Insert a copy from the PHI argument to a new destination at the
1016*e4b17023SJohn Marino end of the block with the backedge to the top of the loop. Update
1017*e4b17023SJohn Marino the PHI argument to reference this new destination. */
1018*e4b17023SJohn Marino
1019*e4b17023SJohn Marino static void
insert_backedge_copies(void)1020*e4b17023SJohn Marino insert_backedge_copies (void)
1021*e4b17023SJohn Marino {
1022*e4b17023SJohn Marino basic_block bb;
1023*e4b17023SJohn Marino gimple_stmt_iterator gsi;
1024*e4b17023SJohn Marino
1025*e4b17023SJohn Marino mark_dfs_back_edges ();
1026*e4b17023SJohn Marino
1027*e4b17023SJohn Marino FOR_EACH_BB (bb)
1028*e4b17023SJohn Marino {
1029*e4b17023SJohn Marino /* Mark block as possibly needing calculation of UIDs. */
1030*e4b17023SJohn Marino bb->aux = &bb->aux;
1031*e4b17023SJohn Marino
1032*e4b17023SJohn Marino for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1033*e4b17023SJohn Marino {
1034*e4b17023SJohn Marino gimple phi = gsi_stmt (gsi);
1035*e4b17023SJohn Marino tree result = gimple_phi_result (phi);
1036*e4b17023SJohn Marino tree result_var;
1037*e4b17023SJohn Marino size_t i;
1038*e4b17023SJohn Marino
1039*e4b17023SJohn Marino if (!is_gimple_reg (result))
1040*e4b17023SJohn Marino continue;
1041*e4b17023SJohn Marino
1042*e4b17023SJohn Marino result_var = SSA_NAME_VAR (result);
1043*e4b17023SJohn Marino for (i = 0; i < gimple_phi_num_args (phi); i++)
1044*e4b17023SJohn Marino {
1045*e4b17023SJohn Marino tree arg = gimple_phi_arg_def (phi, i);
1046*e4b17023SJohn Marino edge e = gimple_phi_arg_edge (phi, i);
1047*e4b17023SJohn Marino
1048*e4b17023SJohn Marino /* If the argument is not an SSA_NAME, then we will need a
1049*e4b17023SJohn Marino constant initialization. If the argument is an SSA_NAME with
1050*e4b17023SJohn Marino a different underlying variable then a copy statement will be
1051*e4b17023SJohn Marino needed. */
1052*e4b17023SJohn Marino if ((e->flags & EDGE_DFS_BACK)
1053*e4b17023SJohn Marino && (TREE_CODE (arg) != SSA_NAME
1054*e4b17023SJohn Marino || SSA_NAME_VAR (arg) != result_var
1055*e4b17023SJohn Marino || trivially_conflicts_p (bb, result, arg)))
1056*e4b17023SJohn Marino {
1057*e4b17023SJohn Marino tree name;
1058*e4b17023SJohn Marino gimple stmt, last = NULL;
1059*e4b17023SJohn Marino gimple_stmt_iterator gsi2;
1060*e4b17023SJohn Marino
1061*e4b17023SJohn Marino gsi2 = gsi_last_bb (gimple_phi_arg_edge (phi, i)->src);
1062*e4b17023SJohn Marino if (!gsi_end_p (gsi2))
1063*e4b17023SJohn Marino last = gsi_stmt (gsi2);
1064*e4b17023SJohn Marino
1065*e4b17023SJohn Marino /* In theory the only way we ought to get back to the
1066*e4b17023SJohn Marino start of a loop should be with a COND_EXPR or GOTO_EXPR.
1067*e4b17023SJohn Marino However, better safe than sorry.
1068*e4b17023SJohn Marino If the block ends with a control statement or
1069*e4b17023SJohn Marino something that might throw, then we have to
1070*e4b17023SJohn Marino insert this assignment before the last
1071*e4b17023SJohn Marino statement. Else insert it after the last statement. */
1072*e4b17023SJohn Marino if (last && stmt_ends_bb_p (last))
1073*e4b17023SJohn Marino {
1074*e4b17023SJohn Marino /* If the last statement in the block is the definition
1075*e4b17023SJohn Marino site of the PHI argument, then we can't insert
1076*e4b17023SJohn Marino anything after it. */
1077*e4b17023SJohn Marino if (TREE_CODE (arg) == SSA_NAME
1078*e4b17023SJohn Marino && SSA_NAME_DEF_STMT (arg) == last)
1079*e4b17023SJohn Marino continue;
1080*e4b17023SJohn Marino }
1081*e4b17023SJohn Marino
1082*e4b17023SJohn Marino /* Create a new instance of the underlying variable of the
1083*e4b17023SJohn Marino PHI result. */
1084*e4b17023SJohn Marino stmt = gimple_build_assign (result_var,
1085*e4b17023SJohn Marino gimple_phi_arg_def (phi, i));
1086*e4b17023SJohn Marino name = make_ssa_name (result_var, stmt);
1087*e4b17023SJohn Marino gimple_assign_set_lhs (stmt, name);
1088*e4b17023SJohn Marino
1089*e4b17023SJohn Marino /* copy location if present. */
1090*e4b17023SJohn Marino if (gimple_phi_arg_has_location (phi, i))
1091*e4b17023SJohn Marino gimple_set_location (stmt,
1092*e4b17023SJohn Marino gimple_phi_arg_location (phi, i));
1093*e4b17023SJohn Marino
1094*e4b17023SJohn Marino /* Insert the new statement into the block and update
1095*e4b17023SJohn Marino the PHI node. */
1096*e4b17023SJohn Marino if (last && stmt_ends_bb_p (last))
1097*e4b17023SJohn Marino gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT);
1098*e4b17023SJohn Marino else
1099*e4b17023SJohn Marino gsi_insert_after (&gsi2, stmt, GSI_NEW_STMT);
1100*e4b17023SJohn Marino SET_PHI_ARG_DEF (phi, i, name);
1101*e4b17023SJohn Marino }
1102*e4b17023SJohn Marino }
1103*e4b17023SJohn Marino }
1104*e4b17023SJohn Marino
1105*e4b17023SJohn Marino /* Unmark this block again. */
1106*e4b17023SJohn Marino bb->aux = NULL;
1107*e4b17023SJohn Marino }
1108*e4b17023SJohn Marino }
1109*e4b17023SJohn Marino
1110*e4b17023SJohn Marino /* Free all memory associated with going out of SSA form. SA is
1111*e4b17023SJohn Marino the outof-SSA info object. */
1112*e4b17023SJohn Marino
1113*e4b17023SJohn Marino void
finish_out_of_ssa(struct ssaexpand * sa)1114*e4b17023SJohn Marino finish_out_of_ssa (struct ssaexpand *sa)
1115*e4b17023SJohn Marino {
1116*e4b17023SJohn Marino free (sa->partition_to_pseudo);
1117*e4b17023SJohn Marino if (sa->values)
1118*e4b17023SJohn Marino BITMAP_FREE (sa->values);
1119*e4b17023SJohn Marino delete_var_map (sa->map);
1120*e4b17023SJohn Marino BITMAP_FREE (sa->partition_has_default_def);
1121*e4b17023SJohn Marino memset (sa, 0, sizeof *sa);
1122*e4b17023SJohn Marino }
1123*e4b17023SJohn Marino
1124*e4b17023SJohn Marino /* Take the current function out of SSA form, translating PHIs as described in
1125*e4b17023SJohn Marino R. Morgan, ``Building an Optimizing Compiler'',
1126*e4b17023SJohn Marino Butterworth-Heinemann, Boston, MA, 1998. pp 176-186. */
1127*e4b17023SJohn Marino
1128*e4b17023SJohn Marino unsigned int
rewrite_out_of_ssa(struct ssaexpand * sa)1129*e4b17023SJohn Marino rewrite_out_of_ssa (struct ssaexpand *sa)
1130*e4b17023SJohn Marino {
1131*e4b17023SJohn Marino /* If elimination of a PHI requires inserting a copy on a backedge,
1132*e4b17023SJohn Marino then we will have to split the backedge which has numerous
1133*e4b17023SJohn Marino undesirable performance effects.
1134*e4b17023SJohn Marino
1135*e4b17023SJohn Marino A significant number of such cases can be handled here by inserting
1136*e4b17023SJohn Marino copies into the loop itself. */
1137*e4b17023SJohn Marino insert_backedge_copies ();
1138*e4b17023SJohn Marino
1139*e4b17023SJohn Marino
1140*e4b17023SJohn Marino /* Eliminate PHIs which are of no use, such as virtual or dead phis. */
1141*e4b17023SJohn Marino eliminate_useless_phis ();
1142*e4b17023SJohn Marino
1143*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS))
1144*e4b17023SJohn Marino gimple_dump_cfg (dump_file, dump_flags & ~TDF_DETAILS);
1145*e4b17023SJohn Marino
1146*e4b17023SJohn Marino remove_ssa_form (flag_tree_ter, sa);
1147*e4b17023SJohn Marino
1148*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS))
1149*e4b17023SJohn Marino gimple_dump_cfg (dump_file, dump_flags & ~TDF_DETAILS);
1150*e4b17023SJohn Marino
1151*e4b17023SJohn Marino return 0;
1152*e4b17023SJohn Marino }
1153