irouts.c 18.1 KB
Newer Older
Götz Lindenmaier's avatar
Götz Lindenmaier committed
1
/*
Michael Beck's avatar
Michael Beck committed
2
 * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
Matthias Braun's avatar
Matthias Braun committed
3
4
 *
 * This file is part of libFirm.
Michael Beck's avatar
Michael Beck committed
5
 *
Matthias Braun's avatar
Matthias Braun committed
6
7
8
9
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
Michael Beck's avatar
Michael Beck committed
10
 *
Matthias Braun's avatar
Matthias Braun committed
11
12
13
14
15
16
17
 * Licensees holding valid libFirm Professional Edition licenses may use
 * this file in accordance with the libFirm Commercial License.
 * Agreement provided with the Software.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
Michael Beck's avatar
Michael Beck committed
18
 */
19

Matthias Braun's avatar
Matthias Braun committed
20
21
22
23
24
25
26
/**
 * @file
 * @brief    Compute and access out edges (also called def-use edges).
 * @author   Goetz Lindenmaier, Michael Beck
 * @date     1.2002
 * @version  $Id$
 */
Michael Beck's avatar
Michael Beck committed
27
28
#ifdef HAVE_CONFIG_H
#include "config.h"
Michael Beck's avatar
Michael Beck committed
29
#endif
30

Michael Beck's avatar
Michael Beck committed
31
32
33
34
35
#ifdef HAVE_STRING_H
#include <string.h>
#endif

#include "xmalloc.h"
36
37
#include "irouts.h"
#include "irnode_t.h"
Götz Lindenmaier's avatar
Götz Lindenmaier committed
38
#include "irgraph_t.h"
39
#include "irprog_t.h"
40
#include "irgwalk.h"
41
#include "irtools.h"
42

43
44
45
46
47
48
#ifdef DEBUG_libfirm
/* Note:  ir_node.out_valid and ir_graph.n_outs are only present when DEBUG_libfirm is defined */
/* Accesses to out_valid and n_outs are fenced out to avoid breakage
   when compiling with neither DEBUG_libfirm or NDEBUG defined */
#endif /* defined DEBUG_libfirm */

Michael Beck's avatar
Michael Beck committed
49
/*--------------------------------------------------------------------*/
50
/** Accessing the out datastructures                                 **/
Michael Beck's avatar
Michael Beck committed
51
/*--------------------------------------------------------------------*/
52

Matthias Braun's avatar
Matthias Braun committed
53
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
54
/** Clear the outs of a node */
Michael Beck's avatar
Michael Beck committed
55
static void reset_outs(ir_node *node, void *unused) {
Matthias Braun's avatar
Matthias Braun committed
56
	(void) unused;
Michael Beck's avatar
Michael Beck committed
57
58
	node->out       = NULL;
	node->out_valid = 0;
59
}
Matthias Braun's avatar
Matthias Braun committed
60
#endif
61

62
63
64
65
66
int get_irn_outs_computed(const ir_node *node)
{
	return node->out != NULL;
}

67
/* returns the number of successors of the node: */
Michael Beck's avatar
Michael Beck committed
68
69
int get_irn_n_outs(ir_node *node) {
	assert(node && node->kind == k_ir_node);
70
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
71
	/* assert(node->out_valid); */
72
#endif /* defined DEBUG_libfirm */
73
74
	/* we misuse the first for the size info of the out array */
	return node->out[0].pos;
75
76
77
}

/* Access successor n */
78
79
ir_node *get_irn_out(ir_node *def, int pos) {
	assert(pos >= 0 && pos < get_irn_n_outs(def));
80
#ifdef DEBUG_libfirm
81
82
83
84
85
86
87
88
89
90
	/* assert(def->out_valid); */
#endif /* defined DEBUG_libfirm */
	return def->out[pos+1].use;
}

