lower_calls.c 20.3 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
/*
2
 * Copyright (C) 1995-2011 University of Karlsruhe.  All right reserved.
Christian Würdig's avatar
Christian Würdig committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 *
 * This file is part of libFirm.
 *
 * 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.
 *
 * 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
20
21
22
23
24
/**
 * @file
 * @brief   Lowering of Calls with compound parameters and return types.
 * @author  Michael Beck
 * @version $Id$
25
26
27
 */
#include "config.h"

28
29
30
#include <stdbool.h>

#include "lower_calls.h"
31
#include "lowering.h"
32
33
34
35
36
37
38
#include "irprog_t.h"
#include "irnode_t.h"
#include "type_t.h"
#include "irmode_t.h"
#include "ircons.h"
#include "irgmod.h"
#include "irgwalk.h"
39
#include "irmemory.h"
40
#include "irtools.h"
41
#include "iroptimize.h"
42
#include "array_t.h"
43
#include "pmap.h"
44
#include "error.h"
45

46
47
static pmap *pointer_types;
static pmap *lowered_mtps;
48
49
50
51
52

/**
 * Default implementation for finding a pointer type for a given element type.
 * Simple create a new one.
 */
53
static ir_type *get_pointer_type(ir_type *dest_type)
54
{
55
56
57
58
	ir_type *res = (ir_type*)pmap_get(pointer_types, dest_type);
	if (res == NULL) {
		res = new_type_pointer(dest_type);
		pmap_insert(pointer_types, dest_type, res);
59
60
	}
	return res;
61
}
62

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
static void fix_parameter_entities(ir_graph *irg, size_t n_compound_ret)
{
	ir_type *frame_type = get_irg_frame_type(irg);
	size_t   n_compound = get_compound_n_members(frame_type);
	size_t   i;

	if (n_compound_ret == 0)
		return;

	for (i = 0; i < n_compound; ++i) {
		ir_entity *member = get_compound_member(frame_type, i);
		size_t     num;
		if (!is_parameter_entity(member))
			continue;

		/* increase parameter number since we added a new parameter in front */
		num = get_entity_parameter_number(member);
80
81
		if (num == IR_VA_START_PARAMETER_NUMBER)
			continue;
82
83
84
85
		set_entity_parameter_number(member, num + n_compound_ret);
	}
}

86
87
88
89
/**
 * Creates a new lowered type for a method type with compound
 * arguments. The new type is associated to the old one and returned.
 */
90
static ir_type *lower_mtp(compound_call_lowering_flags flags, ir_type *mtp)
91
{
92
93
94
95
96
97
98
99
100
	bool      must_be_lowered = false;
	ir_type  *lowered;
	ir_type **params;
	ir_type **results;
	size_t    n_ress;
	size_t    n_params;
	size_t    nn_ress;
	size_t    nn_params;
	size_t    i;
101
	mtp_additional_properties mtp_properties;
102
103
104
105
106

	if (!is_Method_type(mtp))
		return mtp;

	lowered = (ir_type*)pmap_get(lowered_mtps, mtp);
107
	if (lowered != NULL)
108
109
		return lowered;

110
111
112
113
114
115
116
	/* check if the type has to be lowered at all */
	n_ress = get_method_n_ress(mtp);
	for (i = 0; i < n_ress; ++i) {
		ir_type *res_tp = get_method_res_type(mtp, i);
		if (is_compound_type(res_tp)) {
			must_be_lowered = true;
			break;
117
		}
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
	}
	if (!must_be_lowered)
		return mtp;

	n_params  = get_method_n_params(mtp);
	results   = ALLOCANZ(ir_type*, n_ress);
	params    = ALLOCANZ(ir_type*, n_params + n_ress);
	nn_ress   = 0;
	nn_params = 0;

	/* add a hidden parameter in front for every compound result */
	for (i = 0; i < n_ress; ++i) {
		ir_type *res_tp = get_method_res_type(mtp, i);

		if (is_compound_type(res_tp)) {
			/* this compound will be allocated on callers stack and its
			   address will be transmitted as a hidden parameter. */
			ir_type *ptr_tp = get_pointer_type(res_tp);
			params[nn_params++] = ptr_tp;
			if (flags & LF_RETURN_HIDDEN)
				results[nn_ress++] = ptr_tp;
		} else {
			/* scalar result */
			results[nn_ress++] = res_tp;
142
143
		}
	}
144
145
146
147
148
149
	/* copy over parameter types */
	for (i = 0; i < n_params; ++i) {
		params[nn_params++] = get_method_param_type(mtp, i);
	}
	assert(nn_ress <= n_ress);
	assert(nn_params <= n_params + n_ress);
150
151

	/* create the new type */
152
	lowered = new_d_type_method(nn_params, nn_ress, get_type_dbg_info(mtp));
153
154
155
156
157
158
159

	/* fill it */
	for (i = 0; i < nn_params; ++i)
		set_method_param_type(lowered, i, params[i]);
	for (i = 0; i < nn_ress; ++i)
		set_method_res_type(lowered, i, results[i]);

160
	set_method_variadicity(lowered, get_method_variadicity(mtp));
161

162
	set_method_calling_convention(lowered, get_method_calling_convention(mtp) | cc_compound_ret);
163
164
165
166
167
	mtp_properties = get_method_additional_properties(mtp);
	/* after lowering the call is not const anymore, since it writes to the
	 * memory for the return value passed to it */
	mtp_properties &= ~mtp_property_const;
	set_method_additional_properties(lowered, mtp_properties);
168

169
	/* associate the lowered type with the original one for easier access */
170
	set_lowered_type(mtp, lowered);
171
	pmap_insert(lowered_mtps, mtp, lowered);
172
173

	return lowered;
174
175
176
}

