lower_calls.c 19.6 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
101
102
103
104
105
	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;

	if (!is_Method_type(mtp))
		return mtp;

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

109
110
111
112
113
114
115
	/* 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;
116
		}
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
	}
	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;
141
142
		}
	}
143
144
145
146
147
148
	/* 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);
149
150

	/* create the new type */
151
	lowered = new_d_type_method(nn_params, nn_ress, get_type_dbg_info(mtp));
152
	lowered->attr.ma.has_compound_ret_parameter = true;
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

	/* associate the lowered type with the original one for easier access */
163
	set_method_calling_convention(lowered, get_method_calling_convention(mtp) | cc_compound_ret);
164
	set_method_additional_properties(lowered, get_method_additional_properties(mtp));
165

166
	set_lowered_type(mtp, lowered);
167
	pmap_insert(lowered_mtps, mtp, lowered);
168
169

	return lowered;
170
171
172
}

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

/**
 * Walker environment for fix_args_and_collect_calls().
184
 */
185
typedef struct wlk_env_t {
Michael Beck's avatar
Michael Beck committed
186
	size_t               arg_shift;        /**< The Argument index shift for parameters. */
187
188
189
	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. */
190
	compound_call_lowering_flags flags;
191
	ir_type              *lowered_mtp;     /**< The lowered method type of the current irg if any. */
192
193
	unsigned             only_local_mem:1; /**< Set if only local memory access was found. */
	unsigned             changed:1;        /**< Set if the current graph was changed. */
194
195
196
} wlk_env;

/**
197
198
199
200
201
202
203
 * 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.
 */
204
205
static cl_entry *get_Call_entry(ir_node *call, wlk_env *env)
{
206
	cl_entry *res = (cl_entry*)get_irn_link(call);
207
	if (res == NULL) {
208
		res = OALLOC(&env->obst, cl_entry);
209
210
211
212
213
214
215
		res->next  = env->cl_list;
		res->call  = call;
		res->copyb = NULL;
		set_irn_link(call, res);
		env->cl_list = res;
	}
	return res;
216
217
218
}

/**
219
220
221
222
223
224
 * 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
 */
225
226
static ir_node *find_base_adr(ir_node *ptr, ir_entity **pEnt)
{
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
	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.
 */
255
256
static void check_ptr(ir_node *ptr, wlk_env *env)
{
257
258
259
260
261
	ir_storage_class_class_t sc;
	ir_entity                *ent;

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

269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/*
 * 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;
}

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

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

327
		ctp = get_Call_type(n);
328
329
330
331
332
333
334
335
336
		/* 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;
337
338
			}
		}
339
		break;
340
341
342
	}
	case iro_CopyB: {
		ir_node *src = get_CopyB_src(n);
343
344
345
346
347
		if (env->only_local_mem) {
			check_ptr(get_CopyB_src(n), env);
			if (env->only_local_mem)
				check_ptr(get_CopyB_dst(n), env);
		}
348
349
350
351
352
353
354
355
356
357
358
359
		/* 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;
360
361
362
					}
				}
			}
363
		}
364
		break;
365
	}
366
367
368
	default:
		/* do nothing */
		break;
369
	}
370
371
372
}

/**
373
374
 * Returns non-zero if a node is a compound address
 * of a frame-type entity.
375
376
377
378
 *
 * @param ft   the frame type
 * @param adr  the node
 */
379
static bool is_compound_address(ir_type *ft, ir_node *adr)
380
{
381
382
383
	ir_entity *ent;

	if (! is_Sel(adr))
384
		return false;
385
	if (get_Sel_n_indexs(adr) != 0)
386
		return false;
387
388
	ent = get_Sel_entity(adr);
	return get_entity_owner(ent) == ft;
389
390
}

391
/** A pair for the copy-return-optimization. */
392
typedef struct cr_pair {
393
394
	ir_entity *ent; /**< the entity than can be removed from the frame */
	ir_node *arg;   /**< the argument that replaces the entities address */
395
396
397
398
399
400
} cr_pair;

/**
 * Post walker: fixes all entities addresses for the copy-return
 * optimization.
 *
yb9976's avatar
yb9976 committed
401
 * Note: We expect the length of the cr_pair array (i.e. number of compound
402
403
 * return values) to be 1 (C, C++) in almost all cases, so ignore the
 * linear search complexity here.
404
 */