/* Access successor n */
ir_node *get_irn_out_ex(ir_node *def, int pos, int *in_pos) {
	assert(pos >= 0 && pos < get_irn_n_outs(def));
#ifdef DEBUG_libfirm
	/* assert(def->out_valid); */
91
#endif /* defined DEBUG_libfirm */
92
93
	*in_pos = def->out[pos+1].pos;
	return def->out[pos+1].use;
94
95
}

96
97
98
void set_irn_out(ir_node *def, int pos, ir_node *use, int in_pos) {
	assert(def && use);
	assert(pos >= 0 && pos < get_irn_n_outs(def));
99
#ifdef DEBUG_libfirm
100
	def->out_valid = 1;          /* assume that this function is used correctly */
101
#endif /* defined DEBUG_libfirm */
102
103
	def->out[pos+1].use = use;
	def->out[pos+1].pos = in_pos;
104
105
}

106
/* Return the number of control flow successors, ignore keep-alives. */
107
int get_Block_n_cfg_outs(ir_node *bl) {
Michael Beck's avatar
Michael Beck committed
108
109
	int i, n_cfg_outs = 0;
	assert(bl && is_Block(bl));
110
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
111
	assert(bl->out_valid);
112
#endif /* defined DEBUG_libfirm */
113
114
115
116
	for (i = 1; i <= bl->out[0].pos; ++i) {
		ir_node *succ = bl->out[i].use;
		if (get_irn_mode(succ) == mode_X && !is_End(succ))
			n_cfg_outs += succ->out[0].pos;
117
	}
Michael Beck's avatar
Michael Beck committed
118
	return n_cfg_outs;
Götz Lindenmaier's avatar
Götz Lindenmaier committed
119
120
}

121
122
/* Return the number of control flow successors, honor keep-alives. */
int get_Block_n_cfg_outs_ka(ir_node *bl) {
Michael Beck's avatar
Michael Beck committed
123
124
	int i, n_cfg_outs = 0;
	assert(bl && is_Block(bl));
125
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
126
	assert(bl->out_valid);
127
#endif /* defined DEBUG_libfirm */
128
129
	for (i = 1; i <= bl->out[0].pos; ++i) {
		ir_node *succ = bl->out[i].use;
130
		if (get_irn_mode(succ) == mode_X) {
131

132
			if (is_End(succ)) {
133
				/* ignore End if we are in the Endblock */
134
				if (get_nodes_block(succ) == bl)
135
136
137
138
					continue;
				else /* count Keep-alive as one */
					n_cfg_outs += 1;
			} else
139
				n_cfg_outs += succ->out[0].pos;
Michael Beck's avatar
Michael Beck committed
140
		}
141
	}
Michael Beck's avatar
Michael Beck committed
142
	return n_cfg_outs;
143
}
Götz Lindenmaier's avatar
Götz Lindenmaier committed
144

145
/* Access predecessor n, ignore keep-alives. */
146
ir_node *get_Block_cfg_out(ir_node *bl, int pos) {
147
	int i;
Michael Beck's avatar
Michael Beck committed
148
	assert(bl && is_Block(bl));
149
#ifdef DEBUG_libfirm
150
	assert(bl->out_valid);
151
#endif /* defined DEBUG_libfirm */
152
153
154
155
	for (i = 1; i <= bl->out[0].pos; ++i) {
		ir_node *succ = bl->out[i].use;
		if (get_irn_mode(succ) == mode_X && !is_End(succ)) {
			int n_outs = succ->out[0].pos;
156
			if (pos < n_outs)
157
				return succ->out[pos + 1].use;
158
159
			else
				pos -= n_outs;
Michael Beck's avatar
Michael Beck committed
160
		}
161
	}
Michael Beck's avatar
Michael Beck committed
162
	return NULL;
Götz Lindenmaier's avatar
Götz Lindenmaier committed
163
164
}

