Branch data Line data Source code
1 : : /* Gimple range phi analysis.
2 : : Copyright (C) 2023-2025 Free Software Foundation, Inc.
3 : : Contributed by Andrew MacLeod <amacleod@redhat.com>.
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify
8 : : it under the terms of the GNU General Public License as published by
9 : : the Free Software Foundation; either version 3, or (at your option)
10 : : any later version.
11 : :
12 : : GCC is distributed in the hope that it will be useful,
13 : : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : : GNU General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with GCC; see the file COPYING3. If not see
19 : : <http://www.gnu.org/licenses/>. */
20 : :
21 : : #include "config.h"
22 : : #include "system.h"
23 : : #include "coretypes.h"
24 : : #include "backend.h"
25 : : #include "insn-codes.h"
26 : : #include "tree.h"
27 : : #include "gimple.h"
28 : : #include "ssa.h"
29 : : #include "gimple-pretty-print.h"
30 : : #include "gimple-range.h"
31 : : #include "gimple-range-cache.h"
32 : : #include "value-range-storage.h"
33 : : #include "tree-cfg.h"
34 : : #include "target.h"
35 : : #include "attribs.h"
36 : : #include "gimple-iterator.h"
37 : : #include "gimple-walk.h"
38 : : #include "cfganal.h"
39 : :
40 : : // Invoke a phi analyzer. It will process all the current PHI groups
41 : : // and export any ranges found to set_range_info.
42 : : // When finished, it will simply dispose of itself.
43 : :
44 : : void
45 : 4308183 : phi_analysis (range_query &q)
46 : : {
47 : 4308183 : phi_analyzer analyze (q);
48 : 4308183 : }
49 : :
50 : : // Initialize a phi_group from another group G.
51 : :
52 : 692685 : phi_group::phi_group (const phi_group &g)
53 : : {
54 : 692685 : m_group = g.m_group;
55 : 692685 : m_modifier = g.m_modifier;
56 : 692685 : m_modifier_op = g.m_modifier_op;
57 : 692685 : m_vr = g.m_vr;
58 : 692685 : }
59 : :
60 : : // Create a new phi_group with members BM, initial range INIT_RANGE, modifier
61 : : // statement MOD on edge MOD_EDGE, and resolve values using query Q. Calculate
62 : : // the range for the group if possible, otherwise set it to VARYING.
63 : :
64 : 1089359 : phi_group::phi_group (bitmap bm, irange &init_range, gimple *mod,
65 : 1089359 : range_query *q)
66 : : {
67 : : // we dont expect a modifer and no inital value, so trap to have a look.
68 : : // perhaps they are dead cycles and we can just used UNDEFINED.
69 : 1089359 : gcc_checking_assert (!init_range.undefined_p ());
70 : 1089359 : gcc_checking_assert (!init_range.varying_p ());
71 : :
72 : 1089359 : m_modifier_name = NULL_TREE;
73 : 1089359 : m_modifier_op = is_modifier_p (mod, bm, &m_modifier_name);
74 : 1089359 : m_group = bm;
75 : 1089359 : m_vr = init_range;
76 : 1089359 : m_modifier = mod;
77 : : // No modifier means the initial range is the full range.
78 : : // Otherwise try to calculate a range.
79 : 1089359 : if (!m_modifier_op || calculate_using_modifier (q))
80 : 693197 : return;
81 : : // Couldn't calculate a range, set to varying.
82 : 396162 : m_vr.set_varying (init_range.type ());
83 : : }
84 : :
85 : : // Return 0 if S is not a modifier statment for group members BM.
86 : : // If it could be a modifier, return which operand position (1 or 2)
87 : : // the phi member occurs in.
88 : : unsigned
89 : 4986051 : phi_group::is_modifier_p (gimple *s, const bitmap bm, tree *op)
90 : : {
91 : 4986051 : if (!s)
92 : : return 0;
93 : 4955855 : gimple_range_op_handler handler (s);
94 : 4955855 : if (handler)
95 : : {
96 : 4118308 : tree op1 = gimple_range_ssa_p (handler.operand1 ());
97 : 4118308 : tree op2 = gimple_range_ssa_p (handler.operand2 ());
98 : : // Also disallow modifiers that have 2 ssa-names.
99 : 7580498 : if (op1 && !op2 && bitmap_bit_p (bm, SSA_NAME_VERSION (op1)))
100 : : {
101 : 2423924 : if (op)
102 : 1059162 : *op = op1;
103 : 2423924 : return 1;
104 : : }
105 : 1724315 : else if (op2 && !op1 && bitmap_bit_p (bm, SSA_NAME_VERSION (op2)))
106 : : {
107 : 56 : if (op)
108 : 1 : *op = op2;
109 : 56 : return 2;
110 : : }
111 : : }
112 : : return 0;
113 : : }
114 : :
115 : : // Calulcate the range of the phi group using range_query Q.
116 : :
117 : : bool
118 : 1059163 : phi_group::calculate_using_modifier (range_query *q)
119 : : {
120 : : // Look at the modifier for any relation
121 : 1059163 : relation_trio trio = fold_relations (m_modifier, q);
122 : 1059163 : relation_kind k = VREL_VARYING;
123 : 1059163 : if (m_modifier_op == 1)
124 : 1059162 : k = trio.lhs_op1 ();
125 : 1 : else if (m_modifier_op == 2)
126 : 1 : k = trio.lhs_op2 ();
127 : : else
128 : : return false;
129 : :
130 : : // If we can resolve the range using relations, use that range.
131 : 1059163 : if (refine_using_relation (k))
132 : : return true;
133 : :
134 : : // Examine modifier and run iteration evaluations to see if it convergences.
135 : : // The constructor initilaized m_vr to the initial value already.
136 : 407935 : int_range_max nv;
137 : 407935 : int_range_max iter_value = m_vr;
138 : 407935 : int_range_max iter_reach;
139 : :
140 : : // Determine the maximum range of the var reaching here. The back edge
141 : : // usually has a guard restircting the range. Default to VARYING.
142 : 407935 : if (!m_modifier_name
143 : 407935 : || !q->range_of_expr (iter_reach, m_modifier_name, m_modifier))
144 : 0 : iter_reach.set_varying (m_vr.type ());
145 : :
146 : : // Iterative evaluation can be expensive, so heuristically :
147 : : // - PLUS and MINUS are 98% of the cases, and usually handled well enough
148 : : // by loop analysis, The exception is if the reaching range has multiple
149 : : // subranges, those are often worth examining.
150 : : // - All other operations (2%) are worth checking.
151 : 407935 : bool do_iterative = false;
152 : 407935 : if (gimple_code (m_modifier) == GIMPLE_ASSIGN)
153 : 407797 : switch (gimple_assign_rhs_code (m_modifier))
154 : : {
155 : 402237 : case PLUS_EXPR:
156 : 402237 : case MINUS_EXPR:
157 : 402237 : if (iter_reach.num_pairs () > 1)
158 : : do_iterative = true;
159 : : break;
160 : : default:
161 : : do_iterative = true;
162 : : }
163 : :
164 : : // Limit iterations to 1 more than the number of bits.
165 : : unsigned num_iter;
166 : : if (do_iterative)
167 : 27316 : num_iter = TYPE_PRECISION (m_vr.type ()) + 1;
168 : : else
169 : : num_iter = 0;
170 : :
171 : 1284157 : for (unsigned x = 0; x < num_iter; x++)
172 : : {
173 : 888122 : if (!fold_range (nv, m_modifier, iter_value, q))
174 : : break;
175 : : // Ensure nothing calculated is outside outside the reaching range.
176 : 888122 : nv.intersect (iter_reach);
177 : : // If union does nothing, then we have convergence.
178 : 888122 : if (!iter_value.union_ (nv))
179 : : {
180 : 11900 : if (iter_value.varying_p ())
181 : : break;
182 : : // The last iteration Will also reach the PHI node, add it in.
183 : 11773 : fold_range (nv, m_modifier, iter_value, q);
184 : 11773 : iter_value.union_ (nv);
185 : 11773 : m_vr = iter_value;
186 : 11773 : return true;
187 : : }
188 : : }
189 : :
190 : : // Never converged, so bail for now. we could examine the pattern
191 : : // from m_initial to m_vr as an extension Especially if we had a way
192 : : // to project the actual number of iterations (SCEV?)
193 : : //
194 : : // We can also try to identify "parallel" phis to get loop counts and
195 : : // determine the number of iterations of these parallel PHIs.
196 : :
197 : : return false;
198 : 407935 : }
199 : :
200 : :
201 : : // IF the modifier statement has a relation K between the modifier and the
202 : : // PHI member in it, we can project a range based on that.
203 : : // ie, a_2 = PHI <0, a_3> and a_3 = a_2 + 1
204 : : // if the relation a_3 > a_2 is present, the know the range is [0, +INF]
205 : : // m_vr contains the initial value for the PHI range.
206 : :
207 : : bool
208 : 1059163 : phi_group::refine_using_relation (relation_kind k)
209 : : {
210 : 1059163 : if (k == VREL_VARYING)
211 : : return false;
212 : 1041969 : tree type = m_vr.type ();
213 : : // If the type wraps, then relations dont tell us much.
214 : 1041969 : if (TYPE_OVERFLOW_WRAPS (type))
215 : : return false;
216 : :
217 : 651228 : int_range<2> type_range;
218 : 651228 : type_range.set_varying (type);
219 : 651228 : switch (k)
220 : : {
221 : 20156 : case VREL_LT:
222 : 20156 : case VREL_LE:
223 : 20156 : {
224 : : // Value always decreases.
225 : 20156 : m_vr.set (type, type_range.lower_bound (), m_vr.upper_bound ());
226 : 20156 : return true;
227 : : }
228 : :
229 : 631072 : case VREL_GT:
230 : 631072 : case VREL_GE:
231 : 631072 : {
232 : : // Value always increases.
233 : 631072 : m_vr.set (type, m_vr.lower_bound (), type_range.upper_bound ());
234 : 631072 : return true;
235 : : }
236 : :
237 : : // If its always equal, then its simply the initial value.
238 : : // which is what m_vr has already been set to.
239 : : case VREL_EQ:
240 : : return true;
241 : :
242 : : default:
243 : : break;
244 : : }
245 : :
246 : : return false;
247 : 651228 : }
248 : :
249 : : // Dump the information for a phi group to file F.
250 : :
251 : : void
252 : 3 : phi_group::dump (FILE *f)
253 : : {
254 : 3 : unsigned i;
255 : 3 : bitmap_iterator bi;
256 : 3 : fprintf (f, "PHI GROUP < ");
257 : :
258 : 6 : EXECUTE_IF_SET_IN_BITMAP (m_group, 0, i, bi)
259 : : {
260 : 3 : print_generic_expr (f, ssa_name (i), TDF_SLIM);
261 : 3 : fputc (' ',f);
262 : : }
263 : 3 : fprintf (f, "> : range : ");
264 : 3 : m_vr.dump (f);
265 : 3 : fprintf (f, "\n Modifier : ");
266 : 3 : if (m_modifier)
267 : 3 : print_gimple_stmt (f, m_modifier, 0, TDF_SLIM);
268 : : else
269 : 0 : fprintf (f, "NONE\n");
270 : 3 : }
271 : :
272 : : // -------------------------------------------------------------------------
273 : :
274 : : // Construct a phi analyzer which uses range_query G to pick up values.
275 : :
276 : 4308183 : phi_analyzer::phi_analyzer (range_query &query) : m_phi_groups (vNULL)
277 : : {
278 : 4308183 : m_work.create (0);
279 : 4308183 : m_work.safe_grow (20);
280 : :
281 : 4308183 : m_tab.create (0);
282 : 8616366 : m_tab.safe_grow_cleared (num_ssa_names + 10);
283 : :
284 : 4308183 : bitmap_obstack_initialize (&m_bitmaps);
285 : 4308183 : m_simple = BITMAP_ALLOC (&m_bitmaps);
286 : 4308183 : m_current = BITMAP_ALLOC (&m_bitmaps);
287 : :
288 : 4308183 : basic_block bb;
289 : 4308183 : gphi_iterator gphi;
290 : :
291 : 4308183 : if (dump_file && (dump_flags & TDF_DETAILS))
292 : 45 : fprintf (dump_file, "PHI ANALYZER : processing PHIS.\n");
293 : :
294 : : // Process each PHI node to see if it belongs in a group with others.
295 : : // Then calculate an initial value for the group.
296 : 37649423 : FOR_EACH_BB_FN (bb, cfun)
297 : : {
298 : 33341240 : for (gphi = gsi_start_nonvirtual_phis (bb);
299 : 41522766 : !gsi_end_p (gphi);
300 : 8181526 : gsi_next_nonvirtual_phi (&gphi))
301 : 8181526 : process_phi (gphi.phi (), query);
302 : : }
303 : 4308183 : if (dump_file && (dump_flags & TDF_DETAILS))
304 : 45 : fprintf (dump_file, "PHI ANALYZER : Finished processing PHIS.\n");
305 : 4308183 : }
306 : :
307 : : // Destruct a PHI analyzer.
308 : :
309 : 4308183 : phi_analyzer::~phi_analyzer ()
310 : : {
311 : 4308183 : bitmap_obstack_release (&m_bitmaps);
312 : 4308183 : m_tab.release ();
313 : 4308183 : m_work.release ();
314 : 5370958 : for (auto grp : m_phi_groups)
315 : 1385370 : delete grp;
316 : 4308183 : m_phi_groups.release ();
317 : 4308183 : }
318 : :
319 : : // Return the group, if any, that NAME is part of. Do no analysis.
320 : :
321 : : phi_group *
322 : 12328759 : phi_analyzer::group (tree name) const
323 : : {
324 : 12328759 : gcc_checking_assert (TREE_CODE (name) == SSA_NAME);
325 : 12328759 : if (!is_a<gphi *> (SSA_NAME_DEF_STMT (name)))
326 : : return NULL;
327 : 7718702 : unsigned v = SSA_NAME_VERSION (name);
328 : 7718702 : if (v >= m_tab.length ())
329 : : return NULL;
330 : 7718702 : return m_tab[v];
331 : : }
332 : :
333 : : // Return the group NAME is associated with, if any. If name has not been
334 : : // procvessed yet, do the analysis to determine if it is part of a group
335 : : // and return that.
336 : :
337 : : phi_group *
338 : 0 : phi_analyzer::operator[] (tree name)
339 : : {
340 : 0 : gcc_checking_assert (TREE_CODE (name) == SSA_NAME);
341 : :
342 : : // Initial support for irange only.
343 : 0 : if (!irange::supports_p (TREE_TYPE (name)))
344 : : return NULL;
345 : 0 : if (!is_a<gphi *> (SSA_NAME_DEF_STMT (name)))
346 : : return NULL;
347 : :
348 : 0 : unsigned v = SSA_NAME_VERSION (name);
349 : 0 : if (v >= m_tab.length ())
350 : : return NULL;
351 : 0 : return m_tab[v];
352 : : }
353 : :
354 : : // Process phi node PHI to see if it is part of a group. Use QUERY
355 : : // to deteremine ranges.
356 : :
357 : : void
358 : 8181526 : phi_analyzer::process_phi (gphi *phi, range_query &query)
359 : : {
360 : 8181526 : tree def = gimple_phi_result (phi);
361 : 8181526 : unsigned v = SSA_NAME_VERSION (def);
362 : :
363 : 8181526 : gcc_checking_assert (v < m_tab.length ());
364 : : // If this is already on a group, or identified as a simple phi, or
365 : : // not an irange, do not process it.
366 : 16216357 : if (m_tab[v] || bitmap_bit_p (m_simple, v)
367 : 15782639 : || !irange::supports_p (TREE_TYPE (def)))
368 : 7488841 : return;
369 : :
370 : 5055346 : bool cycle_p = true;
371 : :
372 : : // Start with the LHS of the PHI in the worklist.
373 : 5055346 : unsigned x;
374 : 5055346 : m_work.truncate (0);
375 : 5055346 : m_work.safe_push (def);
376 : 5055346 : unsigned phi_count = 1;
377 : 5055346 : bitmap_clear (m_current);
378 : :
379 : : // We can only have 2 externals: an initial value and a modifier.
380 : : // Any more than that and this fails to be a group.
381 : 5055346 : unsigned m_num_extern = 0;
382 : 5055346 : tree m_external[2];
383 : 5055346 : edge m_ext_edge[2];
384 : 5055346 : int_range_max init_range;
385 : 5055346 : init_range.set_undefined ();
386 : :
387 : 15876735 : while (m_work.length () > 0)
388 : : {
389 : 5766043 : tree phi_def = m_work.pop ();
390 : 5766043 : gphi *phi_stmt = as_a<gphi *> (SSA_NAME_DEF_STMT (phi_def));
391 : : // if the phi is already in a different cycle, we don't try to merge.
392 : 5766043 : if (group (phi_def))
393 : : {
394 : : cycle_p = false;
395 : : break;
396 : : }
397 : 5766043 : bitmap_set_bit (m_current, SSA_NAME_VERSION (phi_def));
398 : : // Process the args.
399 : 15255679 : for (x = 0; x < gimple_phi_num_args (phi_stmt); x++)
400 : : {
401 : 10930559 : tree arg = gimple_phi_arg_def (phi_stmt, x);
402 : 10930559 : if (arg == phi_def)
403 : 1365029 : continue;
404 : 10928772 : enum tree_code code = TREE_CODE (arg);
405 : 10928772 : if (code == SSA_NAME)
406 : : {
407 : 7213474 : unsigned v = SSA_NAME_VERSION (arg);
408 : : // Already a member of this potential group.
409 : 7213474 : if (bitmap_bit_p (m_current, v))
410 : 650758 : continue;
411 : : // Part of a different group ends cycle possibility.
412 : 6562716 : if (group (arg) || bitmap_bit_p (m_simple, v))
413 : : {
414 : : cycle_p = false;
415 : 1440923 : break;
416 : : }
417 : : // Check if its a PHI to examine.
418 : 5320754 : gimple *arg_stmt = SSA_NAME_DEF_STMT (arg);
419 : 5320754 : if (arg_stmt && is_a<gphi *> (arg_stmt))
420 : : {
421 : 710697 : phi_count++;
422 : 710697 : m_work.safe_push (arg);
423 : 710697 : continue;
424 : : }
425 : : // More than 2 outside names is too complicated.
426 : 4610057 : if (m_num_extern >= 2)
427 : : {
428 : : cycle_p = false;
429 : : break;
430 : : }
431 : 4411096 : m_external[m_num_extern] = arg;
432 : 4411096 : m_ext_edge[m_num_extern++] = gimple_phi_arg_edge (phi_stmt, x);
433 : : }
434 : 3715298 : else if (code == INTEGER_CST)
435 : : {
436 : : // Constants are just added to the initialization value.
437 : 7430596 : int_range<1> val (TREE_TYPE (arg), wi::to_wide (arg),
438 : 7430596 : wi::to_wide (arg));
439 : 3715298 : init_range.union_ (val);
440 : 3715298 : }
441 : : else
442 : : {
443 : : // Everything else terminates the cycle.
444 : : cycle_p = false;
445 : : break;
446 : : }
447 : : }
448 : : }
449 : :
450 : 5055346 : if (phi_count < 1)
451 : : return;
452 : :
453 : 5055346 : gcc_checking_assert (!bitmap_empty_p (m_current));
454 : :
455 : 5055346 : phi_group *g = NULL;
456 : 5055346 : gimple *mod = NULL;
457 : 5055346 : bool valid = false;
458 : 5055346 : signed init_idx = -1;
459 : 5055346 : int_range_max init_sym;
460 : 5055346 : if (cycle_p)
461 : : {
462 : : valid = true;
463 : : // At this point all the PHIs have been added to the bitmap.
464 : : // the external list needs to be checked for initial values and modifiers.
465 : 7551217 : for (x = 0; x < m_num_extern; x++)
466 : : {
467 : 3896692 : tree name = m_external[x];
468 : 5261509 : if (TREE_CODE (name) == SSA_NAME
469 : 3896692 : && phi_group::is_modifier_p (SSA_NAME_DEF_STMT (name), m_current))
470 : : {
471 : : // Can't have multiple modifiers.
472 : 1364817 : if (mod)
473 : 6135 : valid = false;
474 : 1364817 : mod = SSA_NAME_DEF_STMT (name);
475 : 1364817 : continue;
476 : : }
477 : : // Can't have 2 initializers either.
478 : 2531875 : if (init_idx != -1)
479 : 673585 : valid = false;
480 : 2531875 : init_idx = x;
481 : : }
482 : : // If there is an symbolic initializer as well, include it here.
483 : 3654525 : if (valid && init_idx != -1)
484 : : {
485 : 1184705 : if (query.range_on_edge (init_sym, m_ext_edge[init_idx],
486 : : m_external[init_idx]))
487 : 1184705 : init_range.union_ (init_sym);
488 : : else
489 : : valid = false;
490 : : }
491 : : }
492 : : // If there are less than 2 names, . This PHI may be included
493 : : // by another PHI, making it simple or a group of one will prevent a larger
494 : : // group from being formed.
495 : : // The exception will be pattern matching:
496 : : // a_1 = a_2 OP X
497 : : // a_2 = PHI <const, a_1>
498 : 5055346 : if (phi_count == 1
499 : 5055346 : && (m_num_extern != 1 || init_range.undefined_p () || !mod))
500 : : valid = false;
501 : 1273371 : if (valid && !init_range.varying_p () && !init_range.undefined_p ())
502 : : {
503 : : // Try to create a group based on m_current. If a result comes back
504 : : // with a range that isn't varying, create the group.
505 : 1089359 : phi_group cyc (m_current, init_range, mod, &query);
506 : 1089359 : if (!cyc.range ().varying_p ())
507 : : {
508 : 692685 : g = new phi_group (cyc);
509 : 692685 : m_phi_groups.safe_push (g);
510 : 692685 : if (dump_file && (dump_flags & TDF_DETAILS))
511 : : {
512 : 3 : fprintf (dump_file, "PHI ANALYZER : New ");
513 : 3 : g->dump (dump_file);
514 : 3 : fprintf (dump_file," Initial range was ");
515 : 3 : init_range.dump (dump_file);
516 : 3 : if (init_idx != -1)
517 : : {
518 : 0 : fprintf (dump_file, " including symbolic ");
519 : 0 : print_generic_expr (dump_file, m_external[init_idx],
520 : : TDF_SLIM);
521 : 0 : fprintf (dump_file, " on edge %d->%d with range ",
522 : 0 : m_ext_edge[init_idx]->src->index,
523 : 0 : m_ext_edge[init_idx]->dest->index);
524 : 0 : init_sym.dump (dump_file);
525 : : }
526 : 3 : fputc ('\n',dump_file);
527 : : }
528 : : }
529 : 1089359 : }
530 : : // If this doesn't form a group, all members are instead simple phis.
531 : 5055346 : if (!g)
532 : : {
533 : 4362661 : bitmap_ior_into (m_simple, m_current);
534 : 4362661 : return;
535 : : }
536 : :
537 : : // Now set all entries in the group to this record.
538 : 692685 : unsigned i;
539 : 692685 : bitmap_iterator bi;
540 : 1532065 : EXECUTE_IF_SET_IN_BITMAP (m_current, 0, i, bi)
541 : : {
542 : : // Can't be in more than one group.
543 : 839380 : gcc_checking_assert (m_tab[i] == NULL);
544 : 839380 : m_tab[i] = g;
545 : : // Set the new range in the range query.
546 : 839380 : query.update_range_info (ssa_name (i), g->range ());
547 : : }
548 : : // Allocate a new bitmap for the next time as the original one is now part
549 : : // of the new phi group.
550 : 692685 : m_current = BITMAP_ALLOC (&m_bitmaps);
551 : 5055346 : }
552 : :
553 : : void
554 : 0 : phi_analyzer::dump (FILE *f)
555 : : {
556 : 0 : bool header = false;
557 : 0 : bitmap_clear (m_current);
558 : 0 : for (unsigned x = 0; x < m_tab.length (); x++)
559 : : {
560 : 0 : if (bitmap_bit_p (m_simple, x))
561 : 0 : continue;
562 : 0 : if (bitmap_bit_p (m_current, x))
563 : 0 : continue;
564 : 0 : if (m_tab[x] == NULL)
565 : 0 : continue;
566 : 0 : phi_group *g = m_tab[x];
567 : 0 : bitmap_ior_into (m_current, g->group ());
568 : 0 : if (!header)
569 : : {
570 : 0 : header = true;
571 : 0 : fprintf (f, "\nPHI GROUPS:\n");
572 : : }
573 : 0 : g->dump (f);
574 : : }
575 : 0 : }
|