/**
177
178
179
180
 * A call list entry.
 */
typedef struct cl_entry cl_entry;
struct cl_entry {
181
182
183
	cl_entry *next;   /**< Pointer to the next entry. */
	ir_node  *call;   /**< Pointer to the Call node. */
	ir_node  *copyb;  /**< List of all CopyB nodes. */
184
185
186
187
};

/**
 * Walker environment for fix_args_and_collect_calls().
188
 */
189
typedef struct wlk_env_t {
Michael Beck's avatar
Michael Beck committed
190
	size_t               arg_shift;        /**< The Argument index shift for parameters. */
191
192
193
	struct obstack       obst;             /**< An obstack to allocate the data on. */
	cl_entry             *cl_list;         /**< The call list. */
	pmap                 *dummy_map;       /**< A map for finding the dummy arguments. */
194
	compound_call_lowering_flags flags;
195
	ir_type              *lowered_mtp;     /**< The lowered method type of the current irg if any. */
196
197
	unsigned             only_local_mem:1; /**< Set if only local memory access was found. */
	unsigned             changed:1;        /**< Set if the current graph was changed. */
198
199
200
} wlk_env;

/**
201
202
203
204
205
206
207
 * Return the call list entry of a call node.
 * If no entry exists yet, allocate one and enter the node into
 * the call list of the environment.
 *
 * @param call   A Call node.
 * @param env    The environment.
 */
208
209
static cl_entry *get_Call_entry(ir_node *call, wlk_env *env)
{
210
	cl_entry *res = (cl_entry*)get_irn_link(call);
211
	if (res == NULL) {
212
		res = OALLOC(&env->obst, cl_entry);
213
214
215
216
217
218
219
		res->next  = env->cl_list;
		res->call  = call;
		res->copyb = NULL;
		set_irn_link(call, res);
		env->cl_list = res;
	}
	return res;
220
221
222
}

/**
223
224
225
226
227
228
 * Finds the base address of an address by skipping Sel's and address
 * calculation.
 *
 * @param adr   the address
 * @param pEnt  points to the base entity if any
 */
