irouts.c 17 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
#include "config.h"
28

Michael Beck's avatar
Michael Beck committed
29
30
31
#include <string.h>

#include "xmalloc.h"
32
33
#include "irouts.h"
#include "irnode_t.h"
Götz Lindenmaier's avatar
Götz Lindenmaier committed
34
#include "irgraph_t.h"
35
#include "irprog_t.h"
36
#include "irgwalk.h"
37
#include "irtools.h"
38
39
#include "irprintf.h"
#include "error.h"
40

41
42
43
44
45
46
#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
47
/*--------------------------------------------------------------------*/
48
/** Accessing the out datastructures                                 **/
Michael Beck's avatar
Michael Beck committed
49
/*--------------------------------------------------------------------*/
50

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

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

66
/* returns the number of successors of the node: */
67
68
int get_irn_n_outs(const ir_node *node)
{
Michael Beck's avatar
Michael Beck committed
69
	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(const ir_node *def, int pos)
{
80
	assert(pos >= 0 && pos < get_irn_n_outs(def));
81
#ifdef DEBUG_libfirm
82
83
84
85
86
87
	/* assert(def->out_valid); */
#endif /* defined DEBUG_libfirm */
	return def->out[pos+1].use;
}

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

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

109
/* Return the number of control flow successors, ignore keep-alives. */
110
111
int get_Block_n_cfg_outs(const ir_node *bl)
{
Michael Beck's avatar
Michael Beck committed
112
113
	int i, n_cfg_outs = 0;
	assert(bl && is_Block(bl));
114
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
115
	assert(bl->out_valid);
116
#endif /* defined DEBUG_libfirm */
117
118
119
120
	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;
121
	}
Michael Beck's avatar
Michael Beck committed
122
	return n_cfg_outs;
Götz Lindenmaier's avatar
Götz Lindenmaier committed
123
124
}

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

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

150
/* Access predecessor n, ignore keep-alives. */
151
152
ir_node *get_Block_cfg_out(const ir_node *bl, int pos)
{
153
	int i;
Michael Beck's avatar
Michael Beck committed
154
	assert(bl && is_Block(bl));
155
#ifdef DEBUG_libfirm
156
	assert(bl->out_valid);
157
#endif /* defined DEBUG_libfirm */
158
159
160
161
	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;
162
			if (pos < n_outs)
163
				return succ->out[pos + 1].use;
164
165
			else
				pos -= n_outs;
Michael Beck's avatar
Michael Beck committed
166
		}
167
	}
Michael Beck's avatar
Michael Beck committed
168
	return NULL;
Götz Lindenmaier's avatar
Götz Lindenmaier committed
169
170
}

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

Michael Beck's avatar
Michael Beck committed
205
static void irg_out_walk_2(ir_node *node, irg_walk_func *pre,
206
207
                           irg_walk_func *post, void *env)
{
Michael Beck's avatar
Michael Beck committed
208
209
	int     i, n;
	ir_node *succ;
210

Michael Beck's avatar
Michael Beck committed
211
212
	assert(node);
	assert(get_irn_visited(node) < get_irg_visited(current_ir_graph));
213

Michael Beck's avatar
Michael Beck committed
214
	set_irn_visited(node, get_irg_visited(current_ir_graph));
215

Michael Beck's avatar
Michael Beck committed
216
	if (pre) pre(node, env);
217

Michael Beck's avatar
Michael Beck committed
218
219
220
221
222
	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);
	}
223

Michael Beck's avatar
Michael Beck committed
224
	if (post) post(node, env);
225
226
}

227
228
229
void irg_out_walk(ir_node *node, irg_walk_func *pre, irg_walk_func *post,
                  void *env)
{
Michael Beck's avatar
Michael Beck committed
230
231
232
233
234
	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);
	}
235
236
}

237
238
239
static void irg_out_block_walk2(ir_node *bl, irg_walk_func *pre,
                                irg_walk_func *post, void *env)
{
Michael Beck's avatar
Michael Beck committed
240
241
	int i, n;

242
	if (!Block_block_visited(bl)) {
Michael Beck's avatar
Michael Beck committed
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
		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
258
259
}

260
261
/* Walks only over Block nodes in the graph.  Has it's own visited
   flag, so that it can be interleaved with the other walker.         */
262
263
264
void irg_out_block_walk(ir_node *node, irg_walk_func *pre, irg_walk_func *post,
                        void *env)
{
Götz Lindenmaier's avatar
Götz Lindenmaier committed
265

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

Michael Beck's avatar
Michael Beck committed
268
	inc_irg_block_visited(current_ir_graph);
Götz Lindenmaier's avatar
Götz Lindenmaier committed
269

Michael Beck's avatar
Michael Beck committed
270
271
272
273
274
	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);
275
			irg_out_block_walk2(succ, pre, post, env);
Michael Beck's avatar
Michael Beck committed
276
277
278
279
280
		}
	}
	else {
		irg_out_block_walk2(node, pre, post, env);
	}