165
166
/* Access predecessor n, honor keep-alives. */
ir_node *get_Block_cfg_out_ka(ir_node *bl, int pos) {
167
	int i, n_outs;
Michael Beck's avatar
Michael Beck committed
168
	assert(bl && is_Block(bl));
169
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
170
	assert (bl->out_valid);
171
#endif /* defined DEBUG_libfirm */
172
173
	for (i = 1; i <= bl->out[0].pos; ++i) {
		ir_node *succ = bl->out[i].use;
174
		if (get_irn_mode(succ) == mode_X) {
175
176
177
			if (is_End(succ)) {
				ir_node *end_bl = get_nodes_block(succ);
				if (end_bl == bl) {
178
179
180
181
182
					/* ignore End if we are in the Endblock */
					continue;
				}
				if (pos == 0) {
					/* handle keep-alive here: return the Endblock instead of the End node */
183
					return end_bl;
184
185
186
				} else
					--pos;
			} else {
187
				n_outs = succ->out[0].pos;
188
				if (pos < n_outs)
189
					return succ->out[pos + 1].use;
190
191
192
				else
					pos -= n_outs;
			}
Michael Beck's avatar
Michael Beck committed
193
		}
194
	}
Michael Beck's avatar
Michael Beck committed
195
	return NULL;
196
197
}

Michael Beck's avatar
Michael Beck committed
198
static void irg_out_walk_2(ir_node *node, irg_walk_func *pre,
199
            irg_walk_func *post, void *env) {
Michael Beck's avatar
Michael Beck committed
200
201
	int     i, n;
	ir_node *succ;
202

Michael Beck's avatar
Michael Beck committed
203
204
	assert(node);
	assert(get_irn_visited(node) < get_irg_visited(current_ir_graph));
205

Michael Beck's avatar
Michael Beck committed
206
	set_irn_visited(node, get_irg_visited(current_ir_graph));
207

Michael Beck's avatar
Michael Beck committed
208
	if (pre) pre(node, env);
209

Michael Beck's avatar
Michael Beck committed
210
211
212
213
214
	for (i = 0, n = get_irn_n_outs(node); i < n; ++i) {
		succ = get_irn_out(node, i);
		if (get_irn_visited(succ) < get_irg_visited(current_ir_graph))
			irg_out_walk_2(succ, pre, post, env);
	}
215

Michael Beck's avatar
Michael Beck committed
216
	if (post) post(node, env);
217
218
219
}

void irg_out_walk(ir_node *node,
Michael Beck's avatar
Michael Beck committed
220
221
222
223
224
225
226
                  irg_walk_func *pre, irg_walk_func *post,
                  void *env) {
	assert(node);
	if (get_irg_outs_state(current_ir_graph) != outs_none) {
		inc_irg_visited (current_ir_graph);
		irg_out_walk_2(node, pre, post, env);
	}
227
228
}

Michael Beck's avatar
Michael Beck committed
229
static void irg_out_block_walk2(ir_node *bl,
Michael Beck's avatar
Michael Beck committed
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
                                irg_walk_func *pre, irg_walk_func *post,
                                void *env) {
	int i, n;

	if (Block_not_block_visited(bl)) {
		mark_Block_block_visited(bl);

		if (pre)
			pre(bl, env);

		for (i = 0, n =  get_Block_n_cfg_outs(bl); i < n; ++i) {
			/* find the corresponding predecessor block. */
			ir_node *pred = get_Block_cfg_out(bl, i);
			/* recursion */
			irg_out_block_walk2(pred, pre, post, env);
		}

		if (post)
			post(bl, env);
	}
Götz Lindenmaier's avatar
Götz Lindenmaier committed
250
251
}

252
253
254
/* Walks only over Block nodes in the graph.  Has it's own visited
   flag, so that it can be interleaved with the other walker.         */