405
406
static void do_copy_return_opt(ir_node *n, void *ctx)
{
407
408
	if (is_Sel(n)) {
		ir_entity *ent = get_Sel_entity(n);
409
410
		cr_pair   *arr = (cr_pair*)ctx;
		size_t    i, l;
411

412
		for (i = 0, l = ARR_LEN(arr); i < l; ++i) {
413
414
415
416
417
418
			if (ent == arr[i].ent) {
				exchange(n, arr[i].arg);
				break;
			}
		}
	}
419
420
421
}

/**
422
423
424
425
426
427
428
429
430
431
432
 * 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
 */
433
434
static ir_node *get_dummy_sel(ir_graph *irg, ir_node *block, ir_type *tp,
                              wlk_env *env)
435
{
436
437
438
439
440
	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);
441
	if (e) {
442
		ent = (ir_entity*)e->value;
443
	} else {
444
		ir_type *ft = get_irg_frame_type(irg);
445
446
		ident   *dummy_id = id_unique("dummy.%u");
		ent = new_entity(ft, dummy_id, tp);
447
448
449
450
		pmap_insert(env->dummy_map, tp, ent);

		if (get_type_state(ft) == layout_fixed) {
			/* Fix the layout again */
451
			panic("Fixed layout not implemented");
452
453
		}
	}
454
	return new_r_simpleSel(block, get_irg_no_mem(irg), get_irg_frame(irg), ent);
455
456
457
458
459
460
461
462
463
464
465
}

/**
 * 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
 */
466
467
static void add_hidden_param(ir_graph *irg, size_t n_com, ir_node **ins,
                             cl_entry *entry, wlk_env *env)
468
{
469
	ir_node *p, *n, *mem, *blk;
Michael Beck's avatar
Michael Beck committed
470
	size_t n_args;
471
472
473

	n_args = 0;
	for (p = entry->copyb; p; p = n) {
474
475
476
		ir_node *src = get_CopyB_src(p);
		size_t   idx = get_Proj_proj(src);
		n = (ir_node*)get_irn_link(p);
477
478
479
480
481
482

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

		/* get rid of the CopyB */
483
		turn_into_tuple(p, pn_CopyB_max+1);
484
		set_Tuple_pred(p, pn_CopyB_M,         mem);
485
		set_Tuple_pred(p, pn_CopyB_X_regular, new_r_Jmp(blk));
Matthias Braun's avatar
Matthias Braun committed
486
		set_Tuple_pred(p, pn_CopyB_X_except,  new_r_Bad(irg, mode_X));
487
488
489
490
491
492
		++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);
493
494
		size_t   i;
		size_t   j;
495

496
497
		if (is_lowered_type(ctp))
			ctp = get_associated_type(ctp);
498
499
500
501
502
503
504
505
506
507

		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;
			}
		}
	}
508
509
510
511
}

/**
 * Fix all calls on a call list by adding hidden parameters.
512
 *
513
514
515
 * @param irg  the graph
 * @param env  the environment
 */
516
517
static void fix_call_list(ir_graph *irg, wlk_env *env)
{
518
519
520
	cl_entry *p;
	ir_node *call, **new_in;
	ir_type *ctp, *lowered_mtp;
Michael Beck's avatar
Michael Beck committed
521
	size_t i, n_res, n_params, n_com, pos;
522
523
524
525
526

	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);
527
		lowered_mtp = lower_mtp(env->flags, ctp);
528
529
530
531
532
		set_Call_type(call, lowered_mtp);

		n_params = get_Call_n_params(call);

		n_com = 0;
Michael Beck's avatar
Michael Beck committed
533
		for (i = 0, n_res = get_method_n_ress(ctp); i < n_res; ++i) {
534
535
536
537
538
539
			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));
540
541
		add_hidden_param(irg, n_com, &new_in[pos], p, env);
		pos += n_com;
542
543
544
545
546
547
548
549
		/* 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);
	}
550
551
552
553
554
555
556
557
}

/**
 * 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.
 *
558
559
 * @param irg  the graph to transform
 */
560
static void transform_irg(compound_call_lowering_flags flags, ir_graph *irg)
561
{
562
563
	ir_entity  *ent = get_irg_entity(irg);
	ir_type    *mtp, *lowered_mtp, *tp, *ft;
Michael Beck's avatar
Michael Beck committed
564
	size_t     i, j, k, n_ress = 0, n_ret_com = 0;
565
	size_t     n_cr_opt;
566
567
568
	ir_node    **new_in, *ret, *endbl, *bl, *mem, *copy;
	cr_pair    *cr_opt;
	wlk_env    env;
569
570
571

	mtp = get_entity_type(ent);

572
573
574
575
	/* 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);
576

577
578
		if (is_compound_type(tp))
			++n_ret_com;
579
580
	}

581
582
	fix_parameter_entities(irg, n_ret_com);

583
584
585
586
587
	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 */
588
		lowered_mtp = lower_mtp(flags, mtp);
589
590
		set_entity_type(ent, lowered_mtp);

591
592
		/* hidden arguments are added first */
		env.arg_shift    = n_ret_com;
593
594
595
	} else {
		/* we must only search for calls */
		env.arg_shift = 0;
596
		lowered_mtp   = NULL;
597
598
	}
	obstack_init(&env.obst);