229
230
static ir_node *find_base_adr(ir_node *ptr, ir_entity **pEnt)
{
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
	ir_entity *ent = NULL;
	assert(mode_is_reference(get_irn_mode(ptr)));

	for (;;) {
		if (is_Sel(ptr)) {
			ent = get_Sel_entity(ptr);
			ptr = get_Sel_ptr(ptr);
		}
		else if (is_Add(ptr)) {
			ir_node *left = get_Add_left(ptr);
			if (mode_is_reference(get_irn_mode(left)))
				ptr = left;
			else
				ptr = get_Add_right(ptr);
			ent = NULL;
		} else if (is_Sub(ptr)) {
			ptr = get_Sub_left(ptr);
			ent = NULL;
		} else {
			*pEnt = ent;
			return ptr;
		}
	}
}

/**
 * Check if a given pointer represents non-local memory.
 */
259
260
static void check_ptr(ir_node *ptr, wlk_env *env)
{
261
262
263
264
265
	ir_storage_class_class_t sc;
	ir_entity                *ent;

	/* still alias free */
	ptr = find_base_adr(ptr, &ent);
266
	sc  = get_base_sc(classify_pointer(ptr, ent));
267
268
269
270
271
272
	if (sc != ir_sc_localvar && sc != ir_sc_malloced) {
		/* non-local memory access */
		env->only_local_mem = 0;
	}
}

273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
/*
 * Returns non-zero if a Call is surely a self-recursive Call.
 * Beware: if this functions returns 0, the call might be self-recursive!
 */
static bool is_self_recursive_Call(const ir_node *call)
{
	const ir_node *callee = get_Call_ptr(call);

	if (is_SymConst_addr_ent(callee)) {
		const ir_entity *ent = get_SymConst_entity(callee);
		const ir_graph  *irg = get_entity_irg(ent);
		if (irg == get_irn_irg(call))
			return 1;
	}
	return 0;
}

290
291
/**
 * Post walker: shift all parameter indexes
292
 * and collect Calls with compound returns in the call list.
293
294
 * If a non-alias free memory access is found, reset the alias free
 * flag.
295
 */
296
297
static void fix_args_and_collect_calls(ir_node *n, void *ctx)
{
298
	wlk_env *env = (wlk_env*)ctx;
299
	ir_type *ctp;
300
301
302
303
304
305
306
307
308
309
310
311
312
	ir_node *ptr;

	switch (get_irn_opcode(n)) {
	case iro_Load:
	case iro_Store:
		if (env->only_local_mem) {
			ptr = get_irn_n(n, 1);
			check_ptr(ptr, env);
		}
		break;
	case iro_Proj:
		if (env->arg_shift > 0) {
			ir_node *pred = get_Proj_pred(n);
313
			ir_graph *irg = get_irn_irg(n);
314
315

			/* Fix the argument numbers */
316
			if (pred == get_irg_args(irg)) {
317
318
319
320
321
322
				long pnr = get_Proj_proj(n);
				set_Proj_proj(n, pnr + env->arg_shift);
				env->changed = 1;
			}
		}
		break;
323
324
325
	case iro_Call: {
		size_t i;
		size_t n_res;
326
327
328
		if (! is_self_recursive_Call(n)) {
			/* any non self recursive call might access global memory */
			env->only_local_mem = 0;
329
		}
330

331
		ctp = get_Call_type(n);
332
333
334
335
336
337
338
339
340
		/* check for compound returns */
		for (i = 0, n_res = get_method_n_ress(ctp); i < n_res; ++i) {
			if (is_compound_type(get_method_res_type(ctp, i))) {
				/*
				 * This is a call with a compound return. As the result
				 * might be ignored, we must put it in the list.
				 */
				(void)get_Call_entry(n, env);
				break;
341
342
			}
		}
343
		break;
344
345
346
	}
	case iro_CopyB: {
		ir_node *src = get_CopyB_src(n);
347
348
349
350
351
		if (env->only_local_mem) {
			check_ptr(get_CopyB_src(n), env);
			if (env->only_local_mem)
				check_ptr(get_CopyB_dst(n), env);
		}
352
353
354
355
356
357
358
359
360
361
362
363
		/* check for compound returns */
		if (is_Proj(src)) {
			ir_node *proj = get_Proj_pred(src);
			if (is_Proj(proj) && get_Proj_proj(proj) == pn_Call_T_result) {
				ir_node *call = get_Proj_pred(proj);
				if (is_Call(call)) {
					ctp = get_Call_type(call);
					if (is_compound_type(get_method_res_type(ctp, get_Proj_proj(src)))) {
						/* found a CopyB from compound Call result */
						cl_entry *e = get_Call_entry(call, env);
						set_irn_link(n, e->copyb);
						e->copyb = n;
364
365
366
					}
				}
			}
367
		}
368
		break;
369
	}
370
371
372
373
374
375
376
377
378
379
	case iro_Sel: {
		ir_entity *ent  = get_Sel_entity(n);
		ir_type   *type = get_entity_type(ent);

		/* we need to copy compound parameters */
		if (is_parameter_entity(ent) && is_compound_type(type)) {
			env->only_local_mem = 0;
		}
		break;
	}
380
381
382
	default:
		/* do nothing */
		break;
383
	}
384
385
386
}