281
282
}

Michael Beck's avatar
Michael Beck committed
283
/*--------------------------------------------------------------------*/
284
/** Building and Removing the out datastructure                      **/
285
286
287
288
289
290
291
292
293
294
295
296
297
298
/**                                                                  **/
/** 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.                                          **/
299
/** Removes Tuple nodes!                                             **/
Michael Beck's avatar
Michael Beck committed
300
/*--------------------------------------------------------------------*/
301
302


Michael Beck's avatar
Michael Beck committed
303
/** Returns the amount of out edges for not yet visited successors. */
304
305
static int _count_outs(ir_node *n)
{
306
	int start, i, res, irn_arity;
307

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

311
	start = is_Block(n) ? 0 : -1;
Michael Beck's avatar
Michael Beck committed
312
	irn_arity = get_irn_arity(n);
313
	res = irn_arity - start + 1;  /* --1 or --0; 1 for array size. */
Michael Beck's avatar
Michael Beck committed
314

315
	for (i = start; i < irn_arity; ++i) {
Michael Beck's avatar
Michael Beck committed
316
		/* Optimize Tuples.  They annoy if walking the cfg. */
317
318
319
320
321
322
		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
323

324
		/* count Def-Use edges for predecessors */
325
		if (!irn_visited(skipped_pred))
326
			res += _count_outs(skipped_pred);
327

328
		/*count my Def-Use edges */
329
		skipped_pred->out = INT_TO_PTR(PTR_TO_INT(skipped_pred->out) + 1);
Michael Beck's avatar
Michael Beck committed
330
331
	}
	return res;
332
333
}

334
335

/** Returns the amount of out edges for not yet visited successors.
336
 *  This version handles some special nodes like irg_frame, irg_args etc.
337
 */
338
339
static int count_outs(ir_graph *irg)
{
Michael Beck's avatar
Michael Beck committed
340
	ir_node *n;
341
	int     i, res;
Michael Beck's avatar
Michael Beck committed
342
343
344
345

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

346
	/* Now handle anchored nodes. We need the out count of those
347
	   even if they are not visible. */
348
349
	for (i = anchor_last - 1; i >= 0; --i) {
		n = get_irg_anchor(irg, i);
350
		if (!irn_visited_else_mark(n)) {
351
352
353
			n->out = INT_TO_PTR(1);
			++res;
		}
Michael Beck's avatar
Michael Beck committed
354
355
	}
	return res;
356
357
}

Michael Beck's avatar
Michael Beck committed
358
359
360
/**
 * Enter memory for the outs to a node.
 *
361
 * @param use    current node
Michael Beck's avatar
Michael Beck committed
362
363
364
365
 * @param free   current free address in the chunk allocated for the outs
 *
 * @return The next free address
 */
366
367
static ir_def_use_edge *_set_out_edges(ir_node *use, ir_def_use_edge *free)
{
368
	int     n_outs, start, i, irn_arity, pos;
369

370
	mark_irn_visited(use);
371

Michael Beck's avatar
Michael Beck committed
372
	/* Allocate my array */
373
374
	n_outs = PTR_TO_INT(use->out);
	use->out = free;
375
#ifdef DEBUG_libfirm
376
	use->out_valid = 1;
377
#endif /* defined DEBUG_libfirm */
Michael Beck's avatar
Michael Beck committed
378
379
380
381
	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. */
382
	use->out[0].pos = 0;
Michael Beck's avatar
Michael Beck committed
383

384
385
	start = is_Block(use) ? 0 : -1;
	irn_arity = get_irn_arity(use);
386
387

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

Michael Beck's avatar
Michael Beck committed
390
		/* Recursion */
391
		if (!irn_visited(def))
392
393
394
395
396
397
398
399
400
			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
401
402
	}
	return free;
403
404
}

405
406
407
408
409
410
411
412
/**
 * 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
 */