599
600
	env.cl_list        = NULL;
	env.dummy_map      = pmap_create_ex(8);
601
	env.flags          = flags;
602
	env.lowered_mtp    = lowered_mtp;
603
604
	env.only_local_mem = 1;
	env.changed        = 0;
605
606
607
608
609
610
611
612
613
614
615

	/* 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
616
617
		int idx;

618
619
620
		/* 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
621
622
		for (idx = get_Block_n_cfgpreds(endbl) - 1; idx >= 0; --idx) {
			ir_node *pred = get_Block_cfgpred(endbl, idx);
623
624
625
626
627
628

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

		/* in case of infinite loops, there might be no return */
Andreas Zwinkau's avatar
Andreas Zwinkau committed
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
		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);
655
					arg = new_r_Proj(arg, mode_P_data, k);
Andreas Zwinkau's avatar
Andreas Zwinkau committed
656
657
658
					++k;

					if (is_Unknown(pred)) {
659
660
						/* The Return(Unknown) is the Firm construct for a
						 * missing return. Do nothing. */
Andreas Zwinkau's avatar
Andreas Zwinkau committed
661
662
					} else {
						/**
663
664
665
						 * 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
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
						 * 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);
						}
684
					}
685
					if (flags & LF_RETURN_HIDDEN) {
Andreas Zwinkau's avatar
Andreas Zwinkau committed
686
687
688
689
690
						new_in[j] = arg;
						++j;
					}
				} else { /* scalar return value */
					new_in[j] = pred;
691
692
693
					++j;
				}
			}
Andreas Zwinkau's avatar
Andreas Zwinkau committed
694
695
696
			/* replace the in of the Return */
			new_in[0] = mem;
			set_irn_in(ret, j, new_in);
697

Andreas Zwinkau's avatar
Andreas Zwinkau committed
698
			if (n_cr_opt > 0) {
699
700
				size_t c;
				size_t n;
701

Andreas Zwinkau's avatar
Andreas Zwinkau committed
702
				irg_walk_graph(irg, NULL, do_copy_return_opt, cr_opt);
703

704
705
				for (c = 0, n = ARR_LEN(cr_opt); c < n; ++c) {
					free_entity(cr_opt[c].ent);
Andreas Zwinkau's avatar
Andreas Zwinkau committed
706
				}
707
708
			}
		}
709
	}
710
711
712

	pmap_destroy(env.dummy_map);
	obstack_free(&env.obst, NULL);
713
}
714

715
static void lower_method_types(type_or_ent tore, void *env)
716
{
717
718
	const compound_call_lowering_flags *flags
		= (const compound_call_lowering_flags*)env;
719
720

	/* fix method entities */
721
	if (is_entity(tore.ent)) {
722
723
724
725
		ir_entity *ent     = tore.ent;
		ir_type   *tp      = get_entity_type(ent);
		ir_type   *lowered = lower_mtp(*flags, tp);
		set_entity_type(ent, lowered);
726
	} else {
727
		ir_type *tp = tore.typ;
728
729
730

		/* fix pointer to methods */
		if (is_Pointer_type(tp)) {
731
732
733
			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);
734
735
		}
	}
736
737
}

738
void lower_calls_with_compounds(compound_call_lowering_flags flags)
739
{
Michael Beck's avatar
Michael Beck committed
740
	size_t i, n;
741

742
743
	pointer_types = pmap_create();
	lowered_mtps = pmap_create();
744

745
	/* first step: Transform all graphs */
Michael Beck's avatar
Michael Beck committed
746
	for (i = 0, n = get_irp_n_irgs(); i < n; ++i) {
747
748
		ir_graph *irg = get_irp_irg(i);
		transform_irg(flags, irg);
749
	}
750

751
	/* second step: Lower all method types of visible entities */
752
	type_walk(NULL, lower_method_types, &flags);
753

754
755
	pmap_destroy(lowered_mtps);
	pmap_destroy(pointer_types);
756
}