/**
387
388
 * Returns non-zero if a node is a compound address
 * of a frame-type entity.
389
390
391
392
 *
 * @param ft   the frame type
 * @param adr  the node
 */
393
static bool is_compound_address(ir_type *ft, ir_node *adr)
394
{
395
396
397
	ir_entity *ent;

	if (! is_Sel(adr))
398
		return false;
399
	if (get_Sel_n_indexs(adr) != 0)
400
		return false;
401
402
	ent = get_Sel_entity(adr);
	return get_entity_owner(ent) == ft;
403
404
}

405
/** A pair for the copy-return-optimization. */
406
typedef struct cr_pair {
407
408
	ir_entity *ent; /**< the entity than can be removed from the frame */
	ir_node *arg;   /**< the argument that replaces the entities address */
409
410
411
412
413
414
} cr_pair;

/**
 * Post walker: fixes all entities addresses for the copy-return
 * optimization.
 *
yb9976's avatar
yb9976 committed
415
 * Note: We expect the length of the cr_pair array (i.e. number of compound
416
417
 * return values) to be 1 (C, C++) in almost all cases, so ignore the
 * linear search complexity here.
418
 */
419
420
static void do_copy_return_opt(ir_node *n, void *ctx)
{
421
422
	if (is_Sel(n)) {
		ir_entity *ent = get_Sel_entity(n);
423
424
		cr_pair   *arr = (cr_pair*)ctx;
		size_t    i, l;
425

426
		for (i = 0, l = ARR_LEN(arr); i < l; ++i) {
427
428
429
430
431
432
			if (ent == arr[i].ent) {
				exchange(n, arr[i].arg);
				break;
			}
		}
	}
433
434
435
}

/**
436
437
438
439
440
441
442
443
444
445
446
 * Return a Sel node that selects a dummy argument of type tp.
 * Dummy arguments are only needed once and we use a map
 * to store them.
 * We could even assign all dummy arguments the same offset
 * in the frame type ...
 *
 * @param irg    the graph
 * @param block  the block where a newly create Sel should be placed
 * @param tp     the type of the dummy entity that should be create
 * @param env    the environment
 */
447
448
static ir_node *get_dummy_sel(ir_graph *irg, ir_node *block, ir_type *tp,
                              wlk_env *env)
449
{
450
451
452
453
454
	ir_entity *ent;
	pmap_entry *e;

	/* use a map the check if we already create such an entity */
	e = pmap_find(env->dummy_map, tp);
455
	if (e) {
456
		ent = (ir_entity*)e->value;
457
	} else {
458
		ir_type *ft = get_irg_frame_type(irg);
459
460
		ident   *dummy_id = id_unique("dummy.%u");
		ent = new_entity(ft, dummy_id, tp);
461
462
463
464
		pmap_insert(env->dummy_map, tp, ent);

		if (get_type_state(ft) == layout_fixed) {
			/* Fix the layout again */
465
			panic("Fixed layout not implemented");
466
467
		}
	}
468
	return new_r_simpleSel(block, get_irg_no_mem(irg), get_irg_frame(irg), ent);
469
470
471
472
473
474
475
476
477
478
479
}

/**
 * Add the hidden parameter from the CopyB node to the Call node.
 *
 * @param irg    the graph
 * @param n_com  number of compound results (will be number of hidden parameters)
 * @param ins    in array to store the hidden parameters into
 * @param entry  the call list
 * @param env    the environment
 */