void irg_out_block_walk(ir_node *node,
Michael Beck's avatar
Michael Beck committed
255
256
                        irg_walk_func *pre, irg_walk_func *post,
                        void *env) {
Götz Lindenmaier's avatar
Götz Lindenmaier committed
257

Michael Beck's avatar
Michael Beck committed
258
	assert(is_Block(node) || (get_irn_mode(node) == mode_X));
Götz Lindenmaier's avatar
Götz Lindenmaier committed
259

Michael Beck's avatar
Michael Beck committed
260
	inc_irg_block_visited(current_ir_graph);
Götz Lindenmaier's avatar
Götz Lindenmaier committed
261

Michael Beck's avatar
Michael Beck committed
262
263
264
265
266
267
268
269
270
271
272
273
	if (get_irn_mode(node) == mode_X) {
		int i, n;

		for (i = 0, n = get_irn_n_outs(node); i < n; ++i) {
			ir_node *succ = get_irn_out(node, i);
			if (get_irn_visited(succ) < get_irg_visited(current_ir_graph))
				irg_out_walk_2(succ, pre, post, env);
		}
	}
	else {
		irg_out_block_walk2(node, pre, post, env);
	}
274
275
}

Michael Beck's avatar
Michael Beck committed
276
/*--------------------------------------------------------------------*/
277
/** Building and Removing the out datastructure                      **/
278
279
280
281
282
283
284
285
286
287
288
289
290
291
/**                                                                  **/
/** The outs of a graph are allocated in a single, large array.      **/
/** This allows to allocate and deallocate the memory for the outs   **/
/** on demand.  The large array is separated into many small ones    **/
/** for each node.  Only a single field to reference the out array   **/
/** is stored in each node and a field referencing the large out     **/
/** array in irgraph.  The 0 field of each out array contains the    **/
/** size of this array.  This saves memory in the irnodes themselves.**/
/** The construction does two passes over the graph.  The first pass **/
/** counts the overall number of outs and the outs of each node.  It **/
/** stores the outs of each node in the out reference of the node.   **/
/** Then the large array is allocated.  The second iteration chops   **/
/** the large array into smaller parts, sets the out edges and       **/
/** recounts the out edges.                                          **/
292
/** Removes Tuple nodes!                                             **/
Michael Beck's avatar
Michael Beck committed
293
/*--------------------------------------------------------------------*/
294
295


Michael Beck's avatar
Michael Beck committed
296
/** Returns the amount of out edges for not yet visited successors. */
297
static int _count_outs(ir_node *n) {
298
	int start, i, res, irn_arity;
299

Michael Beck's avatar
Michael Beck committed
300
	mark_irn_visited(n);
301
	n->out = INT_TO_PTR(1);     /* Space for array size. */
302

303
	start = is_Block(n) ? 0 : -1;
Michael Beck's avatar
Michael Beck committed
304
	irn_arity = get_irn_arity(n);
305
	res = irn_arity - start + 1;  /* --1 or --0; 1 for array size. */
Michael Beck's avatar
Michael Beck committed
306

307
	for (i = start; i < irn_arity; ++i) {
Michael Beck's avatar
Michael Beck committed
308
		/* Optimize Tuples.  They annoy if walking the cfg. */
309
310
311
312
313
314
		ir_node *pred         = get_irn_n(n, i);
		ir_node *skipped_pred = skip_Tuple(pred);

		if (skipped_pred != pred) {
			set_irn_n(n, i, skipped_pred);
		}
Michael Beck's avatar
Michael Beck committed
315

316
		/* count Def-Use edges for predecessors */
317
318
		if (irn_not_visited(skipped_pred))
			res += _count_outs(skipped_pred);
319

320
		/*count my Def-Use edges */
321
		skipped_pred->out = INT_TO_PTR(PTR_TO_INT(skipped_pred->out) + 1);
Michael Beck's avatar
Michael Beck committed
322
323
	}
	return res;
324
325
}

326
327

/** Returns the amount of out edges for not yet visited successors.
328
 *  This version handles some special nodes like irg_frame, irg_args etc.
329
330
 */
