Introduce ia32_Call, which can handle address mode.
authorChristoph Mallon <christoph.mallon@gmx.de>
Wed, 8 Oct 2008 14:06:58 +0000 (14:06 +0000)
committerChristoph Mallon <christoph.mallon@gmx.de>
Wed, 8 Oct 2008 14:06:58 +0000 (14:06 +0000)
[r22609]

ir/be/ia32/bearch_ia32.c
ir/be/ia32/ia32_emitter.c
ir/be/ia32/ia32_new_nodes.c
ir/be/ia32/ia32_new_nodes.h
ir/be/ia32/ia32_nodes_attr.h
ir/be/ia32/ia32_spec.pl
ir/be/ia32/ia32_transform.c
ir/be/ia32/ia32_x87.c

index 7fc5d80..3e6a1f0 100644 (file)
@@ -392,6 +392,9 @@ static void ia32_set_frame_offset(ir_node *irn, int bias)
 
 static int ia32_get_sp_bias(const ir_node *node)
 {
+       if (is_ia32_Call(node))
+               return -(int)get_ia32_call_attr_const(node)->pop;
+
        if (is_ia32_Push(node))
                return 4;
 
@@ -1889,7 +1892,7 @@ static void ia32_get_call_abi(const void *self, ir_type *method_type,
        call_flags.bits.store_args_sequential = 0;
        /* call_flags.bits.try_omit_fp                 not changed: can handle both settings */
        call_flags.bits.fp_free               = 0;  /* the frame pointer is fixed in IA32 */
-       call_flags.bits.call_has_imm          = 1;  /* No call immediates, we handle this by ourselves */
+       call_flags.bits.call_has_imm          = 0;  /* No call immediates, we handle this by ourselves */
 
        /* set parameter passing style */
        be_abi_call_set_flags(abi, call_flags, &ia32_abi_callbacks);
@@ -2088,16 +2091,13 @@ static const be_execution_unit_t ***ia32_get_allowed_execution_units(
 
        if (is_ia32_irn(irn)) {
                ret = get_ia32_exec_units(irn);
-       }
-       else if (is_be_node(irn)) {
-               if (be_is_Call(irn) || be_is_Return(irn)) {
+       } else if (is_be_node(irn)) {
+               if (be_is_Return(irn)) {
                        ret = _units_callret;
-               }
-               else if (be_is_Barrier(irn)) {
+               } else if (be_is_Barrier(irn)) {
                        ret = _units_dummy;
-               }
-               else {
-                        ret = _units_other;
+               } else {
+                       ret = _units_other;
                }
        }
        else {
index 7061a7c..babfd97 100644 (file)
@@ -255,7 +255,52 @@ void ia32_emit_source_register(const ir_node *node, int pos)
        emit_register(reg, NULL);
 }
 
-static void emit_ia32_Immediate(const ir_node *node);
+static void ia32_emit_entity(ir_entity *entity, int no_pic_adjust)
+{
+       ident *id;
+
+       set_entity_backend_marked(entity, 1);
+       id = get_entity_ld_ident(entity);
+       be_emit_ident(id);
+
+       if (get_entity_owner(entity) == get_tls_type()) {
+               if (get_entity_visibility(entity) == visibility_external_allocated) {
+                       be_emit_cstring("@INDNTPOFF");
+               } else {
+                       be_emit_cstring("@NTPOFF");
+               }
+       }
+
+       if (!no_pic_adjust && do_pic) {
+               /* TODO: only do this when necessary */
+               be_emit_char('-');
+               be_emit_string(pic_base_label);
+       }
+}
+
+static void emit_ia32_Immediate_no_prefix(const ir_node *node)
+{
+       const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node);
+
+       if (attr->symconst != NULL) {
+               if (attr->sc_sign)
+                       be_emit_char('-');
+               ia32_emit_entity(attr->symconst, 0);
+       }
+       if (attr->symconst == NULL || attr->offset != 0) {
+               if (attr->symconst != NULL) {
+                       be_emit_irprintf("%+d", attr->offset);
+               } else {
+                       be_emit_irprintf("0x%X", attr->offset);
+               }
+       }
+}
+
+static void emit_ia32_Immediate(const ir_node *node)
+{
+       be_emit_char('$');
+       emit_ia32_Immediate_no_prefix(node);
+}
 
 void ia32_emit_8bit_source_register_or_immediate(const ir_node *node, int pos)
 {
@@ -476,6 +521,11 @@ static void ia32_emit_cmp_suffix(int pnc)
        be_emit_string(str);
 }
 
+typedef enum ia32_emit_mod_t {
+       EMIT_RESPECT_LS   = 1U << 0,
+       EMIT_ALTERNATE_AM = 1U << 1
+} ia32_emit_mod_t;
+
 /**
  * fmt  parameter               output
  * ---- ----------------------  ---------------------------------------------
@@ -495,6 +545,7 @@ static void ia32_emit_cmp_suffix(int pnc)
  *
  * x starts at 0
  * # modifier for %ASx, %D and %S uses ls mode of node to alter register width
+ * * modifier does not prefix immediates with $, but AM with *
  */
 static void ia32_emitf(const ir_node *node, const char *fmt, ...)
 {
@@ -502,8 +553,8 @@ static void ia32_emitf(const ir_node *node, const char *fmt, ...)
        va_start(ap, fmt);
 
        for (;;) {
-               const char    *start = fmt;
-               const ir_mode *mode  = NULL;
+               const char      *start = fmt;
+               ia32_emit_mod_t  mod   = 0;
 
                while (*fmt != '%' && *fmt != '\n' && *fmt != '\0')
                        ++fmt;
@@ -523,8 +574,13 @@ static void ia32_emitf(const ir_node *node, const char *fmt, ...)
                        break;
 
                ++fmt;
+               if (*fmt == '*') {
+                       mod |= EMIT_ALTERNATE_AM;
+                       ++fmt;
+               }
+
                if (*fmt == '#') {
-                       mode = get_ia32_ls_mode(node);
+                       mod |= EMIT_RESPECT_LS;
                        ++fmt;
                }
 
@@ -536,12 +592,16 @@ static void ia32_emitf(const ir_node *node, const char *fmt, ...)
                        case 'A': {
                                switch (*fmt++) {
                                        case 'M':
+                                               if (mod & EMIT_ALTERNATE_AM)
+                                                       be_emit_char('*');
                                                ia32_emit_am(node);
                                                break;
 
                                        case 'R': {
                                                const arch_register_t *reg = va_arg(ap, const arch_register_t*);
                                                if (get_ia32_op_type(node) == ia32_AddrModeS) {
+                                                       if (mod & EMIT_ALTERNATE_AM)
+                                                               be_emit_char('*');
                                                        ia32_emit_am(node);
                                                } else {
                                                        emit_register(reg, NULL);
@@ -551,6 +611,8 @@ static void ia32_emitf(const ir_node *node, const char *fmt, ...)
 
                                        case 'S':
                                                if (get_ia32_op_type(node) == ia32_AddrModeS) {
+                                                       if (mod & EMIT_ALTERNATE_AM)
+                                                               be_emit_char('*');
                                                        ia32_emit_am(node);
                                                        ++fmt;
                                                } else {
@@ -573,12 +635,14 @@ static void ia32_emitf(const ir_node *node, const char *fmt, ...)
 
                                pos = *fmt++ - '0';
                                reg = get_out_reg(node, pos);
-                               emit_register(reg, mode);
+                               emit_register(reg, mod & EMIT_RESPECT_LS ? get_ia32_ls_mode(node) : NULL);
                                break;
                        }
 
                        case 'I':
-                               emit_ia32_Immediate(node);
+                               if (!(mod & EMIT_ALTERNATE_AM))
+                                       be_emit_char('$');
+                               emit_ia32_Immediate_no_prefix(node);
                                break;
 
                        case 'L':
@@ -613,10 +677,12 @@ emit_S:
                                pos = *fmt++ - '0';
                                in  = get_irn_n(node, pos);
                                if (is_ia32_Immediate(in)) {
-                                       emit_ia32_Immediate(in);
+                                       if (!(mod & EMIT_ALTERNATE_AM))
+                                               be_emit_char('$');
+                                       emit_ia32_Immediate_no_prefix(in);
                                } else {
                                        const arch_register_t *reg = get_in_reg(node, pos);
-                                       emit_register(reg, mode);
+                                       emit_register(reg, mod & EMIT_RESPECT_LS ? get_ia32_ls_mode(node) : NULL);
                                }
                                break;
                        }
@@ -698,29 +764,6 @@ void ia32_emit_unop(const ir_node *node, int pos)
        ia32_emitf(node, fmt);
 }
 
-static void ia32_emit_entity(ir_entity *entity, int no_pic_adjust)
-{
-       ident *id;
-
-       set_entity_backend_marked(entity, 1);
-       id = get_entity_ld_ident(entity);
-       be_emit_ident(id);
-
-       if (get_entity_owner(entity) == get_tls_type()) {
-               if (get_entity_visibility(entity) == visibility_external_allocated) {
-                       be_emit_cstring("@INDNTPOFF");
-               } else {
-                       be_emit_cstring("@NTPOFF");
-               }
-       }
-
-       if (!no_pic_adjust && do_pic) {
-               /* TODO: only do this when necessary */
-               be_emit_char('-');
-               be_emit_string(pic_base_label);
-       }
-}
-
 /**
  * Emits address mode.
  */
@@ -1215,25 +1258,6 @@ static void emit_Jmp(const ir_node *node)
        }
 }
 
-static void emit_ia32_Immediate(const ir_node *node)
-{
-       const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node);
-
-       be_emit_char('$');
-       if (attr->symconst != NULL) {
-               if (attr->sc_sign)
-                       be_emit_char('-');
-               ia32_emit_entity(attr->symconst, 0);
-       }
-       if (attr->symconst == NULL || attr->offset != 0) {
-               if (attr->symconst != NULL) {
-                       be_emit_irprintf("%+d", attr->offset);
-               } else {
-                       be_emit_irprintf("0x%X", attr->offset);
-               }
-       }
-}
-
 /**
  * Emit an inline assembler operand.
  *
@@ -1521,6 +1545,16 @@ static void emit_ia32_Conv_I2I(const ir_node *node)
        }
 }
 
+/**
+ * Emits a call
+ */
+static void emit_ia32_Call(const ir_node *node)
+{
+       /* Special case: Call must not have its immediates prefixed by $, instead
+        * address mode is prefixed by *. */
+       ia32_emitf(node, "\tcall %*AS3\n");
+}
+
 
 /*******************************************
  *  _                          _
@@ -1532,24 +1566,6 @@ static void emit_ia32_Conv_I2I(const ir_node *node)
  *
  *******************************************/
 
-/**
- * Emits a backend call
- */
-static void emit_be_Call(const ir_node *node)
-{
-       ir_entity *ent = be_Call_get_entity(node);
-
-       be_emit_cstring("\tcall ");
-       if (ent) {
-               ia32_emit_entity(ent, 1);
-       } else {
-               const arch_register_t *reg = get_in_reg(node, be_pos_Call_ptr);
-               be_emit_char('*');
-               emit_register(reg, NULL);
-       }
-       be_emit_finish_line_gas(node);
-}
-
 /**
  * Emits code to increase stack pointer.
  */
@@ -1795,6 +1811,7 @@ static void ia32_register_emitters(void)
        IA32_EMIT2(Conv_I2I8Bit, Conv_I2I);
        IA32_EMIT(Asm);
        IA32_EMIT(CMov);
+       IA32_EMIT(Call);
        IA32_EMIT(Const);
        IA32_EMIT(Conv_FP2FP);
        IA32_EMIT(Conv_FP2I);
@@ -1810,7 +1827,6 @@ static void ia32_register_emitters(void)
        IA32_EMIT(SwitchJmp);
 
        /* benode emitter */
-       BE_EMIT(Call);
        BE_EMIT(Copy);
        BE_EMIT(CopyKeep);
        BE_EMIT(IncSP);
index 41bf6f9..7ff8c49 100644 (file)
@@ -438,6 +438,22 @@ const ia32_condcode_attr_t *get_ia32_condcode_attr_const(const ir_node *node) {
        return cc_attr;
 }
 
+ia32_call_attr_t *get_ia32_call_attr(ir_node *node)
+{
+       ia32_attr_t      *attr      = get_ia32_attr(node);
+       ia32_call_attr_t *call_attr = CAST_IA32_ATTR(ia32_call_attr_t, attr);
+
+       return call_attr;
+}
+
+const ia32_call_attr_t *get_ia32_call_attr_const(const ir_node *node)
+{
+       const ia32_attr_t      *attr      = get_ia32_attr_const(node);
+       const ia32_call_attr_t *call_attr = CONST_CAST_IA32_ATTR(ia32_call_attr_t, attr);
+
+       return call_attr;
+}
+
 ia32_copyb_attr_t *get_ia32_copyb_attr(ir_node *node) {
        ia32_attr_t       *attr       = get_ia32_attr(node);
        ia32_copyb_attr_t *copyb_attr = CAST_IA32_ATTR(ia32_copyb_attr_t, attr);
@@ -1095,6 +1111,17 @@ init_ia32_immediate_attributes(ir_node *res, ir_entity *symconst,
        attr->offset   = offset;
 }
 
+void init_ia32_call_attributes(ir_node *const res, unsigned const pop, ir_type *const call_tp)
+{
+       ia32_call_attr_t *attr = get_irn_generic_attr(res);
+
+#ifndef NDEBUG
+       attr->attr.attr_type  |= IA32_ATTR_ia32_call_attr_t;
+#endif
+       attr->pop     = pop;
+       attr->call_tp = call_tp;
+}
+
 void
 init_ia32_copyb_attributes(ir_node *res, unsigned size) {
        ia32_copyb_attr_t *attr = get_irn_generic_attr(res);
@@ -1203,6 +1230,26 @@ int ia32_compare_condcode_attr(ir_node *a, ir_node *b)
        return 0;
 }
 
+static int ia32_compare_call_attr(ir_node *a, ir_node *b)
+{
+       const ia32_call_attr_t *attr_a;
+       const ia32_call_attr_t *attr_b;
+
+       if (ia32_compare_nodes_attr(a, b))
+               return 1;
+
+       attr_a = get_ia32_call_attr_const(a);
+       attr_b = get_ia32_call_attr_const(b);
+
+       if (attr_a->pop != attr_b->pop)
+               return 1;
+
+       if (attr_a->call_tp != attr_b->call_tp)
+               return 1;
+
+       return 0;
+}
+
 /** Compare node attributes for CopyB nodes. */
 static
 int ia32_compare_copyb_attr(ir_node *a, ir_node *b)
index 0055775..56fc5ac 100644 (file)
@@ -86,6 +86,12 @@ const ia32_immediate_attr_t *get_ia32_immediate_attr_const(const ir_node *node);
 ia32_condcode_attr_t *get_ia32_condcode_attr(ir_node *node);
 const ia32_condcode_attr_t *get_ia32_condcode_attr_const(const ir_node *node);
 
+/**
+ * Gets the Call node attributes.
+ */
+ia32_call_attr_t *get_ia32_call_attr(ir_node *node);
+const ia32_call_attr_t *get_ia32_call_attr_const(const ir_node *node);
+
 /**
  * Gets the CopyB node attributes.
  */
@@ -454,6 +460,7 @@ void init_ia32_x87_attributes(ir_node *node);
 void init_ia32_asm_attributes(ir_node *node);
 void init_ia32_immediate_attributes(ir_node *node, ir_entity *symconst,
                                     int symconst_sign, long offset);
+void init_ia32_call_attributes(ir_node *res, unsigned pop, ir_type *call_tp);
 void init_ia32_copyb_attributes(ir_node *res, unsigned size);
 void init_ia32_condcode_attributes(ir_node *res, long pnc);
 
index 2f483d1..b12a200 100644 (file)
@@ -82,7 +82,8 @@ typedef enum {
        IA32_ATTR_ia32_asm_attr_t       = 1 << 2,
        IA32_ATTR_ia32_immediate_attr_t = 1 << 3,
        IA32_ATTR_ia32_condcode_attr_t  = 1 << 4,
-       IA32_ATTR_ia32_copyb_attr_t     = 1 << 5
+       IA32_ATTR_ia32_copyb_attr_t     = 1 << 5,
+       IA32_ATTR_ia32_call_attr_t      = 1 << 6
 } ia32_attr_type_t;
 #endif
 
@@ -141,6 +142,16 @@ struct ia32_attr_t {
 };
 COMPILETIME_ASSERT(sizeof(struct ia32_attr_data_bitfield) <= 4, attr_bitfield);
 
+/**
+ * The attributes for a Call node.
+ */
+typedef struct ia32_call_attr_t ia32_call_attr_t;
+struct ia32_call_attr_t {
+       ia32_attr_t  attr;    /**< generic attribute */
+       unsigned     pop;     /**< number of bytes that get popped by the callee */
+       ir_type     *call_tp; /**< The call type, copied from the original Call node. */
+};
+
 /**
  * The attributes for nodes with condition code.
  */
@@ -204,6 +215,7 @@ struct ia32_asm_attr_t {
  * the structs (we use them to simulate OO-inheritance) */
 union allow_casts_attr_t_ {
        ia32_attr_t            attr;
+       ia32_call_attr_t       call_attr;
        ia32_condcode_attr_t   cc_attr;
        ia32_copyb_attr_t      cpy_attr;
        ia32_x87_attr_t        x87_attr;
index 1f34df0..4bbb018 100644 (file)
@@ -279,6 +279,9 @@ $custom_init_attr_func = \&ia32_custom_init_attr;
                "\tinit_ia32_asm_attributes(res);",
        ia32_attr_t     =>
                "\tinit_ia32_attributes(res, flags, in_reqs, out_reqs, exec_units, n_res);",
+       ia32_call_attr_t =>
+               "\tinit_ia32_attributes(res, flags, in_reqs, out_reqs, exec_units, n_res);\n".
+               "\tinit_ia32_call_attributes(res, pop, call_tp);",
        ia32_condcode_attr_t =>
                "\tinit_ia32_attributes(res, flags, in_reqs, out_reqs, exec_units, n_res);\n".
                "\tinit_ia32_condcode_attributes(res, pnc);",
@@ -296,6 +299,7 @@ $custom_init_attr_func = \&ia32_custom_init_attr;
 %compare_attr = (
        ia32_asm_attr_t       => "ia32_compare_asm_attr",
        ia32_attr_t           => "ia32_compare_nodes_attr",
+       ia32_call_attr_t      => "ia32_compare_call_attr",
        ia32_condcode_attr_t  => "ia32_compare_condcode_attr",
        ia32_copyb_attr_t     => "ia32_compare_copyb_attr",
        ia32_immediate_attr_t => "ia32_compare_immediate_attr",
@@ -1460,6 +1464,21 @@ Bt => {
        modified_flags => $status_flags  # only CF is set, but the other flags are undefined
 },
 
+Call => {
+       state     => "exc_pinned",
+       reg_req   => {
+               in  => [ "gp", "gp", "none", "gp", "esp", "fpcw", "eax", "ecx", "edx" ],
+               out => [ "esp", "fpcw", "none", "eax", "ecx", "edx", "vf0", "vf1", "vf2", "vf3", "vf4", "vf5", "vf6", "vf7", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" ]
+       },
+       ins       => [ "base", "index", "mem", "addr", "stack", "fpcw", "eax", "ecx", "edx" ],
+       outs      => [ "stack:I|S", "fpcw:I", "M", "eax", "ecx", "edx", "vf0", "vf1", "vf2", "vf3", "vf4", "vf5", "vf6", "vf7", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" ],
+       attr_type => "ia32_call_attr_t",
+       attr      => "unsigned pop, ir_type *call_tp",
+       am        => "source,unary",
+       units     => [ "BRANCH" ],
+       latency   => 4, # random number
+},
+
 #-----------------------------------------------------------------------------#
 #   _____ _____ ______    __ _             _                     _            #
 #  / ____/ ____|  ____|  / _| |           | |                   | |           #
index cd0ee9c..36a031d 100644 (file)
@@ -4210,14 +4210,30 @@ static ir_node *gen_Proj_Quot(ir_node *node) {
        panic("No idea how to transform proj->Quot");
 }
 
-static ir_node *gen_be_Call(ir_node *node) {
-       ir_node *res = be_duplicate_node(node);
-       ir_type *call_tp;
-
-       be_node_add_flags(res, -1, arch_irn_flags_modify_flags);
+static ir_node *gen_be_Call(ir_node *node)
+{
+       dbg_info       *const dbgi      = get_irn_dbg_info(node);
+       ir_graph       *const irg       = current_ir_graph;
+       ir_node        *const src_block = get_nodes_block(node);
+       ir_node        *const block     = be_transform_node(src_block);
+       ir_node        *const src_mem   = get_irn_n(node, be_pos_Call_mem);
+       ir_node        *const src_sp    = get_irn_n(node, be_pos_Call_sp);
+       ir_node        *const sp        = be_transform_node(src_sp);
+       ir_node        *const src_ptr   = get_irn_n(node, be_pos_Call_ptr);
+       ir_node        *const noreg     = ia32_new_NoReg_gp(env_cg);
+       ia32_address_mode_t   am;
+       ia32_address_t *const addr      = &am.addr;
+       ir_node        *      mem;
+       ir_node        *      call;
+       int                   i;
+       ir_node        *      fpcw;
+       ir_node        *      eax       = noreg;
+       ir_node        *      ecx       = noreg;
+       ir_node        *      edx       = noreg;
+       unsigned        const pop       = be_Call_get_pop(node);
+       ir_type        *const call_tp   = be_Call_get_type(node);
 
        /* Run the x87 simulator if the call returns a float value */
-       call_tp = be_Call_get_type(node);
        if (get_method_n_ress(call_tp) > 0) {
                ir_type *const res_type = get_method_res_type(call_tp, 0);
                ir_mode *const res_mode = get_type_mode(res_type);
@@ -4227,7 +4243,41 @@ static ir_node *gen_be_Call(ir_node *node) {
                }
        }
 
-       return res;
+       /* We do not want be_Call direct calls */
+       assert(be_Call_get_entity(node) == NULL);
+
+       match_arguments(&am, src_block, NULL, src_ptr, src_mem,
+                       match_am | match_immediate);
+
+       i    = get_irn_arity(node) - 1;
+       fpcw = be_transform_node(get_irn_n(node, i--));
+       for (; i >= be_pos_Call_first_arg; --i) {
+               arch_register_req_t const *const req =
+                       arch_get_register_req(env_cg->arch_env, node, i);
+               ir_node *const reg_parm = be_transform_node(get_irn_n(node, i));
+
+               assert(req->type == arch_register_req_type_limited);
+               assert(req->cls == &ia32_reg_classes[CLASS_ia32_gp]);
+
+               switch (*req->limited) {
+                       case 1 << REG_EAX: assert(eax == noreg); eax = reg_parm; break;
+                       case 1 << REG_ECX: assert(ecx == noreg); ecx = reg_parm; break;
+                       case 1 << REG_EDX: assert(edx == noreg); edx = reg_parm; break;
+                       default: panic("Invalid GP register for register parameter");
+               }
+       }
+
+       mem  = transform_AM_mem(irg, block, src_ptr, src_mem, addr->mem);
+       call = new_rd_ia32_Call(dbgi, irg, block, addr->base, addr->index, mem,
+                               am.new_op2, sp, fpcw, eax, ecx, edx, pop, call_tp);
+       set_am_attributes(call, &am);
+       call = fix_mem_proj(call, &am);
+
+       if (get_irn_pinned(node) == op_pin_state_pinned)
+               set_irn_pinned(call, op_pin_state_pinned);
+
+       SET_IA32_ORIG_NODE(call, ia32_get_old_node_name(env_cg, node));
+       return call;
 }
 
 static ir_node *gen_be_IncSP(ir_node *node) {
@@ -4240,7 +4290,8 @@ static ir_node *gen_be_IncSP(ir_node *node) {
 /**
  * Transform the Projs from a be_Call.
  */
-static ir_node *gen_Proj_be_Call(ir_node *node) {
+static ir_node *gen_Proj_be_Call(ir_node *node)
+{
        ir_node  *block       = be_transform_node(get_nodes_block(node));
        ir_node  *call        = get_Proj_pred(node);
        ir_node  *new_call    = be_transform_node(call);
@@ -4252,6 +4303,7 @@ static ir_node *gen_Proj_be_Call(ir_node *node) {
        ir_mode  *mode        = get_irn_mode(node);
        ir_node  *sse_load;
        const arch_register_class_t *cls;
+       ir_node                     *res;
 
        /* The following is kinda tricky: If we're using SSE, then we have to
         * move the result value of the call in floating point registers to an
@@ -4270,9 +4322,9 @@ static ir_node *gen_Proj_be_Call(ir_node *node) {
                        call_res_pred = get_Proj_pred(call_res_new);
                }
 
-               if (call_res_pred == NULL || be_is_Call(call_res_pred)) {
+               if (call_res_pred == NULL || is_ia32_Call(call_res_pred)) {
                        return new_rd_Proj(dbgi, irg, block, new_call, mode_M,
-                                          pn_be_Call_M_regular);
+                                          n_ia32_Call_mem);
                } else {
                        assert(is_ia32_xLoad(call_res_pred));
                        return new_rd_Proj(dbgi, irg, block, call_res_pred, mode_M,
@@ -4319,7 +4371,47 @@ static ir_node *gen_Proj_be_Call(ir_node *node) {
                mode = cls->mode;
        }
 
-       return new_rd_Proj(dbgi, irg, block, new_call, mode, proj);
+       /* Map from be_Call to ia32_Call proj number */
+       if (proj == pn_be_Call_sp) {
+               proj = pn_ia32_Call_stack;
+       } else if (proj == pn_be_Call_M_regular) {
+               proj = pn_ia32_Call_M;
+       } else {
+               arch_register_req_t const *const req    = arch_get_register_req(env_cg->arch_env, node, BE_OUT_POS(proj));
+               int                        const n_outs = get_ia32_n_res(new_call);
+               int                              i;
+
+               assert(proj      >= pn_be_Call_first_res);
+               assert(req->type == arch_register_req_type_limited);
+
+               for (i = 0; i < n_outs; ++i) {
+                       arch_register_req_t const *const new_req = get_ia32_out_req(new_call, i);
+
+                       if (new_req->type     != arch_register_req_type_limited ||
+                           new_req->cls      != req->cls                       ||
+                           *new_req->limited != *req->limited)
+                               continue;
+
+                       proj = i;
+                       break;
+               }
+               assert(i < n_outs);
+       }
+
+       res = new_rd_Proj(dbgi, irg, block, new_call, mode, proj);
+
+       /* TODO arch_set_irn_register() only operates on Projs, need variant with index */
+       switch (proj) {
+               case pn_ia32_Call_stack:
+                       arch_set_irn_register(env_cg->arch_env, res, &ia32_gp_regs[REG_ESP]);
+                       break;
+
+               case pn_ia32_Call_fpcw:
+                       arch_set_irn_register(env_cg->arch_env, res, &ia32_fp_cw_regs[REG_FPCW]);
+                       break;
+       }
+
+       return res;
 }
 
 /**
@@ -4593,11 +4685,16 @@ static void add_missing_keep_walker(ir_node *node, void *data)
        assert(n_outs < (int) sizeof(unsigned) * 8);
        foreach_out_edge(node, edge) {
                ir_node *proj = get_edge_src_irn(edge);
-               int      pn   = get_Proj_proj(proj);
+               int      pn;
+
+               /* The node could be kept */
+               if (is_End(proj))
+                       continue;
 
                if (get_irn_mode(proj) == mode_M)
                        continue;
 
+               pn = get_Proj_proj(proj);
                assert(pn < n_outs);
                found_projs |= 1 << pn;
        }
index 080d331..9a6b1d4 100644 (file)
@@ -1913,7 +1913,7 @@ static ir_node *get_call_result_proj(ir_node *call) {
                ir_node *proj = get_edge_src_irn(edge);
                long pn = get_Proj_proj(proj);
 
-               if (pn == pn_be_Call_first_res) {
+               if (pn == pn_ia32_Call_vf0) {
                        return proj;
                }
        }
@@ -1922,7 +1922,7 @@ static ir_node *get_call_result_proj(ir_node *call) {
 }  /* get_call_result_proj */
 
 /**
- * Simulate a be_Call.
+ * Simulate a ia32_Call.
  *
  * @param state      the x87 state
  * @param n          the node that should be simulated
@@ -1931,7 +1931,7 @@ static ir_node *get_call_result_proj(ir_node *call) {
  */
 static int sim_Call(x87_state *state, ir_node *n)
 {
-       ir_type *call_tp = be_Call_get_type(n);
+       ir_type *call_tp = get_ia32_call_attr_const(n)->call_tp;
        ir_type *res_type;
        ir_mode *mode;
        ir_node *resproj;
@@ -2354,6 +2354,7 @@ static void x87_init_simulator(x87_simulator *sim, ir_graph *irg,
        /* set the generic function pointer of instruction we must simulate */
        clear_irp_opcodes_generic_func();
 
+       register_sim(op_ia32_Call,         sim_Call);
        register_sim(op_ia32_vfld,         sim_fld);
        register_sim(op_ia32_vfild,        sim_fild);
        register_sim(op_ia32_vfld1,        sim_fld1);
@@ -2372,7 +2373,6 @@ static void x87_init_simulator(x87_simulator *sim, ir_graph *irg,
        register_sim(op_ia32_vFucomFnstsw, sim_Fucom);
        register_sim(op_ia32_vFucomi,      sim_Fucom);
        register_sim(op_be_Copy,           sim_Copy);
-       register_sim(op_be_Call,           sim_Call);
        register_sim(op_be_Spill,          sim_Spill);
        register_sim(op_be_Reload,         sim_Reload);
        register_sim(op_be_Return,         sim_Return);