413
414
static ir_def_use_edge *set_out_edges(ir_graph *irg, ir_def_use_edge *free)
{
415
416
	ir_node *n;
	int     i, n_outs;
417

Michael Beck's avatar
Michael Beck committed
418
419
	inc_irg_visited(irg);
	free = _set_out_edges(get_irg_end(irg), free);
420

421
422
423
	/* handle anchored nodes */
	for (i = anchor_last - 1; i >= 0; --i) {
		n = get_irg_anchor(irg, i);
424
		if (!irn_visited_else_mark(n)) {
Michael Beck's avatar
Michael Beck committed
425
426
			n_outs = PTR_TO_INT(n->out);
			n->out = free;
427
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
428
			n->out_valid = 1;
429
#endif /* defined DEBUG_libfirm */
Michael Beck's avatar
Michael Beck committed
430
431
432
			free += n_outs;
		}
	}
433

Michael Beck's avatar
Michael Beck committed
434
	return free;
435
436
}

Michael Beck's avatar
Michael Beck committed
437
/* compute the outs for a given graph */
438
439
void compute_irg_outs(ir_graph *irg)
{
440
441
442
	ir_graph        *rem = current_ir_graph;
	int             n_out_edges = 0;
	ir_def_use_edge *end = NULL;         /* Only for debugging */
443

Michael Beck's avatar
Michael Beck committed
444
	current_ir_graph = irg;
445

Michael Beck's avatar
Michael Beck committed
446
447
	/* Update graph state */
	assert(get_irg_phase_state(current_ir_graph) != phase_building);
Michael Beck's avatar
Michael Beck committed
448

Michael Beck's avatar
Michael Beck committed
449
450
	if (current_ir_graph->outs_state != outs_none)
		free_irg_outs(current_ir_graph);
451

Michael Beck's avatar
Michael Beck committed
452
453
454
	/* 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);
455

Michael Beck's avatar
Michael Beck committed
456
	/* allocate memory for all out edges. */
457
	irg->outs = XMALLOCNZ(ir_def_use_edge, n_out_edges);
458
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
459
	irg->n_outs = n_out_edges;
460
#endif /* defined DEBUG_libfirm */
461

Michael Beck's avatar
Michael Beck committed
462
463
464
	/* 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);
465

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

Michael Beck's avatar
Michael Beck committed
469
470
	current_ir_graph->outs_state = outs_consistent;
	current_ir_graph = rem;
471
472
}

473
474
void assure_irg_outs(ir_graph *irg)
{
Michael Beck's avatar
Michael Beck committed
475
476
	if (get_irg_outs_state(irg) != outs_consistent)
		compute_irg_outs(irg);
Michael Beck's avatar
Michael Beck committed
477
478
}

479
480
void compute_irp_outs(void)
{
Michael Beck's avatar
Michael Beck committed
481
482
483
	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
484
}
Michael Beck's avatar
Michael Beck committed
485

486
487
void free_irp_outs(void)
{
Michael Beck's avatar
Michael Beck committed
488
489
490
	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
491
}
492
493


Michael Beck's avatar
Michael Beck committed
494
495
496
497
498
499
500
/*------------------------------------------------------------*
 *  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...                   *
 *------------------------------------------------------------*/
501
502


503
#ifdef INTERPROCEDURAL_VIEW
Michael Beck's avatar
Michael Beck committed
504
505
506
507
/**
 * Inits the number of outedges for each node
 * before counting.
 */
508
509
static void init_count(ir_node * node, void *env)
{
Matthias Braun's avatar
Matthias Braun committed
510
	(void) env;
Michael Beck's avatar
Michael Beck committed
511
	node->out = (ir_node **) 1; /* 1 for the array size */
512
}
513
514


Michael Beck's avatar
Michael Beck committed
515
516
517
518
519
/**
 * Adjusts the out edge count for its predecessors
 * and adds the current arity to the overall count,
 * which is saved in "env"
 */
520
521
static void node_arity_count(ir_node * node, void * env)
{
522
	int *anz = (int *) env, arity, n_outs, i, start;
Michael Beck's avatar
Michael Beck committed
523
	ir_node *succ;
524

Michael Beck's avatar
Michael Beck committed
525
	arity = get_irn_arity(node);
526
	start = (is_Block(node)) ? 0 : -1;
527

528
	n_outs = 1 + arity + (-start);  // ((is_Block(node)) ? 0 : 1);   // Why + 1??
529
	*anz += n_outs;
530

531
	for (i = start; i < arity; i++) {
Michael Beck's avatar
Michael Beck committed
532
533
534
		succ = get_irn_n(node, i);
		succ->out = (ir_node **)INT_TO_PTR(PTR_TO_INT(succ->out) + 1);
	}
535
}
536

Michael Beck's avatar
Michael Beck committed
537
538
539
540
/*
 * Inits all nodes for setting the outedges
 * Returns the overall count of edges
 */
541
542
int count_ip_outs(void)
{
Michael Beck's avatar
Michael Beck committed
543
	int res = 0;
544

Michael Beck's avatar
Michael Beck committed
545
	cg_walk(init_count, node_arity_count, &res);
546

Michael Beck's avatar
Michael Beck committed
547
	return(res);
548
549
}

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

Michael Beck's avatar
Michael Beck committed
552
553
554
555
556
/**
 * For each node: Sets the pointer to array
 * in which the outedges are written later.
 * The current array start is transported in env
 */
557
558
static void set_array_pointer(ir_node *node, void *env)
{
Michael Beck's avatar
Michael Beck committed
559
560
561
562
563
564
565
566
567
568
569
570
571
	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;
572
573
574
}


Michael Beck's avatar
Michael Beck committed
575
576
577
578
/**
 * Adds an outedge from the predecessor to the
 * current node.
 */
579
580
static void set_out_pointer(ir_node * node, void *env)
{
Michael Beck's avatar
Michael Beck committed
581
582
	int i, arity = get_irn_arity(node);
	ir_node *succ;
583
	int start = (!is_Block(node)) ? -1 : 0;
Matthias Braun's avatar
Matthias Braun committed
584
	(void) env;
Michael Beck's avatar
Michael Beck committed
585

586
	for (i = start; i < arity; ++i) {
Michael Beck's avatar
Michael Beck committed
587
588
589
590
		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);
	}
591
}
592