480
481
static void add_hidden_param(ir_graph *irg, size_t n_com, ir_node **ins,
                             cl_entry *entry, wlk_env *env)
482
{
483
	ir_node *p, *n, *mem, *blk;
Michael Beck's avatar
Michael Beck committed
484
	size_t n_args;
485
486
487

	n_args = 0;
	for (p = entry->copyb; p; p = n) {
488
489
490
		ir_node *src = get_CopyB_src(p);
		size_t   idx = get_Proj_proj(src);
		n = (ir_node*)get_irn_link(p);
491
492
493
494

		ins[idx] = get_CopyB_dst(p);
		blk      = get_nodes_block(p);

495
496
497
498
499
500
		/* use the memory output of the call and not the input of the CopyB
		 * otherwise stuff breaks if the call was mtp_property_const, because
		 * then the copyb skips the call. But after lowering the call is not
		 * const anymore, and its memory has to be used */
		mem = new_r_Proj(entry->call, mode_M, pn_Call_M);

501
		/* get rid of the CopyB */
502
		turn_into_tuple(p, pn_CopyB_max+1);
503
		set_Tuple_pred(p, pn_CopyB_M,         mem);
504
		set_Tuple_pred(p, pn_CopyB_X_regular, new_r_Jmp(blk));
Matthias Braun's avatar
Matthias Braun committed
505
		set_Tuple_pred(p, pn_CopyB_X_except,  new_r_Bad(irg, mode_X));
506
507
508
509
510
511
		++n_args;
	}

	/* now create dummy entities for function with ignored return value */
	if (n_args < n_com) {
		ir_type *ctp = get_Call_type(entry->call);
512
513
		size_t   i;
		size_t   j;
514

515
516
		if (is_lowered_type(ctp))
			ctp = get_associated_type(ctp);
517
518
519
520
521
522
523
524
525
526

		for (j = i = 0; i < get_method_n_ress(ctp); ++i) {
			ir_type *rtp = get_method_res_type(ctp, i);
			if (is_compound_type(rtp)) {
				if (ins[j] == NULL)
					ins[j] = get_dummy_sel(irg, get_nodes_block(entry->call), rtp, env);
				++j;
			}
		}
	}
527
528
529
530
}

/**
 * Fix all calls on a call list by adding hidden parameters.
531
 *
532
533
534
 * @param irg  the graph
 * @param env  the environment
 */
535
536
static void fix_call_list(ir_graph *irg, wlk_env *env)
{
537
538
539
	cl_entry *p;
	ir_node *call, **new_in;
	ir_type *ctp, *lowered_mtp;
Michael Beck's avatar
Michael Beck committed
540
	size_t i, n_res, n_params, n_com, pos;
541
542
543
544
545

	new_in = NEW_ARR_F(ir_node *, 0);
	for (p = env->cl_list; p; p = p->next) {
		call = p->call;
		ctp = get_Call_type(call);
546
		lowered_mtp = lower_mtp(env->flags, ctp);
547
548
549
550
551
		set_Call_type(call, lowered_mtp);

		n_params = get_Call_n_params(call);

		n_com = 0;
Michael Beck's avatar
Michael Beck committed
552
		for (i = 0, n_res = get_method_n_ress(ctp); i < n_res; ++i) {
553
554
555
556
557
558
			if (is_compound_type(get_method_res_type(ctp, i)))
				++n_com;
		}
		pos = 2;
		ARR_RESIZE(ir_node *, new_in, n_params + n_com + pos);
		memset(new_in, 0, sizeof(*new_in) * (n_params + n_com + pos));
559
560
		add_hidden_param(irg, n_com, &new_in[pos], p, env);
		pos += n_com;
561
562
563
564
565
566
567
568
		/* copy all other parameters */
		for (i = 0; i < n_params; ++i)
			new_in[pos++] = get_Call_param(call, i);
		new_in[0] = get_Call_mem(call);
		new_in[1] = get_Call_ptr(call);

		set_irn_in(call, n_params + n_com + 2, new_in);
	}
569
570
571
572
573
574
575
576
}