static int count_outs(ir_graph *irg) {
Michael Beck's avatar
Michael Beck committed
331
	ir_node *n;
332
	int     i, res;
Michael Beck's avatar
Michael Beck committed
333
334
335
336

	inc_irg_visited(irg);
	res = _count_outs(get_irg_end(irg));

337
	/* Now handle anchored nodes. We need the out count of those
338
	   even if they are not visible. */
339
340
341
342
	for (i = anchor_last - 1; i >= 0; --i) {
		n = get_irg_anchor(irg, i);
		if (irn_not_visited(n)) {
			mark_irn_visited(n);
343

344
345
346
			n->out = INT_TO_PTR(1);
			++res;
		}
Michael Beck's avatar
Michael Beck committed
347
348
	}
	return res;
349
350
}

Michael Beck's avatar
Michael Beck committed
351
352
353
/**
 * Enter memory for the outs to a node.
 *
354
 * @param use    current node
Michael Beck's avatar
Michael Beck committed
355
356
357
358
 * @param free   current free address in the chunk allocated for the outs
 *
 * @return The next free address
 */
359
360
static ir_def_use_edge *_set_out_edges(ir_node *use, ir_def_use_edge *free) {
	int     n_outs, start, i, irn_arity, pos;
361

362
	mark_irn_visited(use);
363

Michael Beck's avatar
Michael Beck committed
364
	/* Allocate my array */
365
366
	n_outs = PTR_TO_INT(use->out);
	use->out = free;
367
#ifdef DEBUG_libfirm
368
	use->out_valid = 1;
369
#endif /* defined DEBUG_libfirm */
Michael Beck's avatar
Michael Beck committed
370
371
372
373
	free += n_outs;
	/* We count the successors again, the space will be sufficient.
	   We use this counter to remember the position for the next back
	   edge. */
374
	use->out[0].pos = 0;
Michael Beck's avatar
Michael Beck committed
375

376
377
	start = is_Block(use) ? 0 : -1;
	irn_arity = get_irn_arity(use);
378
379

	for (i = start; i < irn_arity; ++i) {
380
381
		ir_node *def = get_irn_n(use, i);

Michael Beck's avatar
Michael Beck committed
382
		/* Recursion */
383
384
385
386
387
388
389
390
391
392
		if (irn_not_visited(def))
			free = _set_out_edges(def, free);

		/* Remember this Def-Use edge */
		pos = def->out[0].pos + 1;
		def->out[pos].use = use;
		def->out[pos].pos = i;

		/* increase the number of Def-Use edges so far */
		def->out[0].pos = pos;
Michael Beck's avatar
Michael Beck committed
393
394
	}
	return free;
395
396
}

397
398
399
400
401
402
403
404
/**
 * Enter memory for the outs to a node. Handles special nodes
 *
 * @param irg    the graph
 * @param free   current free address in the chunk allocated for the outs
 *
 * @return The next free address
 */
405
406
407
static ir_def_use_edge *set_out_edges(ir_graph *irg, ir_def_use_edge *free) {
	ir_node *n;
	int     i, n_outs;
408

Michael Beck's avatar
Michael Beck committed
409
410
	inc_irg_visited(irg);
	free = _set_out_edges(get_irg_end(irg), free);
411

412
413
414
415
416
	/* handle anchored nodes */
	for (i = anchor_last - 1; i >= 0; --i) {
		n = get_irg_anchor(irg, i);
		if (irn_not_visited(n)) {
			mark_irn_visited(n);
417

Michael Beck's avatar
Michael Beck committed
418
419
			n_outs = PTR_TO_INT(n->out);
			n->out = free;
420
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
421
			n->out_valid = 1;
422
#endif /* defined DEBUG_libfirm */
Michael Beck's avatar
Michael Beck committed
423
424
425
			free += n_outs;
		}
	}
426

Michael Beck's avatar
Michael Beck committed
427
	return free;
428
429
430
}


Michael Beck's avatar
Michael Beck committed
431
432
433
434
435
/**
 * We want that the out of ProjX from Start contains the next block at
 * position 1, the Start block at position 2.  This is necessary for
 * the out block walker.
 */
