simplify confusing entity/owner interfaces. There is no public way anymore to add...
[libfirm] / ir / lower / lower_calls.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   Lowering of Calls with compound parameters and return types.
23  * @author  Michael Beck
24  * @version $Id$
25  */
26
27 #include "config.h"
28
29 #include "lowering.h"
30 #include "irprog_t.h"
31 #include "irnode_t.h"
32 #include "type_t.h"
33 #include "irmode_t.h"
34 #include "ircons.h"
35 #include "irgmod.h"
36 #include "irgwalk.h"
37 #include "irmemory.h"
38 #include "irtools.h"
39 #include "iroptimize.h"
40 #include "array_t.h"
41 #include "pmap.h"
42 #include "error.h"
43
44 /** A type map for def_find_pointer_type. */
45 static pmap *type_map;
46
47 /**
48  * Default implementation for finding a pointer type for a given element type.
49  * Simple create a new one.
50  */
51 static ir_type *def_find_pointer_type(ir_type *e_type, ir_mode *mode, int alignment)
52 {
53         ir_type *res;
54         pmap_entry *e;
55
56         /* Mode and alignment are always identical in all calls to def_find_pointer_type(), so
57            we simply can use a map from the element type to the pointer type. */
58         e = pmap_find(type_map, e_type);
59         if (e && get_type_mode(e->value) == mode)
60                 res = e->value;
61         else {
62                 res = new_type_pointer(e_type);
63                 set_type_mode(res, mode);
64                 set_type_alignment_bytes(res, alignment);
65                 pmap_insert(type_map, e_type, res);
66         }
67         return res;
68 }
69
70 /**
71  * Creates a new lowered type for a method type with compound
72  * arguments. The new type is associated to the old one and returned.
73  *
74  * @param lp   parameter struct
75  * @param mtp  the method type to lower
76  *
77  * The current implementation expects that a lowered type already
78  * includes the necessary changes ...
79  */
80 static ir_type *create_modified_mtd_type(const lower_params_t *lp, ir_type *mtp)
81 {
82         ir_type *lowered, *ptr_tp, *value_type;
83         ir_type **params, **results, *res_tp;
84         int     *param_map;
85         ir_mode *modes[MAX_REGISTER_RET_VAL];
86         int n_ress, n_params, nn_ress, nn_params, i, first_variadic;
87         add_hidden hidden_params;
88         int        changed = 0;
89         ir_variadicity var;
90
91         if (is_lowered_type(mtp)) {
92                 /* the type is already lowered. Not handled yet. */
93                 assert(0 && "lowered types NYI");
94         }
95
96         lowered = get_associated_type(mtp);
97         if (lowered != NULL)
98                 return lowered;
99
100         n_ress   = get_method_n_ress(mtp);
101         NEW_ARR_A(ir_type *, results, n_ress);
102
103         n_params = get_method_n_params(mtp);
104         NEW_ARR_A(ir_type *, params, n_params + n_ress);
105
106         NEW_ARR_A(int, param_map, n_params + n_ress);
107
108         first_variadic = get_method_first_variadic_param_index(mtp);
109
110         hidden_params = lp->hidden_params;
111         if (hidden_params == ADD_HIDDEN_SMART &&
112                 get_method_variadicity(mtp) == variadicity_variadic)
113                 hidden_params = ADD_HIDDEN_ALWAYS_IN_FRONT;
114
115         if (hidden_params == ADD_HIDDEN_ALWAYS_IN_FRONT) {
116                 /* add hidden in front */
117                 for (nn_ress = nn_params = i = 0; i < n_ress; ++i) {
118                         res_tp = get_method_res_type(mtp, i);
119
120                         if (is_compound_type(res_tp)) {
121                                 int n_regs = 0;
122
123                                 if (lp->flags & LF_SMALL_CMP_IN_REGS)
124                                         n_regs = lp->ret_compound_in_regs(res_tp, modes);
125
126                                 if (n_regs > 0) {
127                                         /* this compound will be returned solely in registers */
128                                         panic("Returning compounds in registers not yet implemented");
129                                 }
130                                 else {
131                                         /* this compound will be allocated on callers stack and its
132                                            address will be transmitted as a hidden parameter. */
133                                         ptr_tp = lp->find_pointer_type(res_tp, get_modeP_data(), lp->def_ptr_alignment);
134                                         params[nn_params]    = ptr_tp;
135                                         param_map[nn_params] = -1 - i;
136                                         ++nn_params;
137                                         changed++;
138                                         if (lp->flags & LF_RETURN_HIDDEN)
139                                                 results[nn_ress++] = ptr_tp;
140                                 }
141                         } else {
142                                 /* scalar result */
143                                 results[nn_ress++] = res_tp;
144                         }
145                 }
146
147                 /* move the index of the first variadic parameter */
148                 first_variadic += nn_params;
149
150                 for (i = 0; i < n_params; ++i, ++nn_params) {
151                         params[nn_params]    = get_method_param_type(mtp, i);
152                         param_map[nn_params] = i;
153                 }
154         } else {
155                 /* add hidden parameters last */
156                 assert(get_method_variadicity(mtp) == variadicity_non_variadic &&
157                         "Cannot add hidden parameters at end of variadic function");
158
159                 for (nn_params = 0; nn_params < n_params; ++nn_params) {
160                         params[nn_params]    = get_method_param_type(mtp, nn_params);
161                         param_map[nn_params] = nn_params;
162                 }
163
164                 for (nn_ress = i = 0; i < n_ress; ++i) {
165                         res_tp = get_method_res_type(mtp, i);
166
167                         if (is_compound_type(res_tp)) {
168                                 params[nn_params] = lp->find_pointer_type(res_tp, get_modeP_data(), lp->def_ptr_alignment);
169                                 param_map[nn_params] = -1 - i;
170                                 ++nn_params;
171                         } else {
172                                 results[nn_ress++] = res_tp;
173                         }
174                 }
175         }
176
177         /* create the new type */
178         lowered = new_d_type_method(nn_params, nn_ress, get_type_dbg_info(mtp));
179
180         /* fill it */
181         for (i = 0; i < nn_params; ++i)
182                 set_method_param_type(lowered, i, params[i]);
183         for (i = 0; i < nn_ress; ++i)
184                 set_method_res_type(lowered, i, results[i]);
185
186         var = get_method_variadicity(mtp);
187         set_method_variadicity(lowered, var);
188         if (var == variadicity_variadic)
189                 set_method_first_variadic_param_index(lowered, first_variadic);
190
191         /* associate the lowered type with the original one for easier access */
192         if (changed) {
193                 set_method_calling_convention(lowered, get_method_calling_convention(mtp) | cc_compound_ret);
194         }
195
196         set_lowered_type(mtp, lowered);
197
198         value_type = get_method_value_param_type(mtp);
199         if (value_type != NULL) {
200                 /* set new param positions */
201                 for (i = 0; i < nn_params; ++i) {
202                         ir_entity *ent = get_method_value_param_ent(lowered, i);
203                         int       pos  = param_map[i];
204                         ident     *id;
205
206                         set_entity_link(ent, INT_TO_PTR(pos));
207                         if (pos < 0) {
208                                 /* formally return value, ignore for now */
209                                 continue;
210                         }
211
212                         id = get_method_param_ident(mtp, pos);
213                         if (id != NULL) {
214                                 set_method_param_ident(lowered, i, id);
215                                 set_entity_ident(ent, id);
216                         }
217                 }
218
219                 set_lowered_type(value_type, get_method_value_param_type(lowered));
220         }
221
222         return lowered;
223 }
224
225 /**
226  * A call list entry.
227  */
228 typedef struct cl_entry cl_entry;
229 struct cl_entry {
230         cl_entry *next;   /**< Pointer to the next entry. */
231         ir_node  *call;   /**< Pointer to the Call node. */
232         ir_node  *copyb;  /**< List of all CopyB nodes. */
233 };
234
235 /**
236  * Walker environment for fix_args_and_collect_calls().
237  */
238 typedef struct _wlk_env_t {
239         int                  arg_shift;        /**< The Argument index shift for parameters. */
240         int                  first_hidden;     /**< The index of the first hidden argument. */
241         struct obstack       obst;             /**< An obstack to allocate the data on. */
242         cl_entry             *cl_list;         /**< The call list. */
243         pmap                 *dummy_map;       /**< A map for finding the dummy arguments. */
244         unsigned             dnr;              /**< The dummy index number. */
245         const lower_params_t *params;          /**< Lowering parameters. */
246         ir_type              *lowered_mtp;     /**< The lowered method type of the current irg if any. */
247         ir_type              *value_params;    /**< The value params type if any. */
248         unsigned             only_local_mem:1; /**< Set if only local memory access was found. */
249         unsigned             changed:1;        /**< Set if the current graph was changed. */
250 } wlk_env;
251
252 /**
253  * Return the call list entry of a call node.
254  * If no entry exists yet, allocate one and enter the node into
255  * the call list of the environment.
256  *
257  * @param call   A Call node.
258  * @param env    The environment.
259  */
260 static cl_entry *get_Call_entry(ir_node *call, wlk_env *env)
261 {
262         cl_entry *res = get_irn_link(call);
263         if (res == NULL) {
264                 cl_entry *res = OALLOC(&env->obst, cl_entry);
265                 res->next  = env->cl_list;
266                 res->call  = call;
267                 res->copyb = NULL;
268                 set_irn_link(call, res);
269                 env->cl_list = res;
270         }
271         return res;
272 }
273
274 /**
275  * Finds the base address of an address by skipping Sel's and address
276  * calculation.
277  *
278  * @param adr   the address
279  * @param pEnt  points to the base entity if any
280  */
281 static ir_node *find_base_adr(ir_node *ptr, ir_entity **pEnt)
282 {
283         ir_entity *ent = NULL;
284         assert(mode_is_reference(get_irn_mode(ptr)));
285
286         for (;;) {
287                 if (is_Sel(ptr)) {
288                         ent = get_Sel_entity(ptr);
289                         ptr = get_Sel_ptr(ptr);
290                 }
291                 else if (is_Add(ptr)) {
292                         ir_node *left = get_Add_left(ptr);
293                         if (mode_is_reference(get_irn_mode(left)))
294                                 ptr = left;
295                         else
296                                 ptr = get_Add_right(ptr);
297                         ent = NULL;
298                 } else if (is_Sub(ptr)) {
299                         ptr = get_Sub_left(ptr);
300                         ent = NULL;
301                 } else {
302                         *pEnt = ent;
303                         return ptr;
304                 }
305         }
306 }
307
308 /**
309  * Check if a given pointer represents non-local memory.
310  */
311 static void check_ptr(ir_node *ptr, wlk_env *env)
312 {
313         ir_storage_class_class_t sc;
314         ir_entity                *ent;
315
316         /* still alias free */
317         ptr = find_base_adr(ptr, &ent);
318         sc  = GET_BASE_SC(classify_pointer(current_ir_graph, ptr, ent));
319         if (sc != ir_sc_localvar && sc != ir_sc_malloced) {
320                 /* non-local memory access */
321                 env->only_local_mem = 0;
322         }
323 }
324
325 /**
326  * Post walker: shift all parameter indexes
327  * and collect Calls with compound returns in the call list.
328  * If a non-alias free memory access is found, reset the alias free
329  * flag.
330  */
331 static void fix_args_and_collect_calls(ir_node *n, void *ctx)
332 {
333         wlk_env *env = ctx;
334         int      i;
335         ir_type *ctp;
336         ir_node *ptr;
337
338         switch (get_irn_opcode(n)) {
339         case iro_Sel:
340                 if (env->lowered_mtp != NULL && env->value_params != NULL) {
341                         ir_entity *ent = get_Sel_entity(n);
342
343                         if (get_entity_owner(ent) == env->value_params) {
344                                 int pos = get_struct_member_index(env->value_params, ent) + env->arg_shift;
345                                 ir_entity *new_ent;
346
347                                 new_ent = get_method_value_param_ent(env->lowered_mtp, pos);
348                                 set_entity_ident(new_ent, get_entity_ident(ent));
349                                 set_Sel_entity(n, new_ent);
350                         }
351                 }
352                 break;
353         case iro_Load:
354         case iro_Store:
355                 if (env->only_local_mem) {
356                         ptr = get_irn_n(n, 1);
357                         check_ptr(ptr, env);
358                 }
359                 break;
360         case iro_Proj:
361                 if (env->arg_shift > 0) {
362                         ir_node *pred = get_Proj_pred(n);
363
364                         /* Fix the argument numbers */
365                         if (pred == get_irg_args(current_ir_graph)) {
366                                 long pnr = get_Proj_proj(n);
367                                 set_Proj_proj(n, pnr + env->arg_shift);
368                                 env->changed = 1;
369                         }
370                 }
371                 break;
372         case iro_Call:
373                 if (! is_self_recursive_Call(n)) {
374                         /* any non self recursive call might access global memory */
375                         env->only_local_mem = 0;
376                 }
377
378                 ctp = get_Call_type(n);
379                 if (env->params->flags & LF_COMPOUND_RETURN) {
380                         /* check for compound returns */
381                         for (i = get_method_n_ress(ctp) -1; i >= 0; --i) {
382                                 if (is_compound_type(get_method_res_type(ctp, i))) {
383                                         /*
384                                          * This is a call with a compound return. As the result
385                                          * might be ignored, we must put it in the list.
386                                          */
387                                         (void)get_Call_entry(n, env);
388                                         break;
389                                 }
390                         }
391                 }
392                 break;
393         case iro_CopyB:
394                 if (env->only_local_mem) {
395                         check_ptr(get_CopyB_src(n), env);
396                         if (env->only_local_mem)
397                                 check_ptr(get_CopyB_dst(n), env);
398                 }
399                 if (env->params->flags & LF_COMPOUND_RETURN) {
400                         /* check for compound returns */
401                         ir_node *src = get_CopyB_src(n);
402                         /* older scheme using value_res_ent */
403                         if (is_Sel(src)) {
404                                 ir_node *proj = get_Sel_ptr(src);
405                                 if (is_Proj(proj) && get_Proj_proj(proj) == pn_Call_P_value_res_base) {
406                                         ir_node *call = get_Proj_pred(proj);
407                                         if (is_Call(call)) {
408                                                 /* found a CopyB from compound Call result */
409                                                 cl_entry *e = get_Call_entry(call, env);
410                                                 set_irn_link(n, e->copyb);
411                                                 e->copyb = n;
412                                         }
413                                 }
414                         } else {
415                                 /* new scheme: compound results are determined by the call type only */
416                                 if (is_Proj(src)) {
417                                         ir_node *proj = get_Proj_pred(src);
418                                         if (is_Proj(proj) && get_Proj_proj(proj) == pn_Call_T_result) {
419                                                 ir_node *call = get_Proj_pred(proj);
420                                                 if (is_Call(call)) {
421                                                         ctp = get_Call_type(call);
422                                                         if (is_compound_type(get_method_res_type(ctp, get_Proj_proj(src)))) {
423                                                                 /* found a CopyB from compound Call result */
424                                                                 cl_entry *e = get_Call_entry(call, env);
425                                                                 set_irn_link(n, e->copyb);
426                                                                 e->copyb = n;
427                                                         }
428                                                 }
429                                         }
430                                 }
431                         }
432                 }
433                 break;
434         default:
435                 /* do nothing */
436                 break;
437         }
438 }
439
440 /**
441  * Returns non-zero if a node is a compound address
442  * of a frame-type entity.
443  *
444  * @param ft   the frame type
445  * @param adr  the node
446  */
447 static int is_compound_address(ir_type *ft, ir_node *adr)
448 {
449         ir_entity *ent;
450
451         if (! is_Sel(adr))
452                 return 0;
453         if (get_Sel_n_indexs(adr) != 0)
454                 return 0;
455         ent = get_Sel_entity(adr);
456         return get_entity_owner(ent) == ft;
457 }
458
459 /** A pair for the copy-return-optimization. */
460 typedef struct cr_pair {
461         ir_entity *ent; /**< the entity than can be removed from the frame */
462         ir_node *arg;   /**< the argument that replaces the entities address */
463 } cr_pair;
464
465 /**
466  * Post walker: fixes all entities addresses for the copy-return
467  * optimization.
468  *
469  * Note: We expect the length of the cr_pair array (ie number of compound
470  * return values) to be 1 (C, C++) in almost all cases, so ignore the
471  * linear search complexity here.
472  */
473 static void do_copy_return_opt(ir_node *n, void *ctx)
474 {
475         cr_pair *arr = ctx;
476         int i;
477
478         if (is_Sel(n)) {
479                 ir_entity *ent = get_Sel_entity(n);
480
481                 for (i = ARR_LEN(arr) - 1; i >= 0; --i) {
482                         if (ent == arr[i].ent) {
483                                 exchange(n, arr[i].arg);
484                                 break;
485                         }
486                 }
487         }
488 }
489
490 /**
491  * Return a Sel node that selects a dummy argument of type tp.
492  * Dummy arguments are only needed once and we use a map
493  * to store them.
494  * We could even assign all dummy arguments the same offset
495  * in the frame type ...
496  *
497  * @param irg    the graph
498  * @param block  the block where a newly create Sel should be placed
499  * @param tp     the type of the dummy entity that should be create
500  * @param env    the environment
501  */
502 static ir_node *get_dummy_sel(ir_graph *irg, ir_node *block, ir_type *tp, wlk_env *env)
503 {
504         ir_entity *ent;
505         pmap_entry *e;
506
507         /* use a map the check if we already create such an entity */
508         e = pmap_find(env->dummy_map, tp);
509         if (e)
510                 ent = e->value;
511         else {
512                 ir_type *ft = get_irg_frame_type(irg);
513                 char buf[16];
514
515                 snprintf(buf, sizeof(buf), "dummy.%u", env->dnr++);
516                 ent = new_entity(ft, new_id_from_str(buf), tp);
517                 pmap_insert(env->dummy_map, tp, ent);
518
519                 if (get_type_state(ft) == layout_fixed) {
520                         /* Fix the layout again */
521                         assert(0 && "Fixed layout not implemented");
522                 }
523         }
524         return new_r_simpleSel(
525                 block,
526                 get_irg_no_mem(irg),
527                 get_irg_frame(irg),
528                 ent);
529 }
530
531 /**
532  * Add the hidden parameter from the CopyB node to the Call node.
533  *
534  * @param irg    the graph
535  * @param n_com  number of compound results (will be number of hidden parameters)
536  * @param ins    in array to store the hidden parameters into
537  * @param entry  the call list
538  * @param env    the environment
539  */
540 static void add_hidden_param(ir_graph *irg, int n_com, ir_node **ins, cl_entry *entry, wlk_env *env)
541 {
542         ir_node *p, *n, *src, *mem, *blk;
543         ir_entity *ent;
544         ir_type *owner;
545         int idx, n_args;
546
547         n_args = 0;
548         for (p = entry->copyb; p; p = n) {
549                 n   = get_irn_link(p);
550                 src = get_CopyB_src(p);
551
552                 /* old scheme using value_res_ent */
553                 if (is_Sel(src)) {
554                         ent = get_Sel_entity(src);
555                         owner = get_entity_owner(ent);
556
557                         /* find the hidden parameter index */
558                         for (idx = 0; idx < get_struct_n_members(owner); ++idx)
559                                 if (get_struct_member(owner, idx) == ent)
560                                         break;
561                         assert(idx < get_struct_n_members(owner));
562                 } else {
563                         /* new scheme: compound returns are determined by the call type and are Proj's */
564                         idx = get_Proj_proj(src);
565                 }
566
567                 ins[idx] = get_CopyB_dst(p);
568                 mem      = get_CopyB_mem(p);
569                 blk      = get_nodes_block(p);
570
571                 /* get rid of the CopyB */
572                 turn_into_tuple(p, pn_CopyB_max);
573                 set_Tuple_pred(p, pn_CopyB_M,         mem);
574                 set_Tuple_pred(p, pn_CopyB_X_regular, new_r_Jmp(blk));
575                 set_Tuple_pred(p, pn_CopyB_X_except,  get_irg_bad(irg));
576                 ++n_args;
577         }
578
579         /* now create dummy entities for function with ignored return value */
580         if (n_args < n_com) {
581                 ir_type *ctp = get_Call_type(entry->call);
582                 int i, j;
583
584                 if (is_lowered_type(ctp))
585                         ctp = get_associated_type(ctp);
586
587                 for (j = i = 0; i < get_method_n_ress(ctp); ++i) {
588                         ir_type *rtp = get_method_res_type(ctp, i);
589                         if (is_compound_type(rtp)) {
590                                 if (ins[j] == NULL)
591                                         ins[j] = get_dummy_sel(irg, get_nodes_block(entry->call), rtp, env);
592                                 ++j;
593                         }
594                 }
595         }
596 }
597
598 /**
599  * Fix all calls on a call list by adding hidden parameters.
600  *
601  * @param irg  the graph
602  * @param env  the environment
603  */
604 static void fix_call_list(ir_graph *irg, wlk_env *env)
605 {
606         const lower_params_t *lp = env->params;
607         cl_entry *p;
608         ir_node *call, **new_in;
609         ir_type *ctp, *lowered_mtp;
610         add_hidden hidden_params;
611         int i, n_params, n_com, pos;
612
613         new_in = NEW_ARR_F(ir_node *, 0);
614         for (p = env->cl_list; p; p = p->next) {
615                 call = p->call;
616                 ctp = get_Call_type(call);
617                 lowered_mtp = create_modified_mtd_type(lp, ctp);
618                 set_Call_type(call, lowered_mtp);
619
620                 hidden_params = lp->hidden_params;
621                 if (hidden_params == ADD_HIDDEN_SMART &&
622                         get_method_variadicity(ctp) == variadicity_variadic)
623                         hidden_params = ADD_HIDDEN_ALWAYS_IN_FRONT;
624
625                 n_params = get_Call_n_params(call);
626
627                 n_com = 0;
628                 for (i = get_method_n_ress(ctp) - 1; i >= 0; --i) {
629                         if (is_compound_type(get_method_res_type(ctp, i)))
630                                 ++n_com;
631                 }
632                 pos = 2;
633                 ARR_RESIZE(ir_node *, new_in, n_params + n_com + pos);
634                 memset(new_in, 0, sizeof(*new_in) * (n_params + n_com + pos));
635                 if (hidden_params == ADD_HIDDEN_ALWAYS_IN_FRONT) {
636                         add_hidden_param(irg, n_com, &new_in[pos], p, env);
637                         pos += n_com;
638                 }
639                 /* copy all other parameters */
640                 for (i = 0; i < n_params; ++i)
641                         new_in[pos++] = get_Call_param(call, i);
642                 if (hidden_params == ADD_HIDDEN_ALWAYS_LAST) {
643                         add_hidden_param(irg, n_com, &new_in[pos], p, env);
644                         pos += n_com;
645                 }
646                 new_in[0] = get_Call_mem(call);
647                 new_in[1] = get_Call_ptr(call);
648
649                 set_irn_in(call, n_params + n_com + 2, new_in);
650         }
651 }
652
653 /**
654  * Transform a graph. If it has compound parameter returns,
655  * remove them and use the hidden parameter instead.
656  * If it calls methods with compound parameter returns, add hidden
657  * parameters.
658  *
659  * @param lp   parameter struct
660  * @param irg  the graph to transform
661  */
662 static void transform_irg(const lower_params_t *lp, ir_graph *irg)
663 {
664         ir_graph   * rem = current_ir_graph;
665         ir_entity  *ent = get_irg_entity(irg);
666         ir_type    *mtp, *lowered_mtp, *tp, *ft;
667         int        i, j, k, n_ress = 0, n_ret_com = 0, n_cr_opt;
668         ir_node    **new_in, *ret, *endbl, *bl, *mem, *copy;
669         cr_pair    *cr_opt;
670         wlk_env    env;
671         add_hidden hidden_params;
672
673         current_ir_graph = irg;
674
675         assert(ent && "Cannot transform graph without an entity");
676         assert(get_irg_phase_state(irg) == phase_high && "call lowering must be done in phase high");
677
678         mtp = get_entity_type(ent);
679
680         if (lp->flags & LF_COMPOUND_RETURN) {
681                 /* calculate the number of compound returns */
682                 n_ress = get_method_n_ress(mtp);
683                 for (n_ret_com = i = 0; i < n_ress; ++i) {
684                         tp = get_method_res_type(mtp, i);
685
686                         if (is_compound_type(tp))
687                                 ++n_ret_com;
688                 }
689         }
690
691         if (n_ret_com) {
692                 /* much easier if we have only one return */
693                 normalize_one_return(irg);
694
695                 /* This graph has a compound argument. Create a new type */
696                 lowered_mtp = create_modified_mtd_type(lp, mtp);
697                 set_entity_type(ent, lowered_mtp);
698
699                 hidden_params = lp->hidden_params;
700                 if (hidden_params == ADD_HIDDEN_SMART &&
701                         get_method_variadicity(mtp) == variadicity_variadic)
702                         hidden_params = ADD_HIDDEN_ALWAYS_IN_FRONT;
703
704                 if (hidden_params == ADD_HIDDEN_ALWAYS_IN_FRONT) {
705                         /* hidden arguments are added first */
706                         env.arg_shift    = n_ret_com;
707                         env.first_hidden = 0;
708                 } else {
709                         /* hidden arguments are added last */
710                         env.arg_shift    = 0;
711                         env.first_hidden = get_method_n_params(mtp);
712                 }
713         } else {
714                 /* we must only search for calls */
715                 env.arg_shift = 0;
716                 lowered_mtp   = NULL;
717         }
718         obstack_init(&env.obst);
719         env.cl_list        = NULL;
720         env.dummy_map      = pmap_create_ex(8);
721         env.dnr            = 0;
722         env.params         = lp;
723         env.lowered_mtp    = lowered_mtp;
724         env.value_params   = get_method_value_param_type(mtp);
725         env.only_local_mem = 1;
726         env.changed        = 0;
727
728         /* scan the code, fix argument numbers and collect calls. */
729         irg_walk_graph(irg, firm_clear_link, fix_args_and_collect_calls, &env);
730
731         /* fix all calls */
732         if (env.cl_list) {
733                 fix_call_list(irg, &env);
734                 env.changed = 1;
735         }
736
737         if (n_ret_com) {
738                 /*
739                  * Now fix the Return node of the current graph.
740                  */
741                 env.changed = 1;
742
743                 /* STEP 1: find the return. This is simple, we have normalized the graph. */
744                 endbl = get_irg_end_block(irg);
745                 ret = NULL;
746                 for (i = get_Block_n_cfgpreds(endbl) - 1; i >= 0; --i) {
747                         ir_node *pred = get_Block_cfgpred(endbl, i);
748
749                         if (is_Return(pred)) {
750                                 ret = pred;
751                                 break;
752                         }
753                 }
754                 /* there should always be a return */
755                 assert(ret);
756
757                 /*
758                  * STEP 2: fix it. For all compound return values add a CopyB,
759                  * all others are copied.
760                  */
761                 NEW_ARR_A(ir_node *, new_in, n_ress + 1);
762
763                 bl  = get_nodes_block(ret);
764                 mem = get_Return_mem(ret);
765
766                 ft = get_irg_frame_type(irg);
767                 NEW_ARR_A(cr_pair, cr_opt, n_ret_com);
768                 n_cr_opt = 0;
769                 for (j = 1, i = k = 0; i < n_ress; ++i) {
770                         ir_node *pred = get_Return_res(ret, i);
771                         tp = get_method_res_type(mtp, i);
772
773                         if (is_compound_type(tp)) {
774                                 ir_node *arg = get_irg_args(irg);
775                                 arg = new_r_Proj(arg, mode_P_data, env.first_hidden + k);
776                                 ++k;
777
778                                 if (is_Unknown(pred)) {
779                                         /* The Return(Unknown) is the Firm construct for a missing return.
780                                            Do nothing. */
781                                 } else {
782                                         /**
783                                          * Sorrily detecting that copy-return is possible isn't that simple.
784                                          * We must check, that the hidden address is alias free during the whole
785                                          * function.
786                                          * A simple heuristic: all Loads/Stores inside
787                                          * the function access only local frame.
788                                          */
789                                         if (env.only_local_mem && is_compound_address(ft, pred)) {
790                                                 /* we can do the copy-return optimization here */
791                                                 cr_opt[n_cr_opt].ent = get_Sel_entity(pred);
792                                                 cr_opt[n_cr_opt].arg = arg;
793                                                 ++n_cr_opt;
794                                         } else { /* copy-return optimization is impossible, do the copy. */
795                                                 copy = new_r_CopyB(
796                                                         bl,
797                                                         mem,
798                                                         arg,
799                                                         pred,
800                                                         tp
801                                                         );
802                                                 mem = new_r_Proj(copy, mode_M, pn_CopyB_M);
803                                         }
804                                 }
805                                 if (lp->flags & LF_RETURN_HIDDEN) {
806                                         new_in[j] = arg;
807                                         ++j;
808                                 }
809                         } else { /* scalar return value */
810                                 new_in[j] = pred;
811                                 ++j;
812                         }
813                 }
814                 /* replace the in of the Return */
815                 new_in[0] = mem;
816                 set_irn_in(ret, j, new_in);
817
818                 if (n_cr_opt > 0) {
819                         irg_walk_graph(irg, NULL, do_copy_return_opt, cr_opt);
820
821                         for (i = ARR_LEN(cr_opt) - 1; i >= 0; --i) {
822                                 free_entity(cr_opt[i].ent);
823                         }
824                 }
825         } /* if (n_ret_com) */
826
827         pmap_destroy(env.dummy_map);
828         obstack_free(&env.obst, NULL);
829
830         if (env.changed) {
831                 /* invalidate the analysis info */
832                 set_irg_outs_inconsistent(irg);
833                 set_irg_loopinfo_state(irg, loopinfo_inconsistent);
834         }
835         current_ir_graph = rem;
836 }
837
838 /**
839  * Returns non-zero if the given type is a method
840  * type that must be lowered.
841  *
842  * @param lp  lowering parameters
843  * @param tp  The type.
844  */
845 static int must_be_lowered(const lower_params_t *lp, ir_type *tp)
846 {
847   int i, n_ress;
848   ir_type *res_tp;
849
850   if (is_Method_type(tp)) {
851     if (lp->flags & LF_COMPOUND_RETURN) {
852       /* check for compound returns */
853       n_ress = get_method_n_ress(tp);
854       for (i = 0; i < n_ress; ++i) {
855         res_tp = get_method_res_type(tp, i);
856
857         if (is_compound_type(res_tp))
858           return 1;
859       }
860     }
861   }
862   return 0;
863 }
864
865 /**
866  * type-walker: lower all method types of entities
867  * and points-to types.
868  */
869 static void lower_method_types(type_or_ent tore, void *env)
870 {
871         const lower_params_t *lp = env;
872         ir_type *tp;
873
874         /* fix method entities */
875         if (is_entity(tore.ent)) {
876                 ir_entity *ent = tore.ent;
877                 tp = get_entity_type(ent);
878
879                 if (must_be_lowered(lp, tp)) {
880                         tp = create_modified_mtd_type(lp, tp);
881                         set_entity_type(ent, tp);
882                 }
883         } else {
884                 tp = tore.typ;
885
886                 /* fix pointer to methods */
887                 if (is_Pointer_type(tp)) {
888                         ir_type *etp = get_pointer_points_to_type(tp);
889                         if (must_be_lowered(lp, etp)) {
890                                 etp = create_modified_mtd_type(lp, etp);
891                                 set_pointer_points_to_type(tp, etp);
892                         }
893                 }
894         }
895 }
896
897 /*
898  * Lower calls with compound parameters and return types.
899  * This function does the following transformations:
900  *
901  * - Adds a new (hidden) pointer parameter for
902  *   any return compound type.
903  *
904  * - Use of the hidden parameters in the function code.
905  *
906  * - Change all calls to functions with compound return
907  *   by providing space for the hidden parameter on the callers
908  *   stack.
909  *
910  * - Replace a possible block copy after the function call.
911  */
912 void lower_calls_with_compounds(const lower_params_t *params)
913 {
914         int i;
915         ir_graph *irg;
916         lower_params_t param = *params;
917
918         if (param.find_pointer_type == NULL) {
919                 param.find_pointer_type = def_find_pointer_type;
920                 type_map = pmap_create_ex(8);
921         } else
922                 type_map = NULL;
923
924         /* first step: Transform all graphs */
925         for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
926                 irg = get_irp_irg(i);
927
928                 transform_irg(&param, irg);
929         }
930
931         /* second step: Lower all method types of visible entities */
932         type_walk(NULL, lower_method_types, &param);
933
934         if (type_map)
935                 pmap_destroy(type_map);
936 }