/**
 * Transform a graph. If it has compound parameter returns,
 * remove them and use the hidden parameter instead.
 * If it calls methods with compound parameter returns, add hidden
 * parameters.
 *
577
578
 * @param irg  the graph to transform
 */
579
static void transform_irg(compound_call_lowering_flags flags, ir_graph *irg)
580
{
581
582
	ir_entity  *ent = get_irg_entity(irg);
	ir_type    *mtp, *lowered_mtp, *tp, *ft;
Michael Beck's avatar
Michael Beck committed
583
	size_t     i, j, k, n_ress = 0, n_ret_com = 0;
584
	size_t     n_cr_opt;
585
586
587
	ir_node    **new_in, *ret, *endbl, *bl, *mem, *copy;
	cr_pair    *cr_opt;
	wlk_env    env;
588
589
590

	mtp = get_entity_type(ent);

591
592
593
594
	/* calculate the number of compound returns */
	n_ress = get_method_n_ress(mtp);
	for (n_ret_com = i = 0; i < n_ress; ++i) {
		tp = get_method_res_type(mtp, i);
595

596
597
		if (is_compound_type(tp))
			++n_ret_com;
598
599
	}

600
601
	fix_parameter_entities(irg, n_ret_com);

602
603
604
605
606
	if (n_ret_com) {
		/* much easier if we have only one return */
		normalize_one_return(irg);

		/* This graph has a compound argument. Create a new type */
607
		lowered_mtp = lower_mtp(flags, mtp);
608
609
		set_entity_type(ent, lowered_mtp);

610
611
		/* hidden arguments are added first */
		env.arg_shift    = n_ret_com;
612
613
614
	} else {
		/* we must only search for calls */
		env.arg_shift = 0;
615
		lowered_mtp   = NULL;
616
617
	}
	obstack_init(&env.obst);
618
619
	env.cl_list        = NULL;
	env.dummy_map      = pmap_create_ex(8);
620
	env.flags          = flags;
621
	env.lowered_mtp    = lowered_mtp;
622
623
	env.only_local_mem = 1;
	env.changed        = 0;
624
625
626
627
628
629
630
631
632
633
634

	/* scan the code, fix argument numbers and collect calls. */
	irg_walk_graph(irg, firm_clear_link, fix_args_and_collect_calls, &env);

	/* fix all calls */
	if (env.cl_list) {
		fix_call_list(irg, &env);
		env.changed = 1;
	}

	if (n_ret_com) {
Michael Beck's avatar
Michael Beck committed
635
636
		int idx;

637
638
639
		/* STEP 1: find the return. This is simple, we have normalized the graph. */
		endbl = get_irg_end_block(irg);
		ret = NULL;
Michael Beck's avatar
Michael Beck committed
640
641
		for (idx = get_Block_n_cfgpreds(endbl) - 1; idx >= 0; --idx) {
			ir_node *pred = get_Block_cfgpred(endbl, idx);
642
643
644
645
646
647

			if (is_Return(pred)) {
				ret = pred;
				break;
			}
		}
Andreas Zwinkau's avatar
Andreas Zwinkau committed
648
649

		/* in case of infinite loops, there might be no return */
Andreas Zwinkau's avatar
Andreas Zwinkau committed
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
		if (ret != NULL) {
			/*
			 * Now fix the Return node of the current graph.
			 */
			env.changed = 1;

			/*
			 * STEP 2: fix it. For all compound return values add a CopyB,
			 * all others are copied.
			 */
			NEW_ARR_A(ir_node *, new_in, n_ress + 1);

			bl  = get_nodes_block(ret);
			mem = get_Return_mem(ret);

			ft = get_irg_frame_type(irg);
			NEW_ARR_A(cr_pair, cr_opt, n_ret_com);
			n_cr_opt = 0;
			for (j = 1, i = k = 0; i < n_ress; ++i) {
				ir_node *pred = get_Return_res(ret, i);
				tp = get_method_res_type(mtp, i);

				if (is_compound_type(tp)) {
					ir_node *arg = get_irg_args(irg);
674
					arg = new_r_Proj(arg, mode_P_data, k);
Andreas Zwinkau's avatar
Andreas Zwinkau committed
675
676
677
					++k;

					if (is_Unknown(pred)) {
678
679
						/* The Return(Unknown) is the Firm construct for a
						 * missing return. Do nothing. */
Andreas Zwinkau's avatar
Andreas Zwinkau committed
680
681
					} else {
						/**
682
683
684
						 * Sorrily detecting that copy-return is possible isn't
						 * that simple. We must check, that the hidden address
						 * is alias free during the whole function.
Andreas Zwinkau's avatar
Andreas Zwinkau committed
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
						 * A simple heuristic: all Loads/Stores inside
						 * the function access only local frame.
						 */
						if (env.only_local_mem && is_compound_address(ft, pred)) {
							/* we can do the copy-return optimization here */
							cr_opt[n_cr_opt].ent = get_Sel_entity(pred);
							cr_opt[n_cr_opt].arg = arg;
							++n_cr_opt;
						} else { /* copy-return optimization is impossible, do the copy. */
							copy = new_r_CopyB(
									bl,
									mem,
									arg,
									pred,
									tp
									);
							mem = new_r_Proj(copy, mode_M, pn_CopyB_M);
						}
703
					}
704
					if (flags & LF_RETURN_HIDDEN) {
Andreas Zwinkau's avatar
Andreas Zwinkau committed
705
706
707
708
709
						new_in[j] = arg;
						++j;
					}
				} else { /* scalar return value */
					new_in[j] = pred;
710
711
712
					++j;
				}
			}
Andreas Zwinkau's avatar
Andreas Zwinkau committed
713
714
715
			/* replace the in of the Return */
			new_in[0] = mem;
			set_irn_in(ret, j, new_in);
716

Andreas Zwinkau's avatar
Andreas Zwinkau committed
717
			if (n_cr_opt > 0) {
718
719
				size_t c;
				size_t n;
720

Andreas Zwinkau's avatar
Andreas Zwinkau committed
721
				irg_walk_graph(irg, NULL, do_copy_return_opt, cr_opt);
722

723
724
				for (c = 0, n = ARR_LEN(cr_opt); c < n; ++c) {
					free_entity(cr_opt[c].ent);
Andreas Zwinkau's avatar
Andreas Zwinkau committed
725
				}
726
727
			}
		}
728
	}
729
730
731

	pmap_destroy(env.dummy_map);
	obstack_free(&env.obst, NULL);
732
}
733