436
static INLINE void fix_start_proj(ir_graph *irg) {
Michael Beck's avatar
Michael Beck committed
437
	ir_node *proj    = NULL;
438
	ir_node *irn;
Michael Beck's avatar
Michael Beck committed
439
	ir_node *startbl = get_irg_start_block(irg);
440
	int     i, block_pos, other_pos;
Michael Beck's avatar
Michael Beck committed
441
442
443
444
445
446
447
448

	if (get_Block_n_cfg_outs(startbl)) {
		for (i = get_irn_n_outs(startbl) - 1; i >= 0; --i)
			if (get_irn_mode(get_irn_out(startbl, i)) == mode_X) {
				proj = get_irn_out(startbl, i);
				break;
			}

449
		if (get_irn_out_ex(proj, 0, &block_pos) == startbl) {
Michael Beck's avatar
Michael Beck committed
450
			assert(get_irn_n_outs(proj) == 2);
451
452
453
			irn = get_irn_out_ex(proj, 1, &other_pos);
			set_irn_out(proj, 0, irn, other_pos);
			set_irn_out(proj, 1, startbl, block_pos);
Michael Beck's avatar
Michael Beck committed
454
455
		}
	}
Götz Lindenmaier's avatar
Götz Lindenmaier committed
456
457
}

Michael Beck's avatar
Michael Beck committed
458
/* compute the outs for a given graph */
Götz Lindenmaier's avatar
Götz Lindenmaier committed
459
void compute_irg_outs(ir_graph *irg) {
460
461
462
	ir_graph        *rem = current_ir_graph;
	int             n_out_edges = 0;
	ir_def_use_edge *end = NULL;         /* Only for debugging */
463

Michael Beck's avatar
Michael Beck committed
464
	current_ir_graph = irg;
465

Michael Beck's avatar
Michael Beck committed
466
467
	/* Update graph state */
	assert(get_irg_phase_state(current_ir_graph) != phase_building);
Michael Beck's avatar
Michael Beck committed
468

Michael Beck's avatar
Michael Beck committed
469
470
	if (current_ir_graph->outs_state != outs_none)
		free_irg_outs(current_ir_graph);
471

Michael Beck's avatar
Michael Beck committed
472
473
474
	/* This first iteration counts the overall number of out edges and the
	   number of out edges for each node. */
	n_out_edges = count_outs(irg);
475

Michael Beck's avatar
Michael Beck committed
476
477
	/* allocate memory for all out edges. */
	irg->outs = xcalloc(n_out_edges, sizeof(irg->outs[0]));
478
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
479
	irg->n_outs = n_out_edges;
480
#endif /* defined DEBUG_libfirm */
481

Michael Beck's avatar
Michael Beck committed
482
483
484
	/* The second iteration splits the irg->outs array into smaller arrays
	   for each node and writes the back edges into this array. */
	end = set_out_edges(irg, irg->outs);
485

Michael Beck's avatar
Michael Beck committed
486
487
	/* Check how much memory we have used */
	assert (end == (irg->outs + n_out_edges));
488

Michael Beck's avatar
Michael Beck committed
489
490
491
492
	/* We want that the out of ProjX from Start contains the next block at
	   position 1, the Start block at position 2.  This is necessary for
	   the out block walker. */
	fix_start_proj(irg);
Götz Lindenmaier's avatar
Götz Lindenmaier committed
493

Michael Beck's avatar
Michael Beck committed
494
495
	current_ir_graph->outs_state = outs_consistent;
	current_ir_graph = rem;
496
497
}

Michael Beck's avatar
Michael Beck committed
498
void assure_irg_outs(ir_graph *irg) {
Michael Beck's avatar
Michael Beck committed
499
500
	if (get_irg_outs_state(irg) != outs_consistent)
		compute_irg_outs(irg);
Michael Beck's avatar
Michael Beck committed
501
502
}

Götz Lindenmaier's avatar
Götz Lindenmaier committed
503
void compute_irp_outs(void) {
Michael Beck's avatar
Michael Beck committed
504
505
506
	int i;
	for (i = get_irp_n_irgs() -1; i >= 0; --i)
		compute_irg_outs(get_irp_irg(i));
Götz Lindenmaier's avatar
Götz Lindenmaier committed
507
}
Michael Beck's avatar
Michael Beck committed
508

