begnuas: let user specify elf variants
[libfirm] / ir / lower / lower_calls.c
index 31da624..9e57bef 100644 (file)
@@ -60,6 +60,29 @@ static ir_type *get_pointer_type(ir_type *dest_type)
        return res;
 }
 
+static void fix_parameter_entities(ir_graph *irg, size_t n_compound_ret)
+{
+       ir_type *frame_type = get_irg_frame_type(irg);
+       size_t   n_compound = get_compound_n_members(frame_type);
+       size_t   i;
+
+       if (n_compound_ret == 0)
+               return;
+
+       for (i = 0; i < n_compound; ++i) {
+               ir_entity *member = get_compound_member(frame_type, i);
+               size_t     num;
+               if (!is_parameter_entity(member))
+                       continue;
+
+               /* increase parameter number since we added a new parameter in front */
+               num = get_entity_parameter_number(member);
+               if (num == IR_VA_START_PARAMETER_NUMBER)
+                       continue;
+               set_entity_parameter_number(member, num + n_compound_ret);
+       }
+}
+
 /**
  * Creates a new lowered type for a method type with compound
  * arguments. The new type is associated to the old one and returned.
@@ -75,6 +98,7 @@ static ir_type *lower_mtp(compound_call_lowering_flags flags, ir_type *mtp)
        size_t    nn_ress;
        size_t    nn_params;
        size_t    i;
+       mtp_additional_properties mtp_properties;
 
        if (!is_Method_type(mtp))
                return mtp;
@@ -126,6 +150,7 @@ static ir_type *lower_mtp(compound_call_lowering_flags flags, ir_type *mtp)
 
        /* create the new type */
        lowered = new_d_type_method(nn_params, nn_ress, get_type_dbg_info(mtp));
+       lowered->attr.ma.has_compound_ret_parameter = true;
 
        /* fill it */
        for (i = 0; i < nn_params; ++i)
@@ -135,9 +160,14 @@ static ir_type *lower_mtp(compound_call_lowering_flags flags, ir_type *mtp)
 
        set_method_variadicity(lowered, get_method_variadicity(mtp));
 
-       /* associate the lowered type with the original one for easier access */
        set_method_calling_convention(lowered, get_method_calling_convention(mtp) | cc_compound_ret);
+       mtp_properties = get_method_additional_properties(mtp);
+       /* after lowering the call is not const anymore, since it writes to the
+        * memory for the return value passed to it */
+       mtp_properties &= ~mtp_property_const;
+       set_method_additional_properties(lowered, mtp_properties);
 
+       /* associate the lowered type with the original one for easier access */
        set_lowered_type(mtp, lowered);
        pmap_insert(lowered_mtps, mtp, lowered);
 
@@ -164,7 +194,6 @@ typedef struct wlk_env_t {
        pmap                 *dummy_map;       /**< A map for finding the dummy arguments. */
        compound_call_lowering_flags flags;
        ir_type              *lowered_mtp;     /**< The lowered method type of the current irg if any. */
-       ir_type              *value_params;    /**< The value params type if any. */
        unsigned             only_local_mem:1; /**< Set if only local memory access was found. */
        unsigned             changed:1;        /**< Set if the current graph was changed. */
 } wlk_env;
@@ -272,20 +301,6 @@ static void fix_args_and_collect_calls(ir_node *n, void *ctx)
        ir_node *ptr;
 
        switch (get_irn_opcode(n)) {
-       case iro_Sel:
-               if (env->lowered_mtp != NULL && env->value_params != NULL) {
-                       ir_entity *ent = get_Sel_entity(n);
-
-                       if (get_entity_owner(ent) == env->value_params) {
-                               size_t pos = get_struct_member_index(env->value_params, ent) + env->arg_shift;
-                               ir_entity *new_ent;
-
-                               new_ent = get_method_value_param_ent(env->lowered_mtp, pos);
-                               set_entity_ident(new_ent, get_entity_ident(ent));
-                               set_Sel_entity(n, new_ent);
-                       }
-               }
-               break;
        case iro_Load:
        case iro_Store:
                if (env->only_local_mem) {
@@ -353,6 +368,16 @@ static void fix_args_and_collect_calls(ir_node *n, void *ctx)
                }
                break;
        }
+       case iro_Sel: {
+               ir_entity *ent  = get_Sel_entity(n);
+               ir_type   *type = get_entity_type(ent);
+
+               /* we need to copy compound parameters */
+               if (is_parameter_entity(ent) && is_compound_type(type)) {
+                       env->only_local_mem = 0;
+               }
+               break;
+       }
        default:
                /* do nothing */
                break;
@@ -466,9 +491,14 @@ static void add_hidden_param(ir_graph *irg, size_t n_com, ir_node **ins,
                n = (ir_node*)get_irn_link(p);
 
                ins[idx] = get_CopyB_dst(p);
-               mem      = get_CopyB_mem(p);
                blk      = get_nodes_block(p);
 
+               /* use the memory output of the call and not the input of the CopyB
+                * otherwise stuff breaks if the call was mtp_property_const, because
+                * then the copyb skips the call. But after lowering the call is not
+                * const anymore, and its memory has to be used */
+               mem = new_r_Proj(entry->call, mode_M, pn_Call_M);
+
                /* get rid of the CopyB */
                turn_into_tuple(p, pn_CopyB_max+1);
                set_Tuple_pred(p, pn_CopyB_M,         mem);
@@ -568,6 +598,8 @@ static void transform_irg(compound_call_lowering_flags flags, ir_graph *irg)
                        ++n_ret_com;
        }
 
+       fix_parameter_entities(irg, n_ret_com);
+
        if (n_ret_com) {
                /* much easier if we have only one return */
                normalize_one_return(irg);
@@ -588,7 +620,6 @@ static void transform_irg(compound_call_lowering_flags flags, ir_graph *irg)
        env.dummy_map      = pmap_create_ex(8);
        env.flags          = flags;
        env.lowered_mtp    = lowered_mtp;
-       env.value_params   = get_method_value_param_type(mtp);
        env.only_local_mem = 1;
        env.changed        = 0;