734
static void lower_method_types(type_or_ent tore, void *env)
735
{
736
737
	const compound_call_lowering_flags *flags
		= (const compound_call_lowering_flags*)env;
738
739

	/* fix method entities */
740
	if (is_entity(tore.ent)) {
741
742
743
744
		ir_entity *ent     = tore.ent;
		ir_type   *tp      = get_entity_type(ent);
		ir_type   *lowered = lower_mtp(*flags, tp);
		set_entity_type(ent, lowered);
745
	} else {
746
		ir_type *tp = tore.typ;
747
748
749

		/* fix pointer to methods */
		if (is_Pointer_type(tp)) {
750
751
752
			ir_type *points_to         = get_pointer_points_to_type(tp);
			ir_type *lowered_points_to = lower_mtp(*flags, points_to);
			set_pointer_points_to_type(tp, lowered_points_to);
753
754
		}
	}
755
756
}

757
void lower_calls_with_compounds(compound_call_lowering_flags flags)
758
{
Michael Beck's avatar
Michael Beck committed
759
	size_t i, n;
760

761
762
	pointer_types = pmap_create();
	lowered_mtps = pmap_create();
763

764
	/* first step: Transform all graphs */
Michael Beck's avatar
Michael Beck committed
765
	for (i = 0, n = get_irp_n_irgs(); i < n; ++i) {
766
767
		ir_graph *irg = get_irp_irg(i);
		transform_irg(flags, irg);
768
	}
769

770
	/* second step: Lower all method types of visible entities */
771
	type_walk(NULL, lower_method_types, &flags);
772

773
774
	pmap_destroy(lowered_mtps);
	pmap_destroy(pointer_types);
775
}