593

Michael Beck's avatar
Michael Beck committed
594
595
596
/*
 * Sets the outedges for all nodes.
 */
597
598
void set_ip_outs(void)
{
Michael Beck's avatar
Michael Beck committed
599
600
	ir_node **outedge_array = get_irp_ip_outedges();
	cg_walk(set_array_pointer, set_out_pointer, (void *) &outedge_array);
601
602
603
604
}



Michael Beck's avatar
Michael Beck committed
605
606
607
608
609
/*
 * Counts the outedges, allocates memory to save the
 * outedges and fills this outedge array in interprocedural
 * view!
 */
610
611
void compute_ip_outs(void)
{
Michael Beck's avatar
Michael Beck committed
612
613
	int n_out_edges;
	ir_node **out_edges;
614

Michael Beck's avatar
Michael Beck committed
615
616
	assert(get_irp_ip_view_state() == ip_view_valid &&
	 "Cannot construct outs for invalid ip view.");
617

Michael Beck's avatar
Michael Beck committed
618
619
620
	if (irp->outs_state != outs_none) {
		free_ip_outs();
	}
Götz Lindenmaier's avatar
Götz Lindenmaier committed
621

Michael Beck's avatar
Michael Beck committed
622
	global_count = n_out_edges = count_ip_outs();
623
	out_edges    = XMALLOCNZ(ir_node*, n_out_edges);
Michael Beck's avatar
Michael Beck committed
624
625
	set_irp_ip_outedges(out_edges);
	set_ip_outs();
626
627
}

628
629
void free_ip_outs(void)
{
Michael Beck's avatar
Michael Beck committed
630
631
632
633
634
635
	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;
636
}
637
#endif
638

639

640
641
void free_irg_outs(ir_graph *irg)
{
Michael Beck's avatar
Michael Beck committed
642
643
	/*   current_ir_graph->outs_state = outs_none; */
	irg->outs_state = outs_none;
644

Michael Beck's avatar
Michael Beck committed
645
	if (irg->outs) {
646
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
647
		memset(irg->outs, 0, irg->n_outs);
648
#endif /* defined DEBUG_libfirm */
Michael Beck's avatar
Michael Beck committed
649
650
		free(irg->outs);
		irg->outs = NULL;
651
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
652
		irg->n_outs = 0;
653
#endif /* defined DEBUG_libfirm */
Michael Beck's avatar
Michael Beck committed
654
	}
655

656
#ifdef DEBUG_libfirm
Michael Beck's avatar
Michael Beck committed
657
658
659
	/* when debugging, *always* reset all nodes' outs!  irg->outs might
	   have been lying to us */
	irg_walk_graph (irg, reset_outs, NULL, NULL);
660
#endif /* defined DEBUG_libfirm */
661
}