Götz Lindenmaier's avatar
Götz Lindenmaier committed
509
void free_irp_outs(void) {
Michael Beck's avatar
Michael Beck committed
510
511
512
	int i;
	for (i = get_irp_n_irgs() -1; i >= 0; --i)
		free_irg_outs(get_irp_irg(i));
Götz Lindenmaier's avatar
Götz Lindenmaier committed
513
}
514
515


Michael Beck's avatar
Michael Beck committed
516
517
518
519
520
521
522
/*------------------------------------------------------------*
 *  This computes the outedges for in interprocedural graph.  *
 *  There is one quirk:                                       *
 *  The number of the outedges for each node is saved in      *
 *  the first member of the ir_node** array. Maybe we should  *
 *  change this to make it more portable...                   *
 *------------------------------------------------------------*/
523
524


525
#ifdef INTERPROCEDURAL_VIEW
Michael Beck's avatar
Michael Beck committed
526
527
528
529
530
/**
 * Inits the number of outedges for each node
 * before counting.
 */
static void init_count(ir_node * node, void *env) {
Matthias Braun's avatar
Matthias Braun committed
531
	(void) env;
Michael Beck's avatar
Michael Beck committed
532
	node->out = (ir_node **) 1; /* 1 for the array size */
533
}
534
535


Michael Beck's avatar
Michael Beck committed
536
537
538
539
540
/**
 * Adjusts the out edge count for its predecessors
 * and adds the current arity to the overall count,
 * which is saved in "env"
 */
Michael Beck's avatar
Michael Beck committed
541
static void node_arity_count(ir_node * node, void * env) {
542
	int *anz = (int *) env, arity, n_outs, i, start;
Michael Beck's avatar
Michael Beck committed
543
	ir_node *succ;
544

Michael Beck's avatar
Michael Beck committed
545
	arity = get_irn_arity(node);
546
	start = (is_Block(node)) ? 0 : -1;
547

548
	n_outs = 1 + arity + (-start);  // ((is_Block(node)) ? 0 : 1);   // Why + 1??
549
	*anz += n_outs;
550
551

	for(i = start; i < arity; i++) {
Michael Beck's avatar
Michael Beck committed
552
553
554
		succ = get_irn_n(node, i);
		succ->out = (ir_node **)INT_TO_PTR(PTR_TO_INT(succ->out) + 1);
	}
555
}
556

Michael Beck's avatar
Michael Beck committed
557
558
559
560
/*
 * Inits all nodes for setting the outedges
 * Returns the overall count of edges
 */
561
int count_ip_outs(void) {
Michael Beck's avatar
Michael Beck committed
562
	int res = 0;
563

Michael Beck's avatar
Michael Beck committed
564
	cg_walk(init_count, node_arity_count, &res);
565

Michael Beck's avatar
Michael Beck committed
566
	return(res);
567
568
}

Michael Beck's avatar
Michael Beck committed
569
static int dummy_count = 0, global_count; /* Only for debugging */
570

Michael Beck's avatar
Michael Beck committed
571
572
573
574
575
/**
 * For each node: Sets the pointer to array
 * in which the outedges are written later.
 * The current array start is transported in env
 */
576
static void set_array_pointer(ir_node *node, void *env) {
Michael Beck's avatar
Michael Beck committed
577
578
579
580
581
582
583
584
585
586
587
588
589
	int n_outs;
	ir_node ***free = (ir_node ***) env;

	/* Allocate my array */
	n_outs = PTR_TO_INT(node->out);  /* We wrote the count here in count_ip_outs */
	dummy_count += n_outs;
	assert(dummy_count <= global_count && "More outedges than initially counted!");
	node -> out = *free;
	*free = &((*free)[n_outs]);
	/* We count the successors again, the space will be sufficient.
	   We use this counter to remember the position for the next back
	   edge. */
	node -> out[0] = (ir_node *) 0;
590
591
592
}


