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