only add new X nodes as tuple preds if CopyB throws an exception
[libfirm] / ir / lower / lower_calls.c
1 /*
2  * Copyright (C) 1995-2011 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, Matthias Braun
24  */
25 #include "config.h"
26
27 #include <stdbool.h>
28
29 #include "lower_calls.h"
30 #include "lowering.h"
31 #include "irprog_t.h"
32 #include "irnode_t.h"
33 #include "type_t.h"
34 #include "irmode_t.h"
35 #include "ircons.h"
36 #include "irgmod.h"
37 #include "irgwalk.h"
38 #include "irmemory.h"
39 #include "irtools.h"
40 #include "iroptimize.h"
41 #include "array_t.h"
42 #include "pmap.h"
43 #include "error.h"
44
45 static pmap *pointer_types;
46 static pmap *lowered_mtps;
47
48 /**
49  * Default implementation for finding a pointer type for a given element type.
50  * Simple create a new one.
51  */
52 static ir_type *get_pointer_type(ir_type *dest_type)
53 {
54         ir_type *res = (ir_type*)pmap_get(pointer_types, dest_type);
55         if (res == NULL) {
56                 res = new_type_pointer(dest_type);
57                 pmap_insert(pointer_types, dest_type, res);
58         }
59         return res;
60 }
61
62 static void fix_parameter_entities(ir_graph *irg, size_t n_compound_ret)
63 {
64         ir_type *frame_type = get_irg_frame_type(irg);
65         size_t   n_members  = get_compound_n_members(frame_type);
66         size_t   i;
67
68         for (i = 0; i < n_members; ++i) {
69                 ir_entity *member = get_compound_member(frame_type, i);
70                 size_t     num;
71                 if (!is_parameter_entity(member))
72                         continue;
73
74                 /* increase parameter number since we added a new parameter in front */
75                 num = get_entity_parameter_number(member);
76                 if (num == IR_VA_START_PARAMETER_NUMBER)
77                         continue;
78                 set_entity_parameter_number(member, num + n_compound_ret);
79         }
80 }
81
82 static void remove_compound_param_entities(ir_graph *irg)
83 {
84         ir_type *frame_type = get_irg_frame_type(irg);
85         size_t   n_members  = get_compound_n_members(frame_type);
86         size_t   i;
87
88         for (i = n_members; i > 0; ) {
89                 ir_entity *member = get_compound_member(frame_type, --i);
90                 ir_type   *type;
91                 if (!is_parameter_entity(member))
92                         continue;
93
94                 type = get_entity_type(member);
95                 if (is_compound_type(type)) {
96                         free_entity(member);
97                 }
98         }
99 }
100
101 /**
102  * Creates a new lowered type for a method type with compound
103  * arguments. The new type is associated to the old one and returned.
104  */
105 static ir_type *lower_mtp(compound_call_lowering_flags flags, ir_type *mtp)
106 {
107         bool      must_be_lowered = false;
108         ir_type  *lowered;
109         ir_type **params;
110         ir_type **results;
111         size_t    n_ress;
112         size_t    n_params;
113         size_t    nn_ress;
114         size_t    nn_params;
115         size_t    i;
116         unsigned  cconv;
117         mtp_additional_properties mtp_properties;
118
119         if (!is_Method_type(mtp))
120                 return mtp;
121
122         lowered = (ir_type*)pmap_get(lowered_mtps, mtp);
123         if (lowered != NULL)
124                 return lowered;
125
126         /* check if the type has to be lowered at all */
127         n_params = get_method_n_params(mtp);
128         n_ress   = get_method_n_ress(mtp);
129         for (i = 0; i < n_ress; ++i) {
130                 ir_type *res_tp = get_method_res_type(mtp, i);
131                 if (is_compound_type(res_tp)) {
132                         must_be_lowered = true;
133                         break;
134                 }
135         }
136         if (!must_be_lowered && !(flags & LF_DONT_LOWER_ARGUMENTS)) {
137                 for (i = 0; i < n_params; ++i) {
138                         ir_type *param_type = get_method_param_type(mtp, i);
139                         if (is_compound_type(param_type)) {
140                                 must_be_lowered = true;
141                                 break;
142                         }
143                 }
144         }
145         if (!must_be_lowered)
146                 return mtp;
147
148         results   = ALLOCANZ(ir_type*, n_ress);
149         params    = ALLOCANZ(ir_type*, n_params + n_ress);
150         nn_ress   = 0;
151         nn_params = 0;
152
153         /* add a hidden parameter in front for every compound result */
154         for (i = 0; i < n_ress; ++i) {
155                 ir_type *res_tp = get_method_res_type(mtp, i);
156
157                 if (is_compound_type(res_tp)) {
158                         /* this compound will be allocated on callers stack and its
159                            address will be transmitted as a hidden parameter. */
160                         ir_type *ptr_tp = get_pointer_type(res_tp);
161                         params[nn_params++] = ptr_tp;
162                         if (flags & LF_RETURN_HIDDEN)
163                                 results[nn_ress++] = ptr_tp;
164                 } else {
165                         /* scalar result */
166                         results[nn_ress++] = res_tp;
167                 }
168         }
169         /* copy over parameter types */
170         for (i = 0; i < n_params; ++i) {
171                 ir_type *param_type = get_method_param_type(mtp, i);
172                 if (! (flags & LF_DONT_LOWER_ARGUMENTS)
173                     && is_compound_type(param_type)) {
174                     /* turn parameter into a pointer type */
175                     param_type = new_type_pointer(param_type);
176                 }
177                 params[nn_params++] = param_type;
178         }
179         assert(nn_ress <= n_ress);
180         assert(nn_params <= n_params + n_ress);
181
182         /* create the new type */
183         lowered = new_d_type_method(nn_params, nn_ress, get_type_dbg_info(mtp));
184
185         /* fill it */
186         for (i = 0; i < nn_params; ++i)
187                 set_method_param_type(lowered, i, params[i]);
188         for (i = 0; i < nn_ress; ++i)
189                 set_method_res_type(lowered, i, results[i]);
190
191         set_method_variadicity(lowered, get_method_variadicity(mtp));
192
193         cconv = get_method_calling_convention(mtp);
194         if (nn_params > n_params) {
195                 cconv |= cc_compound_ret;
196         }
197         set_method_calling_convention(lowered, cconv);
198
199         mtp_properties = get_method_additional_properties(mtp);
200         /* after lowering the call is not const anymore, since it writes to the
201          * memory for the return value passed to it */
202         mtp_properties &= ~mtp_property_const;
203         set_method_additional_properties(lowered, mtp_properties);
204
205         /* associate the lowered type with the original one for easier access */
206         set_higher_type(lowered, mtp);
207         pmap_insert(lowered_mtps, mtp, lowered);
208
209         return lowered;
210 }
211
212 /**
213  * A call list entry.
214  */
215 typedef struct cl_entry cl_entry;
216 struct cl_entry {
217         cl_entry *next;   /**< Pointer to the next entry. */
218         ir_node  *call;   /**< Pointer to the Call node. */
219         ir_node  *copyb;  /**< List of all CopyB nodes. */
220         bool      has_compound_ret   : 1;
221         bool      has_compound_param : 1;
222 };
223
224 /**
225  * Walker environment for fix_args_and_collect_calls().
226  */
227 typedef struct wlk_env_t {
228         size_t               arg_shift;        /**< The Argument index shift for parameters. */
229         struct obstack       obst;             /**< An obstack to allocate the data on. */
230         cl_entry             *cl_list;         /**< The call list. */
231         pmap                 *dummy_map;       /**< A map for finding the dummy arguments. */
232         compound_call_lowering_flags flags;
233         ir_type              *lowered_mtp;     /**< The lowered method type of the current irg if any. */
234         bool                  only_local_mem:1;/**< Set if only local memory access was found. */
235         bool                  changed:1;       /**< Set if the current graph was changed. */
236 } wlk_env;
237
238 /**
239  * Return the call list entry of a call node.
240  * If no entry exists yet, allocate one and enter the node into
241  * the call list of the environment.
242  *
243  * @param call   A Call node.
244  * @param env    The environment.
245  */
246 static cl_entry *get_call_entry(ir_node *call, wlk_env *env)
247 {
248         cl_entry *res = (cl_entry*)get_irn_link(call);
249         if (res == NULL) {
250                 res = OALLOC(&env->obst, cl_entry);
251                 res->next  = env->cl_list;
252                 res->call  = call;
253                 res->copyb = NULL;
254                 set_irn_link(call, res);
255                 env->cl_list = res;
256         }
257         return res;
258 }
259
260 /**
261  * Finds the base address of an address by skipping Sel's and address
262  * calculation.
263  *
264  * @param adr   the address
265  * @param pEnt  points to the base entity if any
266  */
267 static ir_node *find_base_adr(ir_node *ptr, ir_entity **pEnt)
268 {
269         ir_entity *ent = NULL;
270         assert(mode_is_reference(get_irn_mode(ptr)));
271
272         for (;;) {
273                 if (is_Sel(ptr)) {
274                         ent = get_Sel_entity(ptr);
275                         ptr = get_Sel_ptr(ptr);
276                 }
277                 else if (is_Add(ptr)) {
278                         ir_node *left = get_Add_left(ptr);
279                         if (mode_is_reference(get_irn_mode(left)))
280                                 ptr = left;
281                         else
282                                 ptr = get_Add_right(ptr);
283                         ent = NULL;
284                 } else if (is_Sub(ptr)) {
285                         ptr = get_Sub_left(ptr);
286                         ent = NULL;
287                 } else {
288                         *pEnt = ent;
289                         return ptr;
290                 }
291         }
292 }
293
294 /**
295  * Check if a given pointer represents non-local memory.
296  */
297 static void check_ptr(ir_node *ptr, wlk_env *env)
298 {
299         ir_storage_class_class_t sc;
300         ir_entity                *ent;
301
302         /* still alias free */
303         ptr = find_base_adr(ptr, &ent);
304         sc  = get_base_sc(classify_pointer(ptr, ent));
305         if (sc != ir_sc_localvar && sc != ir_sc_malloced) {
306                 /* non-local memory access */
307                 env->only_local_mem = false;
308         }
309 }
310
311 /*
312  * Returns non-zero if a Call is surely a self-recursive Call.
313  * Beware: if this functions returns 0, the call might be self-recursive!
314  */
315 static bool is_self_recursive_Call(const ir_node *call)
316 {
317         const ir_node *callee = get_Call_ptr(call);
318
319         if (is_SymConst_addr_ent(callee)) {
320                 const ir_entity *ent = get_SymConst_entity(callee);
321                 const ir_graph  *irg = get_entity_irg(ent);
322                 if (irg == get_irn_irg(call))
323                         return true;
324         }
325         return false;
326 }
327
328 /**
329  * Post walker: shift all parameter indexes
330  * and collect Calls with compound returns in the call list.
331  * If a non-alias free memory access is found, reset the alias free
332  * flag.
333  */
334 static void fix_args_and_collect_calls(ir_node *n, void *ctx)
335 {
336         wlk_env *env = (wlk_env*)ctx;
337         ir_node *ptr;
338
339         switch (get_irn_opcode(n)) {
340         case iro_Load:
341         case iro_Store:
342                 if (env->only_local_mem) {
343                         ptr = get_irn_n(n, 1);
344                         check_ptr(ptr, env);
345                 }
346                 break;
347         case iro_Proj:
348                 if (env->arg_shift > 0) {
349                         ir_node *pred = get_Proj_pred(n);
350                         ir_graph *irg = get_irn_irg(n);
351
352                         /* Fix the argument numbers */
353                         if (pred == get_irg_args(irg)) {
354                                 long pnr = get_Proj_proj(n);
355                                 set_Proj_proj(n, pnr + env->arg_shift);
356                                 env->changed = true;
357                         }
358                 }
359                 break;
360         case iro_Call: {
361                 ir_type *ctp      = get_Call_type(n);
362                 size_t   n_ress   = get_method_n_ress(ctp);
363                 size_t   n_params = get_method_n_params(ctp);
364                 size_t   i;
365                 if (! is_self_recursive_Call(n)) {
366                         /* any non self recursive call might access global memory */
367                         env->only_local_mem = false;
368                 }
369
370                 /* check for compound returns */
371                 for (i = 0; i < n_ress; ++i) {
372                         ir_type *type = get_method_res_type(ctp, i);
373                         if (is_compound_type(type)) {
374                                 /*
375                                  * This is a call with a compound return. As the result
376                                  * might be ignored, we must put it in the list.
377                                  */
378                                 cl_entry *entry = get_call_entry(n, env);
379                                 entry->has_compound_ret = true;
380                                 break;
381                         }
382                 }
383                 for (i = 0; i < n_params; ++i) {
384                         ir_type *type = get_method_param_type(ctp, i);
385                         if (is_compound_type(type)) {
386                                 cl_entry *entry = get_call_entry(n, env);
387                                 entry->has_compound_param = true;
388                                 break;
389                         }
390                 }
391                 break;
392         }
393         case iro_CopyB: {
394                 ir_node *src = get_CopyB_src(n);
395                 if (env->only_local_mem) {
396                         check_ptr(get_CopyB_src(n), env);
397                         if (env->only_local_mem)
398                                 check_ptr(get_CopyB_dst(n), env);
399                 }
400                 /* check for compound returns */
401                 if (is_Proj(src)) {
402                         ir_node *proj = get_Proj_pred(src);
403                         if (is_Proj(proj) && get_Proj_proj(proj) == pn_Call_T_result) {
404                                 ir_node *call = get_Proj_pred(proj);
405                                 if (is_Call(call)) {
406                                         ir_type *ctp = get_Call_type(call);
407                                         if (is_compound_type(get_method_res_type(ctp, get_Proj_proj(src)))) {
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                         }
415                 }
416                 break;
417         }
418         case iro_Sel: {
419                 ir_entity *entity = get_Sel_entity(n);
420                 ir_type   *type   = get_entity_type(entity);
421
422                 if (is_parameter_entity(entity) && is_compound_type(type)) {
423                         if (! (env->flags & LF_DONT_LOWER_ARGUMENTS)) {
424                                 /* note that num was already modified by fix_parameter_entities
425                                  * so no need to add env->arg_shift again */
426                                 size_t num = get_entity_parameter_number(entity);
427                                 ir_graph *irg  = get_irn_irg(n);
428                                 ir_node  *args = get_irg_args(irg);
429                                 ir_node  *ptr  = new_r_Proj(args, mode_P, num);
430                                 exchange(n, ptr);
431                                 /* hack to avoid us visiting the proj again */
432                                 mark_irn_visited(ptr);
433                         }
434
435                         /* we need to copy compound parameters */
436                         env->only_local_mem = false;
437                 }
438                 break;
439         }
440         default:
441                 /* do nothing */
442                 break;
443         }
444 }
445
446 /**
447  * Returns non-zero if a node is a compound address
448  * of a frame-type entity.
449  *
450  * @param ft   the frame type
451  * @param adr  the node
452  */
453 static bool is_compound_address(ir_type *ft, ir_node *adr)
454 {
455         ir_entity *ent;
456
457         if (! is_Sel(adr))
458                 return false;
459         if (get_Sel_n_indexs(adr) != 0)
460                 return false;
461         ent = get_Sel_entity(adr);
462         return get_entity_owner(ent) == ft;
463 }
464
465 /** A pair for the copy-return-optimization. */
466 typedef struct cr_pair {
467         ir_entity *ent; /**< the entity than can be removed from the frame */
468         ir_node *arg;   /**< the argument that replaces the entities address */
469 } cr_pair;
470
471 /**
472  * Post walker: fixes all entities addresses for the copy-return
473  * optimization.
474  *
475  * Note: We expect the length of the cr_pair array (i.e. number of compound
476  * return values) to be 1 (C, C++) in almost all cases, so ignore the
477  * linear search complexity here.
478  */
479 static void do_copy_return_opt(ir_node *n, void *ctx)
480 {
481         if (is_Sel(n)) {
482                 ir_entity *ent = get_Sel_entity(n);
483                 cr_pair   *arr = (cr_pair*)ctx;
484                 size_t    i, l;
485
486                 for (i = 0, l = ARR_LEN(arr); i < l; ++i) {
487                         if (ent == arr[i].ent) {
488                                 exchange(n, arr[i].arg);
489                                 break;
490                         }
491                 }
492         }
493 }
494
495 /**
496  * Return a Sel node that selects a dummy argument of type tp.
497  * Dummy arguments are only needed once and we use a map
498  * to store them.
499  * We could even assign all dummy arguments the same offset
500  * in the frame type ...
501  *
502  * @param irg    the graph
503  * @param block  the block where a newly create Sel should be placed
504  * @param tp     the type of the dummy entity that should be create
505  * @param env    the environment
506  */
507 static ir_node *get_dummy_sel(ir_graph *irg, ir_node *block, ir_type *tp,
508                               wlk_env *env)
509 {
510         ir_entity *ent;
511         pmap_entry *e;
512
513         /* use a map the check if we already create such an entity */
514         e = pmap_find(env->dummy_map, tp);
515         if (e) {
516                 ent = (ir_entity*)e->value;
517         } else {
518                 ir_type *ft = get_irg_frame_type(irg);
519                 ident   *dummy_id = id_unique("dummy.%u");
520                 ent = new_entity(ft, dummy_id, tp);
521                 pmap_insert(env->dummy_map, tp, ent);
522
523                 if (get_type_state(ft) == layout_fixed) {
524                         /* Fix the layout again */
525                         panic("Fixed layout not implemented");
526                 }
527         }
528         return new_r_simpleSel(block, get_irg_no_mem(irg), get_irg_frame(irg), ent);
529 }
530
531 /**
532  * Add the hidden parameter from the CopyB node to the Call node.
533  */
534 static void add_hidden_param(ir_graph *irg, size_t n_com, ir_node **ins,
535                              cl_entry *entry, wlk_env *env,
536                              ir_type *ctp)
537 {
538         ir_node *p, *n;
539         size_t n_args;
540
541         n_args = 0;
542         for (p = entry->copyb; p; p = n) {
543                 ir_node *src = get_CopyB_src(p);
544                 size_t   idx = get_Proj_proj(src);
545                 n = (ir_node*)get_irn_link(p);
546
547                 /* consider only the first CopyB */
548                 if (ins[idx] == NULL) {
549                         ir_node *block = get_nodes_block(p);
550
551                         /* use the memory output of the call and not the input of the CopyB
552                          * otherwise stuff breaks if the call was mtp_property_const, because
553                          * then the copyb skips the call. But after lowering the call is not
554                          * const anymore, and its memory has to be used */
555                         ir_node *mem = new_r_Proj(entry->call, mode_M, pn_Call_M);
556
557                         ins[idx] = get_CopyB_dst(p);
558
559                         /* get rid of the CopyB */
560                         if (ir_throws_exception(p)) {
561                                 turn_into_tuple(p, pn_CopyB_max+1);
562                                 set_Tuple_pred(p, pn_CopyB_M,         mem);
563                                 set_Tuple_pred(p, pn_CopyB_X_regular, new_r_Jmp(block));
564                                 set_Tuple_pred(p, pn_CopyB_X_except,  new_r_Bad(irg, mode_X));
565                         } else {
566                                 turn_into_tuple(p, pn_CopyB_M+1);
567                                 set_Tuple_pred(p, pn_CopyB_M, mem);
568                         }
569                         ++n_args;
570                 }
571         }
572
573         /* now create dummy entities for function with ignored return value */
574         if (n_args < n_com) {
575                 size_t   i;
576                 size_t   j;
577
578                 for (j = i = 0; i < get_method_n_ress(ctp); ++i) {
579                         ir_type *rtp = get_method_res_type(ctp, i);
580                         if (is_compound_type(rtp)) {
581                                 if (ins[j] == NULL)
582                                         ins[j] = get_dummy_sel(irg, get_nodes_block(entry->call), rtp, env);
583                                 ++j;
584                         }
585                 }
586         }
587 }
588
589 static void fix_compound_ret(wlk_env *env, cl_entry *entry, ir_type *ctp)
590 {
591         ir_node  *call     = entry->call;
592         ir_graph *irg      = get_irn_irg(call);
593         size_t    n_params = get_Call_n_params(call);
594         size_t    n_com    = 0;
595         size_t    n_res    = get_method_n_ress(ctp);
596         size_t    pos      = 0;
597         ir_node **new_in;
598         size_t    i;
599
600         for (i = 0; i < n_res; ++i) {
601                 ir_type *type = get_method_res_type(ctp, i);
602                 if (is_compound_type(type))
603                         ++n_com;
604         }
605
606         new_in = ALLOCANZ(ir_node*, n_params + n_com + (n_Call_max+1));
607         new_in[pos++] = get_Call_mem(call);
608         new_in[pos++] = get_Call_ptr(call);
609         assert(pos == n_Call_max+1);
610         add_hidden_param(irg, n_com, &new_in[pos], entry, env, ctp);
611         pos += n_com;
612
613         /* copy all other parameters */
614         for (i = 0; i < n_params; ++i) {
615                 ir_node *param = get_Call_param(call, i);
616                 new_in[pos++] = param;
617         }
618         assert(pos == n_params+n_com+(n_Call_max+1));
619         set_irn_in(call, pos, new_in);
620 }
621
622 static ir_entity *create_compound_arg_entitiy(ir_graph *irg, ir_type *type)
623 {
624         ir_type   *frame  = get_irg_frame_type(irg);
625         ident     *id     = id_unique("$compound_param.%u");
626         ir_entity *entity = new_entity(frame, id, type);
627         /* TODO:
628          * we could do some optimisations here and create a big union type for all
629          * different call types in a function */
630         return entity;
631 }
632
633 static void fix_compound_params(cl_entry *entry, ir_type *ctp)
634 {
635         ir_node  *call     = entry->call;
636         dbg_info *dbgi     = get_irn_dbg_info(call);
637         ir_node  *mem      = get_Call_mem(call);
638         ir_graph *irg      = get_irn_irg(call);
639         ir_node  *nomem    = new_r_NoMem(irg);
640         ir_node  *frame    = get_irg_frame(irg);
641         size_t    n_params = get_method_n_params(ctp);
642         size_t    i;
643
644         for (i = 0; i < n_params; ++i) {
645                 ir_type   *type = get_method_param_type(ctp, i);
646                 ir_node   *block;
647                 ir_node   *arg;
648                 ir_node   *sel;
649                 ir_node   *copyb;
650                 ir_entity *arg_entity;
651                 if (!is_compound_type(type))
652                         continue;
653
654                 arg        = get_Call_param(call, i);
655                 arg_entity = create_compound_arg_entitiy(irg, type);
656                 block      = get_nodes_block(call);
657                 sel        = new_rd_simpleSel(dbgi, block, nomem, frame, arg_entity);
658                 copyb      = new_rd_CopyB(dbgi, block, mem, sel, arg, type);
659                 mem        = new_r_Proj(copyb, mode_M, pn_CopyB_M);
660                 set_Call_param(call, i, sel);
661         }
662         set_Call_mem(call, mem);
663 }
664
665 static void fix_calls(wlk_env *env)
666 {
667         cl_entry *entry;
668         for (entry = env->cl_list; entry; entry = entry->next) {
669                 ir_node *call        = entry->call;
670                 ir_type *ctp         = get_Call_type(call);
671                 ir_type *lowered_mtp = lower_mtp(env->flags, ctp);
672                 set_Call_type(call, lowered_mtp);
673
674                 if (entry->has_compound_param) {
675                         fix_compound_params(entry, ctp);
676                 }
677                 if (entry->has_compound_ret) {
678                         fix_compound_ret(env, entry, ctp);
679                 }
680         }
681 }
682
683 /**
684  * Transform a graph. If it has compound parameter returns,
685  * remove them and use the hidden parameter instead.
686  * If it calls methods with compound parameter returns, add hidden
687  * parameters.
688  *
689  * @param irg  the graph to transform
690  */
691 static void transform_irg(compound_call_lowering_flags flags, ir_graph *irg)
692 {
693         ir_entity *ent         = get_irg_entity(irg);
694         ir_type   *mtp         = get_entity_type(ent);
695         size_t     n_ress      = get_method_n_ress(mtp);
696         size_t     n_params    = get_method_n_params(mtp);
697         size_t     n_ret_com   = 0;
698         size_t     n_param_com = 0;
699
700         ir_type   *lowered_mtp, *tp, *ft;
701         size_t    i, j, k;
702         size_t    n_cr_opt;
703         ir_node   **new_in, *ret, *endbl, *bl, *mem, *copy;
704         cr_pair   *cr_opt;
705         wlk_env   env;
706
707         /* calculate the number of compound returns */
708         for (n_ret_com = i = 0; i < n_ress; ++i) {
709                 ir_type *type = get_method_res_type(mtp, i);
710                 if (is_compound_type(type))
711                         ++n_ret_com;
712         }
713         for (i = 0; i < n_params; ++i) {
714                 ir_type *type = get_method_param_type(mtp, i);
715                 if (is_compound_type(type))
716                         ++n_param_com;
717         }
718
719         if (n_ret_com > 0)
720                 fix_parameter_entities(irg, n_ret_com);
721
722         if (n_ret_com) {
723                 /* much easier if we have only one return */
724                 normalize_one_return(irg);
725
726                 /* This graph has a compound argument. Create a new type */
727                 lowered_mtp = lower_mtp(flags, mtp);
728                 set_entity_type(ent, lowered_mtp);
729
730                 /* hidden arguments are added first */
731                 env.arg_shift = n_ret_com;
732         } else {
733                 /* we must only search for calls */
734                 env.arg_shift = 0;
735                 lowered_mtp   = NULL;
736         }
737         obstack_init(&env.obst);
738         env.cl_list        = NULL;
739         env.dummy_map      = pmap_create_ex(8);
740         env.flags          = flags;
741         env.lowered_mtp    = lowered_mtp;
742         env.only_local_mem = true;
743         env.changed        = false;
744
745         /* scan the code, fix argument numbers and collect calls. */
746         irg_walk_graph(irg, firm_clear_link, NULL, &env);
747         irg_walk_graph(irg, fix_args_and_collect_calls, NULL, &env);
748
749         if (n_param_com > 0 && !(flags & LF_DONT_LOWER_ARGUMENTS))
750                 remove_compound_param_entities(irg);
751
752         /* fix all calls */
753         if (env.cl_list != NULL) {
754                 fix_calls(&env);
755                 env.changed = true;
756         }
757
758         if (n_ret_com) {
759                 int idx;
760
761                 /* STEP 1: find the return. This is simple, we have normalized the graph. */
762                 endbl = get_irg_end_block(irg);
763                 ret = NULL;
764                 for (idx = get_Block_n_cfgpreds(endbl) - 1; idx >= 0; --idx) {
765                         ir_node *pred = get_Block_cfgpred(endbl, idx);
766
767                         if (is_Return(pred)) {
768                                 ret = pred;
769                                 break;
770                         }
771                 }
772
773                 /* in case of infinite loops, there might be no return */
774                 if (ret != NULL) {
775                         /*
776                          * Now fix the Return node of the current graph.
777                          */
778                         env.changed = true;
779
780                         /*
781                          * STEP 2: fix it. For all compound return values add a CopyB,
782                          * all others are copied.
783                          */
784                         NEW_ARR_A(ir_node *, new_in, n_ress + 1);
785
786                         bl  = get_nodes_block(ret);
787                         mem = get_Return_mem(ret);
788
789                         ft = get_irg_frame_type(irg);
790                         NEW_ARR_A(cr_pair, cr_opt, n_ret_com);
791                         n_cr_opt = 0;
792                         for (j = 1, i = k = 0; i < n_ress; ++i) {
793                                 ir_node *pred = get_Return_res(ret, i);
794                                 tp = get_method_res_type(mtp, i);
795
796                                 if (is_compound_type(tp)) {
797                                         ir_node *arg = get_irg_args(irg);
798                                         arg = new_r_Proj(arg, mode_P_data, k);
799                                         ++k;
800
801                                         if (is_Unknown(pred)) {
802                                                 /* The Return(Unknown) is the Firm construct for a
803                                                  * missing return. Do nothing. */
804                                         } else {
805                                                 /**
806                                                  * Sorrily detecting that copy-return is possible isn't
807                                                  * that simple. We must check, that the hidden address
808                                                  * is alias free during the whole function.
809                                                  * A simple heuristic: all Loads/Stores inside
810                                                  * the function access only local frame.
811                                                  */
812                                                 if (env.only_local_mem && is_compound_address(ft, pred)) {
813                                                         /* we can do the copy-return optimization here */
814                                                         cr_opt[n_cr_opt].ent = get_Sel_entity(pred);
815                                                         cr_opt[n_cr_opt].arg = arg;
816                                                         ++n_cr_opt;
817                                                 } else { /* copy-return optimization is impossible, do the copy. */
818                                                         copy = new_r_CopyB(
819                                                                         bl,
820                                                                         mem,
821                                                                         arg,
822                                                                         pred,
823                                                                         tp
824                                                                         );
825                                                         mem = new_r_Proj(copy, mode_M, pn_CopyB_M);
826                                                 }
827                                         }
828                                         if (flags & LF_RETURN_HIDDEN) {
829                                                 new_in[j] = arg;
830                                                 ++j;
831                                         }
832                                 } else { /* scalar return value */
833                                         new_in[j] = pred;
834                                         ++j;
835                                 }
836                         }
837                         /* replace the in of the Return */
838                         new_in[0] = mem;
839                         set_irn_in(ret, j, new_in);
840
841                         if (n_cr_opt > 0) {
842                                 size_t c;
843                                 size_t n;
844
845                                 irg_walk_graph(irg, NULL, do_copy_return_opt, cr_opt);
846
847                                 for (c = 0, n = ARR_LEN(cr_opt); c < n; ++c) {
848                                         free_entity(cr_opt[c].ent);
849                                 }
850                         }
851                 }
852         }
853
854         pmap_destroy(env.dummy_map);
855         obstack_free(&env.obst, NULL);
856 }
857
858 static void lower_method_types(type_or_ent tore, void *env)
859 {
860         const compound_call_lowering_flags *flags
861                 = (const compound_call_lowering_flags*)env;
862
863         /* fix method entities */
864         if (is_entity(tore.ent)) {
865                 ir_entity *ent     = tore.ent;
866                 ir_type   *tp      = get_entity_type(ent);
867                 ir_type   *lowered = lower_mtp(*flags, tp);
868                 set_entity_type(ent, lowered);
869         } else {
870                 ir_type *tp = tore.typ;
871
872                 /* fix pointer to methods */
873                 if (is_Pointer_type(tp)) {
874                         ir_type *points_to         = get_pointer_points_to_type(tp);
875                         ir_type *lowered_points_to = lower_mtp(*flags, points_to);
876                         set_pointer_points_to_type(tp, lowered_points_to);
877                 }
878         }
879 }
880
881 void lower_calls_with_compounds(compound_call_lowering_flags flags)
882 {
883         size_t i, n;
884
885         pointer_types = pmap_create();
886         lowered_mtps = pmap_create();
887
888         /* first step: Transform all graphs */
889         for (i = 0, n = get_irp_n_irgs(); i < n; ++i) {
890                 ir_graph *irg = get_irp_irg(i);
891                 transform_irg(flags, irg);
892         }
893
894         /* second step: Lower all method types of visible entities */
895         type_walk(NULL, lower_method_types, &flags);
896
897         pmap_destroy(lowered_mtps);
898         pmap_destroy(pointer_types);
899 }