- entity *ent = get_irg_entity(irg);
- ir_type *mtp, *lowered_mtp, *tp, *ft;
- int i, j, k, n_ress = 0, n_ret_com = 0, n_cr_opt;
- ir_node **new_in, *ret, *endbl, *bl, *mem, *copy;
- cr_pair *cr_opt;
- wlk_env env;
- add_hidden hidden_params;
-
- assert(ent && "Cannot tranform graph without an entity");
- assert(get_irg_phase_state(irg) == phase_high && "call lowering must be done in phase high");
-
- mtp = get_entity_type(ent);
-
- if (lp->flags & LF_COMPOUND_RETURN) {
- /* calculate the number of compound returns */
- n_ress = get_method_n_ress(mtp);
- for (n_ret_com = i = 0; i < n_ress; ++i) {
- tp = get_method_res_type(mtp, i);
-
- if (is_compound_type(tp))
- ++n_ret_com;
- }
- }
-
- if (n_ret_com) {
- /* much easier if we have only one return */
- normalize_one_return(irg);
-
- /* This graph has a compound argument. Create a new type */
- lowered_mtp = create_modified_mtd_type(lp, mtp);
- set_entity_type(ent, lowered_mtp);
-
- hidden_params = lp->hidden_params;
- if (hidden_params == ADD_HIDDEN_SMART &&
- get_method_variadicity(mtp) == variadicity_variadic)
- hidden_params = ADD_HIDDEN_ALWAYS_IN_FRONT;
-
- if (hidden_params == ADD_HIDDEN_ALWAYS_IN_FRONT) {
- /* hidden arguments are added first */
- env.arg_shift = n_ret_com;
- env.first_hidden = 0;
- }
- else {
- /* hidden arguments are added last */
- env.arg_shift = 0;
- env.first_hidden = get_method_n_params(mtp);
- }
- }
- else {
- /* we must only search for calls */
- env.arg_shift = 0;
- }
- obstack_init(&env.obst);
- env.cl_list = NULL;
- env.dummy_map = pmap_create_ex(8);
- env.dnr = 0;
- env.params = lp;
-
- /* scan the code, fix argument numbers and collect calls. */
- irg_walk_graph(irg, firm_clear_link, fix_args_and_collect_calls, &env);
-
- /* fix all calls */
- if (env.cl_list)
- fix_call_list(irg, &env);
-
- if (n_ret_com) {
- /*
- * Now fix the Return node of the current graph.
- */
-
- /* STEP 1: find the return. This is simple, we have normalized the graph. */
- endbl = get_irg_end_block(irg);
- ret = NULL;
- for (i = get_Block_n_cfgpreds(endbl) - 1; i >= 0; --i) {
- ir_node *pred = get_Block_cfgpred(endbl, i);
-
- if (is_Return(pred)) {
- ret = pred;
- break;
- }
- }
- /* there should always be a return */
- assert(ret);
-
- /*
- * STEP 2: fix it. For all compound return values add a CopyB,
- * all others are copied.
- */
- NEW_ARR_A(ir_node *, new_in, n_ress + 1);
-
- bl = get_nodes_block(ret);
- mem = get_Return_mem(ret);
-
- ft = get_irg_frame_type(irg);
- NEW_ARR_A(cr_pair, cr_opt, n_ret_com);
- n_cr_opt = 0;
- for (j = 1, i = k = 0; i < n_ress; ++i) {
- ir_node *pred = get_Return_res(ret, i);
- tp = get_method_res_type(mtp, i);
-
- if (is_compound_type(tp)) {
- ir_node *arg = get_irg_args(irg);
- arg = new_r_Proj(irg, get_nodes_block(arg), arg, mode_P_data, env.first_hidden + k);
- ++k;
-
- if (is_compound_address(ft, pred)) {
- /* we can do the copy-return optimization here */
- cr_opt[n_cr_opt].ent = get_Sel_entity(pred);
- cr_opt[n_cr_opt].arg = arg;
- ++n_cr_opt;
- }
- else { /* copy-return optimization is impossible, do the copy. */
- copy = new_r_CopyB(
- irg, bl,
- mem,
- arg,
- pred,
- tp
- );
- mem = new_r_Proj(irg, bl, copy, mode_M, pn_CopyB_M_regular);
- }
- if (lp->flags & LF_RETURN_HIDDEN) {
- new_in[j] = arg;
- ++j;
- }
- }
- else { /* scalar return value */
- new_in[j] = pred;
- ++j;
- }
- }
- /* replace the in of the Return */
- new_in[0] = mem;
- set_irn_in(ret, j, new_in);
-
- if (n_cr_opt > 0) {
- irg_walk_graph(irg, NULL, do_copy_return_opt, cr_opt);
-
- for (i = ARR_LEN(cr_opt) - 1; i >= 0; --i) {
- remove_class_member(ft, cr_opt[i].ent);
- }
- }
- } /* if (n_ret_com) */
-
- pmap_destroy(env.dummy_map);
- obstack_free(&env.obst, NULL);
-}
-
-/**
- * Returns non-zero if the given type is a method
- * type that must be lowered.
- *
- * @param lp lowering parameters
- * @param tp The type.
- */
-static int must_be_lowered(const lower_params_t *lp, ir_type *tp) {
- int i, n_ress;
- ir_type *res_tp;
-
- if (is_Method_type(tp)) {
- if (lp->flags & LF_COMPOUND_RETURN) {
- /* check for compound returns */
- n_ress = get_method_n_ress(tp);
- for (i = 0; i < n_ress; ++i) {
- res_tp = get_method_res_type(tp, i);
-
- if (is_compound_type(res_tp))
- return 1;
- }
- }
- }
- return 0;
+ ir_entity *ent = get_irg_entity(irg);
+ ir_type *mtp = get_entity_type(ent);
+ size_t n_ress = get_method_n_ress(mtp);
+ size_t n_params = get_method_n_params(mtp);
+ size_t n_param_com = 0;
+
+ ir_type *lowered_mtp, *tp, *ft;
+ size_t i, j, k;
+ size_t n_cr_opt;
+ ir_node **new_in, *ret, *endbl, *bl, *mem, *copy;
+ cr_pair *cr_opt;
+ wlk_env env;
+
+ /* calculate the number of compound returns */
+ size_t n_ret_com = 0;
+ for (i = 0; i < n_ress; ++i) {
+ ir_type *type = get_method_res_type(mtp, i);
+ if (needs_lowering(type))
+ ++n_ret_com;
+ }
+ for (i = 0; i < n_params; ++i) {
+ ir_type *type = get_method_param_type(mtp, i);
+ if (needs_lowering(type))
+ ++n_param_com;
+ }
+
+ if (n_ret_com > 0)
+ fix_parameter_entities(irg, n_ret_com);
+
+ if (n_ret_com) {
+ /* much easier if we have only one return */
+ normalize_one_return(irg);
+
+ /* hidden arguments are added first */
+ env.arg_shift = n_ret_com;
+ } else {
+ /* we must only search for calls */
+ env.arg_shift = 0;
+ lowered_mtp = NULL;
+ }
+
+ lowered_mtp = lower_mtp(flags, mtp);
+ set_entity_type(ent, lowered_mtp);
+
+ obstack_init(&env.obst);
+ env.cl_list = NULL;
+ env.flags = flags;
+ env.lowered_mtp = lowered_mtp;
+ env.only_local_mem = true;
+ env.changed = false;
+
+ /* scan the code, fix argument numbers and collect calls. */
+ irg_walk_graph(irg, firm_clear_link, NULL, &env);
+ irg_walk_graph(irg, fix_args_and_collect_calls, NULL, &env);
+
+ if (n_param_com > 0 && !(flags & LF_DONT_LOWER_ARGUMENTS))
+ remove_compound_param_entities(irg);
+
+ /* fix all calls */
+ if (env.cl_list != NULL) {
+ fix_calls(&env);
+ env.changed = true;
+ }
+
+ if (n_ret_com) {
+ int idx;
+
+ /* STEP 1: find the return. This is simple, we have normalized the graph. */
+ endbl = get_irg_end_block(irg);
+ ret = NULL;
+ for (idx = get_Block_n_cfgpreds(endbl) - 1; idx >= 0; --idx) {
+ ir_node *pred = get_Block_cfgpred(endbl, idx);
+
+ if (is_Return(pred)) {
+ ret = pred;
+ break;
+ }
+ }
+
+ /* in case of infinite loops, there might be no return */
+ if (ret != NULL) {
+ /*
+ * Now fix the Return node of the current graph.
+ */
+ env.changed = true;
+
+ /*
+ * STEP 2: fix it. For all compound return values add a CopyB,
+ * all others are copied.
+ */
+ NEW_ARR_A(ir_node *, new_in, n_ress + 1);
+
+ bl = get_nodes_block(ret);
+ mem = get_Return_mem(ret);
+
+ ft = get_irg_frame_type(irg);
+ NEW_ARR_A(cr_pair, cr_opt, n_ret_com);
+ n_cr_opt = 0;
+ for (j = 1, i = k = 0; i < n_ress; ++i) {
+ ir_node *pred = get_Return_res(ret, i);
+ tp = get_method_res_type(mtp, i);
+
+ if (needs_lowering(tp)) {
+ ir_node *arg = get_irg_args(irg);
+ arg = new_r_Proj(arg, mode_P_data, k);
+ ++k;
+
+ if (is_Unknown(pred)) {
+ /* The Return(Unknown) is the Firm construct for a
+ * missing return. Do nothing. */
+ } else {
+ /**
+ * Sorrily detecting that copy-return is possible isn't
+ * that simple. We must check, that the hidden address
+ * is alias free during the whole function.
+ * A simple heuristic: all Loads/Stores inside
+ * the function access only local frame.
+ */
+ if (env.only_local_mem && is_compound_address(ft, pred)) {
+ /* we can do the copy-return optimization here */
+ cr_opt[n_cr_opt].ent = get_Sel_entity(pred);
+ cr_opt[n_cr_opt].arg = arg;
+ ++n_cr_opt;
+ } else { /* copy-return optimization is impossible, do the copy. */
+ copy = new_r_CopyB(
+ bl,
+ mem,
+ arg,
+ pred,
+ tp
+ );
+ mem = new_r_Proj(copy, mode_M, pn_CopyB_M);
+ }
+ }
+ if (flags & LF_RETURN_HIDDEN) {
+ new_in[j] = arg;
+ ++j;
+ }
+ } else { /* scalar return value */
+ new_in[j] = pred;
+ ++j;
+ }
+ }
+ /* replace the in of the Return */
+ new_in[0] = mem;
+ set_irn_in(ret, j, new_in);
+
+ if (n_cr_opt > 0) {
+ size_t c;
+ size_t n;
+
+ irg_walk_graph(irg, NULL, do_copy_return_opt, cr_opt);
+
+ for (c = 0, n = ARR_LEN(cr_opt); c < n; ++c) {
+ free_entity(cr_opt[c].ent);
+ }
+ }
+ }
+ }
+
+ obstack_free(&env.obst, NULL);