Michael Beck's avatar
Michael Beck committed
593
594
595
596
/**
 * Adds an outedge from the predecessor to the
 * current node.
 */
Matthias Braun's avatar
Matthias Braun committed
597
static void set_out_pointer(ir_node * node, void *env) {
Michael Beck's avatar
Michael Beck committed
598
599
	int i, arity = get_irn_arity(node);
	ir_node *succ;
600
	int start = (!is_Block(node)) ? -1 : 0;
Matthias Braun's avatar
Matthias Braun committed
601
	(void) env;
Michael Beck's avatar
Michael Beck committed
602

603
	for (i = start; i < arity; ++i) {
Michael Beck's avatar
Michael Beck committed
604
605
606
607
		succ = get_irn_n(node, i);
		succ->out[get_irn_n_outs(succ)+1] = node;
		succ->out[0] = INT_TO_PTR(get_irn_n_outs(succ) + 1);
	}
608
}
609

610

Michael Beck's avatar
Michael Beck committed
611
612
613
/*
 * Sets the outedges for all nodes.
 */
Michael Beck's avatar
Michael Beck committed
614
615
616
void set_ip_outs(void) {
	ir_node **outedge_array = get_irp_ip_outedges();
	cg_walk(set_array_pointer, set_out_pointer, (void *) &outedge_array);
617
618
619
620
}



Michael Beck's avatar
Michael Beck committed
621
622
623
624
625
/*
 * Counts the outedges, allocates memory to save the
 * outedges and fills this outedge array in interprocedural
 * view!
 */
Götz Lindenmaier's avatar
bugfix    
Götz Lindenmaier committed
626
void compute_ip_outs(void) {
Michael Beck's avatar
Michael Beck committed
627
628
	int n_out_edges;
	ir_node **out_edges;
629

Michael Beck's avatar
Michael Beck committed
630
631
	assert(get_irp_ip_view_state() == ip_view_valid &&
	 "Cannot construct outs for invalid ip view.");
632

Michael Beck's avatar
Michael Beck committed
633
634
635
	if (irp->outs_state != outs_none) {
		free_ip_outs();
	}
Götz Lindenmaier's avatar
Götz Lindenmaier committed
636

Michael Beck's avatar
Michael Beck committed
637
638
639
640
	global_count = n_out_edges = count_ip_outs();
	out_edges = xcalloc(n_out_edges, sizeof(out_edges[0]));
	set_irp_ip_outedges(out_edges);
	set_ip_outs();
641
642
}

Michael Beck's avatar
Michael Beck committed
643
644
645
646
647
648
649
void free_ip_outs(void) {
	ir_node **out_edges = get_irp_ip_outedges();
	if (out_edges != NULL) {
		free(out_edges);
		set_irp_ip_outedges(NULL);
	}
	irp->outs_state = outs_none;
650
}
651
#endif
652

653

Götz Lindenmaier's avatar
Götz Lindenmaier committed
654
void free_irg_outs(ir_graph *irg) {
Michael Beck's avatar
Michael Beck committed
655
656
	/*   current_ir_graph->outs_state = outs_none; */
	irg->outs_state = outs_none;
657

Michael Beck's avatar
Michael Beck committed
658
	if (irg->outs) {
659
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
660
		memset(irg->outs, 0, irg->n_outs);
661
#endif /* defined DEBUG_libfirm */
Michael Beck's avatar
Michael Beck committed
662
663
		free(irg->outs);
		irg->outs = NULL;
664
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
665
		irg->n_outs = 0;
666
#endif /* defined DEBUG_libfirm */
Michael Beck's avatar
Michael Beck committed
667
	}
668

669
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
670
671
672
	/* when debugging, *always* reset all nodes' outs!  irg->outs might
	   have been lying to us */
	irg_walk_graph (irg, reset_outs, NULL, NULL);
673
#endif /* defined DEBUG_libfirm */
674
}