From 93cd212dded0d6c840c3a474ee44f58bf6468838 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Fri, 31 Aug 2007 14:49:22 +0000 Subject: [PATCH] Changed handling of address mode: - Source and Destination address mode are now constructed during the normal transform phase and not as a separate phase - Remove the old ImmOp stuff - introduce 8, 16bit cmps, tests - still some nodes miss SourceAM handling, but generally we should be as good/better than the old code, so I'm comitting now [r15642] --- ir/be/ia32/bearch_ia32.c | 30 +- ir/be/ia32/ia32_emitter.c | 249 +++--- ir/be/ia32/ia32_emitter.h | 2 + ir/be/ia32/ia32_finish.c | 418 +++++---- ir/be/ia32/ia32_fpu.c | 14 +- ir/be/ia32/ia32_new_nodes.c | 259 +----- ir/be/ia32/ia32_new_nodes.h | 75 -- ir/be/ia32/ia32_nodes_attr.h | 39 +- ir/be/ia32/ia32_optimize.c | 1172 +------------------------ ir/be/ia32/ia32_spec.pl | 427 ++++++--- ir/be/ia32/ia32_transform.c | 1599 +++++++++++++++++++--------------- ir/be/ia32/ia32_x87.c | 9 +- 12 files changed, 1618 insertions(+), 2675 deletions(-) diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index c67e02774..fabcfd7c6 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -355,8 +355,6 @@ static void ia32_set_frame_offset(const void *self, ir_node *irn, int bias) { const ia32_irn_ops_t *ops = self; if (get_ia32_frame_ent(irn)) { - ia32_am_flavour_t am_flav; - if (is_ia32_Pop(irn)) { int omit_fp = be_abi_omit_fp(ops->cg->birg->abi); if (omit_fp) { @@ -367,10 +365,6 @@ static void ia32_set_frame_offset(const void *self, ir_node *irn, int bias) { } } - am_flav = get_ia32_am_flavour(irn); - am_flav |= ia32_O; - set_ia32_am_flavour(irn, am_flav); - add_ia32_am_offs_int(irn, bias); } } @@ -613,7 +607,7 @@ static int ia32_get_op_estimated_cost(const void *self, const ir_node *irn) cost += 150; } else if (is_ia32_CopyB_i(irn)) { - int size = get_tarval_long(get_ia32_Immop_tarval(irn)); + int size = get_ia32_pncode(irn); cost = 20 + (int)ceil((4/3) * size); if (ARCH_INTEL(ops->cg->arch)) cost += 150; @@ -666,6 +660,11 @@ static arch_inverse_t *ia32_get_inverse(const void *self, const ir_node *irn, in if (get_ia32_op_type(irn) != ia32_Normal) return NULL; + /* TODO: adjust for new immediates... */ + ir_fprintf(stderr, "TODO: fix get_inverse for new immediates (%+F)\n", + irn); + return NULL; + irg = get_irn_irg(irn); block = get_nodes_block(irn); mode = get_irn_mode(irn); @@ -681,6 +680,7 @@ static arch_inverse_t *ia32_get_inverse(const void *self, const ir_node *irn, in switch (get_ia32_irn_opcode(irn)) { case iro_ia32_Add: +#if 0 if (get_ia32_immop_type(irn) == ia32_ImmConst) { /* we have an add with a const here */ /* invers == add with negated const */ @@ -702,8 +702,10 @@ static arch_inverse_t *ia32_get_inverse(const void *self, const ir_node *irn, in inverse->nodes[0] = new_rd_ia32_Sub(dbg, irg, block, noreg, noreg, (ir_node*) irn, get_irn_n(irn, i ^ 1), nomem); inverse->costs += 2; } +#endif break; case iro_ia32_Sub: +#if 0 if (get_ia32_immop_type(irn) != ia32_ImmNone) { /* we have a sub with a const/symconst here */ /* invers == add with this const */ @@ -721,8 +723,10 @@ static arch_inverse_t *ia32_get_inverse(const void *self, const ir_node *irn, in } inverse->costs += 1; } +#endif break; case iro_ia32_Xor: +#if 0 if (get_ia32_immop_type(irn) != ia32_ImmNone) { /* xor with const: inverse = xor */ inverse->nodes[0] = new_rd_ia32_Xor(dbg, irg, block, noreg, noreg, get_irn_n(irn, i), noreg, nomem); @@ -734,14 +738,15 @@ static arch_inverse_t *ia32_get_inverse(const void *self, const ir_node *irn, in inverse->nodes[0] = new_rd_ia32_Xor(dbg, irg, block, noreg, noreg, (ir_node *) irn, get_irn_n(irn, i), nomem); inverse->costs += 1; } +#endif break; case iro_ia32_Not: { - inverse->nodes[0] = new_rd_ia32_Not(dbg, irg, block, noreg, noreg, (ir_node*) irn, nomem); + inverse->nodes[0] = new_rd_ia32_Not(dbg, irg, block, (ir_node*) irn); inverse->costs += 1; break; } case iro_ia32_Neg: { - inverse->nodes[0] = new_rd_ia32_Neg(dbg, irg, block, noreg, noreg, (ir_node*) irn, nomem); + inverse->nodes[0] = new_rd_ia32_Neg(dbg, irg, block, (ir_node*) irn); inverse->costs += 1; break; } @@ -834,7 +839,6 @@ static void ia32_perform_memory_operand(const void *self, ir_node *irn, } set_ia32_op_type(irn, ia32_AddrModeS); - set_ia32_am_flavour(irn, ia32_B); set_ia32_ls_mode(irn, get_irn_mode(get_irn_n(irn, i))); set_ia32_use_frame(irn); set_ia32_need_stackent(irn); @@ -972,7 +976,7 @@ static void transform_to_Load(ia32_code_gen_t *cg, ir_node *node) { if (mode_is_float(spillmode)) { if (USE_SSE2(cg)) - new_op = new_rd_ia32_xLoad(dbg, irg, block, ptr, noreg, mem); + new_op = new_rd_ia32_xLoad(dbg, irg, block, ptr, noreg, mem, spillmode); else new_op = new_rd_ia32_vfld(dbg, irg, block, ptr, noreg, mem, spillmode); } @@ -984,7 +988,6 @@ static void transform_to_Load(ia32_code_gen_t *cg, ir_node *node) { new_op = new_rd_ia32_Load(dbg, irg, block, ptr, noreg, mem); set_ia32_op_type(new_op, ia32_AddrModeS); - set_ia32_am_flavour(new_op, ia32_B); set_ia32_ls_mode(new_op, spillmode); set_ia32_frame_ent(new_op, ent); set_ia32_use_frame(new_op); @@ -1055,7 +1058,6 @@ static void transform_to_Store(ia32_code_gen_t *cg, ir_node *node) { } set_ia32_op_type(store, ia32_AddrModeD); - set_ia32_am_flavour(store, ia32_B); set_ia32_ls_mode(store, mode); set_ia32_frame_ent(store, ent); set_ia32_use_frame(store); @@ -1082,7 +1084,6 @@ static ir_node *create_push(ia32_code_gen_t *cg, ir_node *node, ir_node *schedpo set_ia32_frame_ent(push, ent); set_ia32_use_frame(push); set_ia32_op_type(push, ia32_AddrModeS); - set_ia32_am_flavour(push, ia32_B); set_ia32_ls_mode(push, mode_Is); sched_add_before(schedpoint, push); @@ -1101,7 +1102,6 @@ static ir_node *create_pop(ia32_code_gen_t *cg, ir_node *node, ir_node *schedpoi set_ia32_frame_ent(pop, ent); set_ia32_use_frame(pop); set_ia32_op_type(pop, ia32_AddrModeD); - set_ia32_am_flavour(pop, ia32_am_OB); set_ia32_ls_mode(pop, mode_Is); sched_add_before(schedpoint, pop); diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 6785688b7..1cba357bc 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -181,14 +181,19 @@ static int produces_result(const ir_node *node) { return !is_ia32_CmpSet(node) && - !is_ia32_CondJmp(node) && + !is_ia32_CmpSet8Bit(node) && + !is_ia32_CmpJmp(node) && + !is_ia32_CmpJmp8Bit(node) && !is_ia32_St(node) && !is_ia32_SwitchJmp(node) && !is_ia32_TestJmp(node) && + !is_ia32_TestJmp8Bit(node) && !is_ia32_xCmpSet(node) && - !is_ia32_xCondJmp(node) && + !is_ia32_xCmpJmp(node) && !is_ia32_CmpCMov(node) && + !is_ia32_CmpCMov8Bit(node) && !is_ia32_TestCMov(node) && + !is_ia32_TestCMov8Bit(node) && !is_ia32_CmpSet(node) && /* this is correct, the Cmp has no result */ !is_ia32_TestSet(node); } @@ -250,29 +255,6 @@ void ia32_emit_source_register(ia32_emit_env_t *env, const ir_node *node, int po be_emit_string(env, reg_name); } -void ia32_emit_8bit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos) -{ - const arch_register_t *reg = get_in_reg(env, node, pos); - const char *reg_name = arch_register_get_name(reg); - - assert(pos < get_irn_arity(node)); - - be_emit_char(env, '%'); - be_emit_char(env, reg_name[1]); - be_emit_char(env, 'l'); -} - -void ia32_emit_16bit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos) -{ - const arch_register_t *reg = get_in_reg(env, node, pos); - const char *reg_name = arch_register_get_name(reg); - - assert(pos < get_irn_arity(node)); - - be_emit_char(env, '%'); - be_emit_string(env, ®_name[1]); -} - void ia32_emit_dest_register(ia32_emit_env_t *env, const ir_node *node, int pos) { const arch_register_t *reg = get_out_reg(env, node, pos); const char *reg_name = arch_register_get_name(reg); @@ -298,34 +280,6 @@ void ia32_emit_x87_name(ia32_emit_env_t *env, const ir_node *node, int pos) be_emit_string(env, attr->x87[pos]->name); } -void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node) -{ - tarval *tv; - ir_entity *ent; - ident *id; - - be_emit_char(env, '$'); - - switch(get_ia32_immop_type(node)) { - case ia32_ImmConst: - tv = get_ia32_Immop_tarval(node); - be_emit_tarval(env, tv); - return; - case ia32_ImmSymConst: - ent = get_ia32_Immop_symconst(node); - set_entity_backend_marked(ent, 1); - id = get_entity_ld_ident(ent); - be_emit_ident(env, id); - return; - case ia32_ImmNone: - break; - } - - assert(0); - be_emit_string(env, "BAD"); - return; -} - static void ia32_emit_mode_suffix_mode(ia32_emit_env_t *env, const ir_mode *mode) { @@ -431,11 +385,63 @@ void ia32_emit_function_size(ia32_emit_env_t *env, const char *name) static void emit_ia32_Immediate(ia32_emit_env_t *env, const ir_node *node); +void ia32_emit_8bit_source_register(ia32_emit_env_t *env, const ir_node *node, + int pos) +{ + const arch_register_t *reg; + const char *reg_name; + ir_node *in; + + in = get_irn_n(node, pos); + if(is_ia32_Immediate(in)) { + emit_ia32_Immediate(env, in); + return; + } + + reg = get_in_reg(env, node, pos); + reg_name = arch_register_get_name(reg); + + be_emit_char(env, '%'); + be_emit_char(env, reg_name[1]); + be_emit_char(env, 'l'); +} + +void ia32_emit_16bit_source_register(ia32_emit_env_t *env, const ir_node *node, + int pos) +{ + const arch_register_t *reg; + const char *reg_name; + ir_node *in; + + in = get_irn_n(node, pos); + if(is_ia32_Immediate(in)) { + emit_ia32_Immediate(env, in); + return; + } + + reg = get_in_reg(env, node, pos); + reg_name = arch_register_get_name(reg); + + be_emit_char(env, '%'); + be_emit_string(env, ®_name[1]); + be_emit_char(env, 'x'); +} + +void ia32_emit_source_register_or_immediate(ia32_emit_env_t *env, + const ir_node *node, int pos) +{ + ir_node *in = get_irn_n(node, pos); + if(is_ia32_Immediate(in)) { + emit_ia32_Immediate(env, in); + } else { + ia32_emit_source_register(env, node, pos); + } +} + /** * Emits registers and/or address mode of a binary operation. */ void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) { - int right_pos; const ir_node *right_op = get_irn_n(node, 3); switch(get_ia32_op_type(node)) { @@ -445,10 +451,6 @@ void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) { be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 2); break; - } else if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) { - ia32_emit_immediate(env, node); - be_emit_cstring(env, ", "); - ia32_emit_source_register(env, node, 2); } else { const arch_register_t *in1 = get_in_reg(env, node, 2); const arch_register_t *in2 = get_in_reg(env, node, 3); @@ -460,11 +462,6 @@ void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) { out = out ? out : in1; in_name = arch_register_get_name(in); - if (is_ia32_emit_cl(node)) { - assert(in == &ia32_gp_regs[REG_ECX]); - in_name = "cl"; - } - be_emit_char(env, '%'); be_emit_string(env, in_name); be_emit_cstring(env, ", %"); @@ -472,13 +469,7 @@ void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) { } break; case ia32_AddrModeS: - if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) { - assert(!produces_result(node) && - "Source AM with Const must not produce result"); - ia32_emit_immediate(env, node); - be_emit_cstring(env, ", "); - ia32_emit_am(env, node); - } else if(is_ia32_Immediate(right_op)) { + if(is_ia32_Immediate(right_op)) { assert(!produces_result(node) && "Source AM with Const must not produce result"); @@ -496,34 +487,7 @@ void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) { } break; case ia32_AddrModeD: - right_pos = get_irn_arity(node) >= 5 ? 3 : 2; - right_op = get_irn_n(node, right_pos); - if(is_ia32_Immediate(right_op)) { - emit_ia32_Immediate(env, right_op); - be_emit_cstring(env, ", "); - ia32_emit_am(env, node); - break; - } else if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) { - ia32_emit_immediate(env, node); - be_emit_cstring(env, ", "); - ia32_emit_am(env, node); - } else { - const arch_register_t *in1 = get_in_reg(env, node, right_pos); - ir_mode *mode = get_ia32_ls_mode(node); - const char *in_name; - - in_name = ia32_get_reg_name_for_mode(env, mode, in1); - - if (is_ia32_emit_cl(node)) { - assert(in1 == &ia32_gp_regs[REG_ECX]); - in_name = "cl"; - } - - be_emit_char(env, '%'); - be_emit_string(env, in_name); - be_emit_cstring(env, ", "); - ia32_emit_am(env, node); - } + panic("DestMode can't be output by %%binop anymore"); break; default: assert(0 && "unsupported op type"); @@ -536,10 +500,7 @@ void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) { void ia32_emit_x87_binop(ia32_emit_env_t *env, const ir_node *node) { switch(get_ia32_op_type(node)) { case ia32_Normal: - if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) { - // should not happen... - assert(0); - } else { + { const ia32_x87_attr_t *x87_attr = get_ia32_x87_attr_const(node); const arch_register_t *in1 = x87_attr->x87[0]; const arch_register_t *in2 = x87_attr->x87[1]; @@ -585,8 +546,6 @@ void ia32_emit_unop(ia32_emit_env_t *env, const ir_node *node, int pos) { op = get_irn_n(node, pos); if (is_ia32_Immediate(op)) { emit_ia32_Immediate(env, op); - } else if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) { - ia32_emit_immediate(env, node); } else { ia32_emit_source_register(env, node, pos); } @@ -917,7 +876,7 @@ void CondJmp_emitter(ia32_emit_env_t *env, const ir_node *node) { * Emits code for conditional jump with two variables. */ static -void emit_ia32_CondJmp(ia32_emit_env_t *env, const ir_node *node) { +void emit_ia32_CmpJmp(ia32_emit_env_t *env, const ir_node *node) { CondJmp_emitter(env, node); } @@ -948,7 +907,7 @@ void emit_ia32_TestJmp(ia32_emit_env_t *env, const ir_node *node) { * Emits code for conditional SSE floating point jump with two variables. */ static -void emit_ia32_xCondJmp(ia32_emit_env_t *env, const ir_node *node) { +void emit_ia32_xCmpJmp(ia32_emit_env_t *env, const ir_node *node) { be_emit_cstring(env, "\tucomi"); ia32_emit_xmm_mode_suffix(env, node); be_emit_char(env, ' '); @@ -962,7 +921,7 @@ void emit_ia32_xCondJmp(ia32_emit_env_t *env, const ir_node *node) { * Emits code for conditional x87 floating point jump with two variables. */ static -void emit_ia32_x87CondJmp(ia32_emit_env_t *env, const ir_node *node) { +void emit_ia32_x87CmpJmp(ia32_emit_env_t *env, const ir_node *node) { const ia32_x87_attr_t *x87_attr = get_ia32_x87_attr_const(node); const char *reg = x87_attr->x87[1]->name; long pnc = get_ia32_pncode(node); @@ -1024,10 +983,10 @@ void CMov_emitter(ia32_emit_env_t *env, const ir_node *node) in1 = arch_get_irn_register(env->arch_env, get_irn_n(node, 2)); in2 = arch_get_irn_register(env->arch_env, get_irn_n(node, 3)); } else { - if (is_ia32_CmpCMov(node)) { + if (is_ia32_CmpCMov(node) || is_ia32_CmpCMov8Bit(node)) { be_emit_cstring(env, "\tcmp "); } else { - assert(is_ia32_TestCMov(node)); + assert(is_ia32_TestCMov(node) || is_ia32_TestCMov8Bit(node)); be_emit_cstring(env, "\ttest "); } ia32_emit_binop(env, node); @@ -1103,11 +1062,13 @@ void Set_emitter(ia32_emit_env_t *env, const ir_node *node) ia32_emit_binop(env, node); } else { if (is_ia32_CmpSet(node)) { - be_emit_cstring(env, "\tcmp "); + be_emit_cstring(env, "\tcmp"); } else { assert(is_ia32_TestSet(node)); - be_emit_cstring(env, "\ttest "); + be_emit_cstring(env, "\ttest"); } + ia32_emit_mode_suffix(env, node); + be_emit_char(env, ' '); ia32_emit_binop(env, node); } be_emit_finish_line_gas(env, node); @@ -1595,8 +1556,7 @@ void emit_CopyB_prolog(ia32_emit_env_t *env, int rem) { */ static void emit_ia32_CopyB(ia32_emit_env_t *env, const ir_node *node) { - tarval *tv = get_ia32_Immop_tarval(node); - int rem = get_tarval_long(tv); + int rem = get_ia32_pncode(node); emit_CopyB_prolog(env, rem); @@ -1609,8 +1569,7 @@ void emit_ia32_CopyB(ia32_emit_env_t *env, const ir_node *node) { */ static void emit_ia32_CopyB_i(ia32_emit_env_t *env, const ir_node *node) { - tarval *tv = get_ia32_Immop_tarval(node); - int size = get_tarval_long(tv); + int size = get_ia32_pncode(node); emit_CopyB_prolog(env, size & 0x3); @@ -1928,34 +1887,26 @@ void emit_be_Perm(ia32_emit_env_t *env, const ir_node *node) { */ static void emit_ia32_Const(ia32_emit_env_t *env, const ir_node *node) { - ia32_immop_type_t imm_tp = get_ia32_immop_type(node); + const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node); - if (imm_tp == ia32_ImmSymConst) { - be_emit_cstring(env, "\tmovl "); - ia32_emit_immediate(env, node); + /* a zero? */ + if(attr->symconst == NULL && attr->offset == 0) { + if (env->isa->opt_arch == arch_pentium_4) { + /* P4 prefers sub r, r, others xor r, r */ + be_emit_cstring(env, "\tsubl "); + } else { + be_emit_cstring(env, "\txorl "); + } + ia32_emit_dest_register(env, node, 0); be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); } else { - tarval *tv = get_ia32_Immop_tarval(node); - assert(get_irn_mode(node) == mode_Iu); - /* beware: in some rare cases mode is mode_b which has no tarval_null() */ - if (tarval_is_null(tv)) { - if (env->isa->opt_arch == arch_pentium_4) { - /* P4 prefers sub r, r, others xor r, r */ - be_emit_cstring(env, "\tsubl "); - } else { - be_emit_cstring(env, "\txorl "); - } - ia32_emit_dest_register(env, node, 0); - be_emit_cstring(env, ", "); - ia32_emit_dest_register(env, node, 0); - } else { - be_emit_cstring(env, "\tmovl "); - ia32_emit_immediate(env, node); - be_emit_cstring(env, ", "); - ia32_emit_dest_register(env, node, 0); - } + be_emit_cstring(env, "\tmovl "); + emit_ia32_Immediate(env, node); + be_emit_cstring(env, ", "); + ia32_emit_dest_register(env, node, 0); } + be_emit_finish_line_gas(env, node); } @@ -2016,12 +1967,18 @@ void ia32_register_emitters(void) { /* other ia32 emitter functions */ IA32_EMIT(Asm); - IA32_EMIT(CondJmp); + IA32_EMIT(CmpJmp); + IA32_EMIT2(CmpJmp8Bit, CmpJmp); IA32_EMIT(TestJmp); + IA32_EMIT2(TestJmp8Bit, TestJmp); IA32_EMIT(CmpCMov); + IA32_EMIT2(CmpCMov8Bit, CmpCMov); IA32_EMIT(TestCMov); + IA32_EMIT2(TestCMov8Bit, TestCMov); IA32_EMIT(CmpSet); + IA32_EMIT2(CmpSet8Bit, CmpSet); IA32_EMIT(TestSet); + IA32_EMIT2(TestSet8Bit, TestSet); IA32_EMIT(SwitchJmp); IA32_EMIT(CopyB); IA32_EMIT(CopyB_i); @@ -2035,13 +1992,13 @@ void ia32_register_emitters(void) { IA32_EMIT(xCmp); IA32_EMIT(xCmpSet); IA32_EMIT(xCmpCMov); - IA32_EMIT(xCondJmp); - IA32_EMIT2(fcomJmp, x87CondJmp); - IA32_EMIT2(fcompJmp, x87CondJmp); - IA32_EMIT2(fcomppJmp, x87CondJmp); - IA32_EMIT2(fcomrJmp, x87CondJmp); - IA32_EMIT2(fcomrpJmp, x87CondJmp); - IA32_EMIT2(fcomrppJmp, x87CondJmp); + IA32_EMIT(xCmpJmp); + IA32_EMIT2(fcomJmp, x87CmpJmp); + IA32_EMIT2(fcompJmp, x87CmpJmp); + IA32_EMIT2(fcomppJmp, x87CmpJmp); + IA32_EMIT2(fcomrJmp, x87CmpJmp); + IA32_EMIT2(fcomrpJmp, x87CmpJmp); + IA32_EMIT2(fcomrppJmp, x87CmpJmp); /* benode emitter */ BE_EMIT(Call); diff --git a/ir/be/ia32/ia32_emitter.h b/ir/be/ia32/ia32_emitter.h index c7ca52684..b4ec84176 100644 --- a/ir/be/ia32/ia32_emitter.h +++ b/ir/be/ia32/ia32_emitter.h @@ -48,6 +48,8 @@ void ia32_emit_16bit_source_register(ia32_emit_env_t *env, const ir_node *node, void ia32_emit_dest_register(ia32_emit_env_t *env, const ir_node *node, int pos); void ia32_emit_x87_name(ia32_emit_env_t *env, const ir_node *node, int pos); void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node); +void ia32_emit_source_register_or_immediate(ia32_emit_env_t *env, + const ir_node *node, int pos); void ia32_emit_mode_suffix(ia32_emit_env_t *env, const ir_node *node); void ia32_emit_x87_mode_suffix(ia32_emit_env_t *env, const ir_node *node); void ia32_emit_xmm_mode_suffix(ia32_emit_env_t *env, const ir_node *node); diff --git a/ir/be/ia32/ia32_finish.c b/ir/be/ia32/ia32_finish.c index 976abdd71..923aa064a 100644 --- a/ir/be/ia32/ia32_finish.c +++ b/ir/be/ia32/ia32_finish.c @@ -64,8 +64,11 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg) { const arch_register_t *in1_reg, *in2_reg, *out_reg, **slots; int i, arity; - /* Return if AM node or not a Sub or xSub */ - if (!(is_ia32_Sub(irn) || is_ia32_xSub(irn)) || get_ia32_op_type(irn) != ia32_Normal) + /* Return if not a Sub or xSub */ + if (!is_ia32_Sub(irn) && !is_ia32_xSub(irn)) + return; + /* fix_am will solve this for AddressMode variants */ + if(get_ia32_op_type(irn) != ia32_Normal) return; noreg = ia32_new_NoReg_gp(cg); @@ -77,6 +80,8 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg) { in2_reg = arch_get_irn_register(cg->arch_env, in2); out_reg = get_ia32_out_reg(irn, 0); + assert(get_irn_mode(irn) != mode_T); + irg = cg->irg; block = get_nodes_block(irn); @@ -96,7 +101,7 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg) { set_ia32_op_type(res, ia32_AddrModeS); set_ia32_ls_mode(res, get_ia32_ls_mode(irn)); } else { - res = new_rd_ia32_Neg(dbg, irg, block, noreg, noreg, in2, nomem); + res = new_rd_ia32_Neg(dbg, irg, block, in2); } arch_set_irn_register(cg->arch_env, res, in2_reg); @@ -108,8 +113,7 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg) { res = new_rd_ia32_xAdd(dbg, irg, block, noreg, noreg, res, in1, nomem); set_ia32_am_support(res, ia32_am_Source, ia32_am_binary); set_ia32_ls_mode(res, get_ia32_ls_mode(irn)); - } - else { + } else { res = new_rd_ia32_Add(dbg, irg, block, noreg, noreg, res, in1, nomem); set_ia32_am_support(res, ia32_am_Full, ia32_am_binary); set_ia32_commutative(res); @@ -136,122 +140,181 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg) { DBG_OPT_SUB2NEGADD(irn, res); } +static INLINE int is_noreg(ia32_code_gen_t *cg, const ir_node *node) +{ + return node == cg->noreg_gp; +} + +static ir_node *create_immediate_from_int(ia32_code_gen_t *cg, int val) +{ + ir_graph *irg = current_ir_graph; + ir_node *start_block = get_irg_start_block(irg); + ir_node *immediate = new_rd_ia32_Immediate(NULL, irg, start_block, NULL, + 0, val); + arch_set_irn_register(cg->arch_env, immediate, &ia32_gp_regs[REG_GP_NOREG]); + + return immediate; +} + +static ir_node *create_immediate_from_am(ia32_code_gen_t *cg, + const ir_node *node) +{ + ir_graph *irg = get_irn_irg(node); + ir_node *block = get_nodes_block(node); + int offset = get_ia32_am_offs_int(node); + int sc_sign = is_ia32_am_sc_sign(node); + ir_entity *entity = get_ia32_am_sc(node); + ir_node *res; + + res = new_rd_ia32_Immediate(NULL, irg, block, entity, sc_sign, offset); + arch_set_irn_register(cg->arch_env, res, &ia32_gp_regs[REG_GP_NOREG]); + return res; +} + /** * Transforms a LEA into an Add or SHL if possible. * THIS FUNCTIONS MUST BE CALLED AFTER REGISTER ALLOCATION. */ -static void ia32_transform_lea_to_add_or_shl(ir_node *irn, ia32_code_gen_t *cg) { - ia32_am_flavour_t am_flav; - dbg_info *dbg = get_irn_dbg_info(irn); - ir_graph *irg; - ir_node *res = NULL; - ir_node *nomem, *noreg, *base, *index, *op1, *op2; - ir_node *block; - long offs = 0; - const arch_register_t *out_reg, *base_reg, *index_reg; - - /* must be a LEA */ - if (! is_ia32_Lea(irn)) - return; - - am_flav = get_ia32_am_flavour(irn); - - /* mustn't have a symconst */ - if (get_ia32_am_sc(irn) != NULL || get_ia32_frame_ent(irn) != NULL) +static void ia32_transform_lea_to_add_or_shl(ir_node *node, ia32_code_gen_t *cg) +{ + const arch_env_t *arch_env = cg->arch_env; + ir_graph *irg = current_ir_graph; + ir_node *base; + ir_node *index; + const arch_register_t *base_reg; + const arch_register_t *index_reg; + const arch_register_t *out_reg; + int scale; + int has_immediates; + ir_node *op1; + ir_node *op2; + dbg_info *dbgi; + ir_node *block; + ir_node *res; + ir_node *noreg; + ir_node *nomem; + + if(!is_ia32_Lea(node)) return; - if (am_flav == ia32_am_IS) { - tarval *tv; - - /* Create a SHL */ - noreg = ia32_new_NoReg_gp(cg); - nomem = new_rd_NoMem(cg->irg); - index = get_irn_n(irn, 1); - index_reg = arch_get_irn_register(cg->arch_env, index); - out_reg = arch_get_irn_register(cg->arch_env, irn); + base = get_irn_n(node, n_ia32_Lea_base); + index = get_irn_n(node, n_ia32_Lea_index); - if (out_reg != index_reg) - return; + if(is_noreg(cg, base)) { + base = NULL; + base_reg = NULL; + } else { + base_reg = arch_get_irn_register(arch_env, base); + } + if(is_noreg(cg, index)) { + index = NULL; + index_reg = NULL; + } else { + index_reg = arch_get_irn_register(arch_env, index); + } - /* ok, we can transform it */ - irg = cg->irg; - block = get_nodes_block(irn); + if(base == NULL && index == NULL) { + /* we shouldn't construct these in the first place... */ +#ifdef DEBUG_libfirm + ir_fprintf(stderr, "Optimisation warning: found immediate only lea\n"); +#endif + return; + } - res = new_rd_ia32_Shl(dbg, irg, block, noreg, noreg, index, noreg, nomem); - offs = get_ia32_am_scale(irn); - tv = new_tarval_from_long(offs, mode_Iu); - set_ia32_Immop_tarval(res, tv); - arch_set_irn_register(cg->arch_env, res, out_reg); + out_reg = arch_get_irn_register(arch_env, node); + scale = get_ia32_am_scale(node); + assert(!is_ia32_need_stackent(node) || get_ia32_frame_ent(node) != NULL); + /* check if we have immediates values (frame entities should already be + * expressed in the offsets) */ + if(get_ia32_am_offs_int(node) != 0 || get_ia32_am_sc(node) != NULL) { + has_immediates = 1; } else { - /* only some LEAs can be transformed to an Add */ - if (am_flav != ia32_am_B && am_flav != ia32_am_OB && am_flav != ia32_am_BI) - return; - - noreg = ia32_new_NoReg_gp(cg); - nomem = new_rd_NoMem(cg->irg); - op1 = noreg; - op2 = noreg; - base = get_irn_n(irn, 0); - index = get_irn_n(irn, 1); - offs = get_ia32_am_offs_int(irn); - - out_reg = arch_get_irn_register(cg->arch_env, irn); - base_reg = arch_get_irn_register(cg->arch_env, base); - index_reg = arch_get_irn_register(cg->arch_env, index); - - irg = cg->irg; - block = get_nodes_block(irn); - - switch(am_flav) { - case ia32_am_B: - case ia32_am_OB: - /* out register must be same as base register */ - if (out_reg != base_reg) - return; - - op1 = base; - op2 = new_rd_ia32_Immediate(NULL, irg, block, NULL, 0, offs); - arch_set_irn_register(cg->arch_env, op2, - &ia32_gp_regs[REG_GP_NOREG]); - break; - case ia32_am_BI: - assert(offs == 0); - /* out register must be same as one in register */ - if (out_reg == base_reg) { - op1 = base; - op2 = index; - } else if (out_reg == index_reg) { - op1 = index; - op2 = base; - } else { - /* in registers a different from out -> no Add possible */ - return; - } - break; + has_immediates = 0; + } - default: - assert(0); - break; + /* we can transform leas where the out register is the same as either the + * base or index register back to an Add or Shl */ + if(out_reg == base_reg) { + if(index == NULL) { +#ifdef DEBUG_libfirm + if(!has_immediates) { + ir_fprintf(stderr, "Optimisation warning: found lea which is " + "just a copy\n"); + } +#endif + op1 = base; + op2 = create_immediate_from_am(cg, node); + goto make_add; } - - res = new_rd_ia32_Add(dbg, irg, block, noreg, noreg, op1, op2, nomem); - arch_set_irn_register(cg->arch_env, res, out_reg); - set_ia32_op_type(res, ia32_Normal); - set_ia32_commutative(res); + if(scale == 0 && !has_immediates) { + op1 = base; + op2 = index; + goto make_add; + } + /* can't create an add */ + return; + } else if(out_reg == index_reg) { + if(base == NULL) { + if(has_immediates && scale == 0) { + op1 = index; + op2 = create_immediate_from_am(cg, node); + goto make_add; + } else if(!has_immediates && scale > 0) { + op1 = index; + op2 = create_immediate_from_int(cg, scale); + goto make_shl; + } else if(!has_immediates) { +#ifdef DEBUG_libfirm + ir_fprintf(stderr, "Optimisation warning: found lea which is " + "just a copy\n"); +#endif + } + } else if(scale == 0 && !has_immediates) { + op1 = index; + op2 = base; + goto make_add; + } + /* can't create an add */ + return; + } else { + /* can't create an add */ + return; } - SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(cg, irn)); +make_add: + dbgi = get_irn_dbg_info(node); + block = get_nodes_block(node); + noreg = ia32_new_NoReg_gp(cg); + nomem = new_NoMem(); + res = new_rd_ia32_Add(dbgi, irg, block, noreg, noreg, op1, op2, nomem); + arch_set_irn_register(arch_env, res, out_reg); + set_ia32_op_type(res, ia32_Normal); + set_ia32_commutative(res); + goto exchange; + +make_shl: + dbgi = get_irn_dbg_info(node); + block = get_nodes_block(node); + noreg = ia32_new_NoReg_gp(cg); + nomem = new_NoMem(); + res = new_rd_ia32_Shl(dbgi, irg, block, op1, op2); + arch_set_irn_register(arch_env, res, out_reg); + set_ia32_op_type(res, ia32_Normal); + goto exchange; + +exchange: + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(cg, node)); /* add new ADD/SHL to schedule */ - sched_add_before(irn, res); + sched_add_before(node, res); - DBG_OPT_LEA2ADD(irn, res); + DBG_OPT_LEA2ADD(node, res); /* remove the old LEA */ - sched_remove(irn); + sched_remove(node); /* exchange the Add and the LEA */ - exchange(irn, res); + exchange(node, res); } static INLINE int need_constraint_copy(ir_node *irn) { @@ -442,11 +505,15 @@ static void assure_should_be_same_requirements(ia32_code_gen_t *cg, * Solution: Turn back this address mode into explicit Load + Operation. */ static void fix_am_source(ir_node *irn, void *env) { - ia32_code_gen_t *cg = env; - ir_node *base, *index, *noreg; - const arch_register_t *reg_base, *reg_index; + ia32_code_gen_t *cg = env; + const arch_env_t *arch_env = cg->arch_env; + ir_node *base; + ir_node *index; + ir_node *noreg; + const arch_register_t *reg_base; + const arch_register_t *reg_index; const arch_register_req_t **reqs; - int n_res, i; + int n_res, i; /* check only ia32 nodes with source address mode */ if (! is_ia32_irn(irn) || get_ia32_op_type(irn) != ia32_AddrModeS) @@ -458,8 +525,8 @@ static void fix_am_source(ir_node *irn, void *env) { base = get_irn_n(irn, 0); index = get_irn_n(irn, 1); - reg_base = arch_get_irn_register(cg->arch_env, base); - reg_index = arch_get_irn_register(cg->arch_env, index); + reg_base = arch_get_irn_register(arch_env, base); + reg_index = arch_get_irn_register(arch_env, index); reqs = get_ia32_out_req_all(irn); noreg = ia32_new_NoReg_gp(cg); @@ -469,69 +536,90 @@ static void fix_am_source(ir_node *irn, void *env) { for (i = 0; i < n_res; i++) { if (arch_register_req_is(reqs[i], should_be_same)) { /* get in and out register */ - const arch_register_t *out_reg = get_ia32_out_reg(irn, i); - int same_pos = reqs[i]->other_same; - - /* - there is a constraint for the remaining operand - and the result register is equal to base or index register - */ - if (same_pos == 2 && - (out_reg == reg_base || out_reg == reg_index)) - { - /* turn back address mode */ - ir_node *in_node = get_irn_n(irn, 2); - const arch_register_t *in_reg = arch_get_irn_register(cg->arch_env, in_node); - ir_node *block = get_nodes_block(irn); - ir_mode *ls_mode = get_ia32_ls_mode(irn); - ir_node *load; - int pnres; - - if (arch_register_get_class(in_reg) == &ia32_reg_classes[CLASS_ia32_gp]) { - load = new_rd_ia32_Load(NULL, cg->irg, block, base, index, get_irn_n(irn, 4)); - pnres = pn_ia32_Load_res; - } - else if (arch_register_get_class(in_reg) == &ia32_reg_classes[CLASS_ia32_xmm]) { - load = new_rd_ia32_xLoad(NULL, cg->irg, block, base, index, get_irn_n(irn, 4)); - pnres = pn_ia32_xLoad_res; - } - else { - panic("cannot turn back address mode for this register class"); - } - - /* copy address mode information to load */ - set_ia32_ls_mode(load, ls_mode); - set_ia32_am_flavour(load, get_ia32_am_flavour(irn)); - set_ia32_op_type(load, ia32_AddrModeS); - set_ia32_am_scale(load, get_ia32_am_scale(irn)); - set_ia32_am_sc(load, get_ia32_am_sc(irn)); - add_ia32_am_offs_int(load, get_ia32_am_offs_int(irn)); - set_ia32_frame_ent(load, get_ia32_frame_ent(irn)); - - if (is_ia32_use_frame(irn)) - set_ia32_use_frame(load); - - /* insert the load into schedule */ - sched_add_before(irn, load); - - DBG((dbg, LEVEL_3, "irg %+F: build back AM source for node %+F, inserted load %+F\n", cg->irg, irn, load)); - - load = new_r_Proj(cg->irg, block, load, ls_mode, pnres); - arch_set_irn_register(cg->arch_env, load, out_reg); - - /* insert the load result proj into schedule */ - sched_add_before(irn, load); + const arch_register_t *out_reg = get_ia32_out_reg(irn, i); + int same_pos = reqs[i]->other_same; + ir_node *same_node = get_irn_n(irn, same_pos); + const arch_register_t *same_reg + = arch_get_irn_register(arch_env, same_node); + const arch_register_class_t *same_cls; + ir_graph *irg = cg->irg; + dbg_info *dbgi = get_irn_dbg_info(irn); + ir_node *block = get_nodes_block(irn); + ir_mode *proj_mode; + ir_node *load; + ir_node *load_res; + int pnres; + + /* should_be same constraint is fullfilled, nothing to do */ + if(out_reg == same_reg) + continue; - /* set the new input operand */ - set_irn_n(irn, 3, load); + /* we only need to do something if the out reg is the same as base + or index register */ + if (out_reg != reg_base && out_reg != reg_index) + continue; - /* this is a normal node now */ - set_irn_n(irn, 0, noreg); - set_irn_n(irn, 1, noreg); - set_ia32_op_type(irn, ia32_Normal); + /* turn back address mode */ + same_cls = arch_register_get_class(same_reg); + if (same_cls == &ia32_reg_classes[CLASS_ia32_gp]) { + load = new_rd_ia32_Load(dbgi, irg, block, base, index, + get_irn_n(irn, 4)); + assert(get_irn_mode(get_irn_n(irn,4)) == mode_M); + pnres = pn_ia32_Load_res; + proj_mode = mode_Iu; + } else if (same_cls == &ia32_reg_classes[CLASS_ia32_xmm]) { + load = new_rd_ia32_xLoad(dbgi, irg, block, base, index, + get_irn_n(irn, 4), + get_ia32_ls_mode(irn)); + assert(get_irn_mode(get_irn_n(irn,4)) == mode_M); + pnres = pn_ia32_xLoad_res; + proj_mode = mode_E; + } else { + panic("cannot turn back address mode for this register class"); + } - break; + /* copy address mode information to load */ + set_ia32_ls_mode(load, get_ia32_ls_mode(irn)); + set_ia32_op_type(load, ia32_AddrModeS); + set_ia32_am_scale(load, get_ia32_am_scale(irn)); + set_ia32_am_sc(load, get_ia32_am_sc(irn)); + if(is_ia32_am_sc_sign(irn)) + set_ia32_am_sc_sign(load); + add_ia32_am_offs_int(load, get_ia32_am_offs_int(irn)); + set_ia32_frame_ent(load, get_ia32_frame_ent(irn)); + if (is_ia32_use_frame(irn)) + set_ia32_use_frame(load); + + /* insert the load into schedule */ + sched_add_before(irn, load); + + DBG((dbg, LEVEL_3, "irg %+F: build back AM source for node %+F, inserted load %+F\n", cg->irg, irn, load)); + + load_res = new_r_Proj(cg->irg, block, load, proj_mode, pnres); + arch_set_irn_register(cg->arch_env, load_res, out_reg); + + /* set the new input operand */ + set_irn_n(irn, 3, load_res); + if(get_irn_mode(irn) == mode_T) { + const ir_edge_t *edge, *next; + foreach_out_edge_safe(irn, edge, next) { + ir_node *node = get_edge_src_irn(edge); + int pn = get_Proj_proj(node); + if(pn == 0) { + exchange(node, irn); + } else { + assert(pn == 1); + set_Proj_pred(node, load); + } + } + set_irn_mode(irn, mode_Iu); } + + /* this is a normal node now */ + set_irn_n(irn, 0, noreg); + set_irn_n(irn, 1, noreg); + set_ia32_op_type(irn, ia32_Normal); + break; } } } diff --git a/ir/be/ia32/ia32_fpu.c b/ir/be/ia32/ia32_fpu.c index 68d31612f..50f426d23 100644 --- a/ir/be/ia32/ia32_fpu.c +++ b/ir/be/ia32/ia32_fpu.c @@ -67,7 +67,6 @@ static ir_node *create_fpu_mode_spill(void *env, ir_node *state, int force, spill = new_rd_ia32_FnstCW(NULL, irg, block, frame, noreg, state, nomem); set_ia32_op_type(spill, ia32_AddrModeD); - set_ia32_am_flavour(spill, ia32_B); set_ia32_ls_mode(spill, ia32_reg_classes[CLASS_ia32_fp_cw].mode); set_ia32_use_frame(spill); @@ -91,7 +90,6 @@ static ir_node *create_fpu_mode_reload(void *env, ir_node *state, if(spill != NULL) { reload = new_rd_ia32_FldCW(NULL, irg, block, frame, noreg, spill); set_ia32_op_type(reload, ia32_AddrModeS); - set_ia32_am_flavour(reload, ia32_B); set_ia32_ls_mode(reload, ia32_reg_classes[CLASS_ia32_fp_cw].mode); set_ia32_use_frame(reload); arch_set_irn_register(cg->arch_env, reload, &ia32_fp_cw_regs[REG_FPCW]); @@ -101,19 +99,18 @@ static ir_node *create_fpu_mode_reload(void *env, ir_node *state, ir_mode *lsmode = ia32_reg_classes[CLASS_ia32_fp_cw].mode; ir_node *nomem = new_NoMem(); ir_node *cwstore, *load, *load_res, *or, *store, *fldcw; + ir_node *or_const; assert(last_state != NULL); cwstore = new_rd_ia32_FnstCW(NULL, irg, block, frame, noreg, last_state, nomem); set_ia32_op_type(cwstore, ia32_AddrModeD); - set_ia32_am_flavour(cwstore, ia32_B); set_ia32_ls_mode(cwstore, lsmode); set_ia32_use_frame(cwstore); sched_add_before(before, cwstore); load = new_rd_ia32_Load(NULL, irg, block, frame, noreg, cwstore); set_ia32_op_type(load, ia32_AddrModeS); - set_ia32_am_flavour(load, ia32_B); set_ia32_ls_mode(load, lsmode); set_ia32_use_frame(load); sched_add_before(before, load); @@ -121,21 +118,22 @@ static ir_node *create_fpu_mode_reload(void *env, ir_node *state, load_res = new_r_Proj(irg, block, load, mode_Iu, pn_ia32_Load_res); /* TODO: make the actual mode configurable in ChangeCW... */ - or = new_rd_ia32_Or(NULL, irg, block, noreg, noreg, load_res, noreg, + or_const = new_rd_ia32_Immediate(NULL, irg, get_irg_start_block(irg), + NULL, 0, 3072); + arch_set_irn_register(cg->arch_env, or_const, + &ia32_gp_regs[REG_GP_NOREG]); + or = new_rd_ia32_Or(NULL, irg, block, noreg, noreg, load_res, or_const, nomem); - set_ia32_Immop_tarval(or, new_tarval_from_long(3072, mode_Iu)); sched_add_before(before, or); store = new_rd_ia32_Store(NULL, irg, block, frame, noreg, or, nomem); set_ia32_op_type(store, ia32_AddrModeD); - set_ia32_am_flavour(store, ia32_B); set_ia32_ls_mode(store, lsmode); set_ia32_use_frame(store); sched_add_before(before, store); fldcw = new_rd_ia32_FldCW(NULL, irg, block, frame, noreg, store); set_ia32_op_type(fldcw, ia32_AddrModeS); - set_ia32_am_flavour(fldcw, ia32_B); set_ia32_ls_mode(fldcw, lsmode); set_ia32_use_frame(fldcw); arch_set_irn_register(cg->arch_env, fldcw, &ia32_fp_cw_regs[REG_FPCW]); diff --git a/ir/be/ia32/ia32_new_nodes.c b/ir/be/ia32/ia32_new_nodes.c index 6f31323df..b8702d8e2 100644 --- a/ir/be/ia32/ia32_new_nodes.c +++ b/ir/be/ia32/ia32_new_nodes.c @@ -123,22 +123,15 @@ static void dump_reg_req(FILE *F, ir_node *n, const arch_register_req_t **reqs, static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { ir_mode *mode = NULL; int bad = 0; - int i, n_res, am_flav, flags; + int i, n_res, flags; const arch_register_req_t **reqs; const arch_register_t **slots; switch (reason) { case dump_node_opcode_txt: fprintf(F, "%s", get_irn_opname(n)); - break; - - case dump_node_mode_txt: - if (is_ia32_Ld(n) || is_ia32_St(n)) { - mode = get_ia32_ls_mode(n); - fprintf(F, "[%s]", mode ? get_mode_name(mode) : "?NOMODE?"); - } - if(is_ia32_Immediate(n)) { + if(is_ia32_Immediate(n) || is_ia32_Const(n)) { const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(n); @@ -181,26 +174,18 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { } break; - case dump_node_nodeattr_txt: - if (is_ia32_ImmConst(n) || is_ia32_ImmSymConst(n)) { - if(is_ia32_ImmSymConst(n)) { - ir_entity *ent = get_ia32_Immop_symconst(n); - ident *id = get_entity_ld_ident(ent); - fprintf(F, "[SymC %s]", get_id_str(id)); - } else { - char buf[128]; - tarval *tv = get_ia32_Immop_tarval(n); - - tarval_snprintf(buf, sizeof(buf), tv); - fprintf(F, "[%s]", buf); - } + case dump_node_mode_txt: + if (is_ia32_Ld(n) || is_ia32_St(n)) { + mode = get_ia32_ls_mode(n); + fprintf(F, "[%s]", mode ? get_mode_name(mode) : "?NOMODE?"); } + break; + case dump_node_nodeattr_txt: if (! is_ia32_Lea(n)) { if (is_ia32_AddrModeS(n)) { fprintf(F, "[AM S] "); - } - else if (is_ia32_AddrModeD(n)) { + } else if (is_ia32_AddrModeD(n)) { fprintf(F, "[AM D] "); } } @@ -254,24 +239,6 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { } fprintf(F, "\n"); - /* dump immop type */ - fprintf(F, "immediate = "); - switch (get_ia32_immop_type(n)) { - case ia32_ImmNone: - fprintf(F, "None"); - break; - case ia32_ImmConst: - fprintf(F, "Const"); - break; - case ia32_ImmSymConst: - fprintf(F, "SymConst"); - break; - default: - fprintf(F, "unknown (%d)", get_ia32_immop_type(n)); - break; - } - fprintf(F, "\n"); - /* dump supported am */ fprintf(F, "AM support = "); switch (get_ia32_am_support(n)) { @@ -293,28 +260,6 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { } fprintf(F, "\n"); - /* dump am flavour */ - fprintf(F, "AM flavour ="); - am_flav = get_ia32_am_flavour(n); - if (am_flav == ia32_am_N) { - fprintf(F, " none"); - } - else { - if (am_flav & ia32_O) { - fprintf(F, " O"); - } - if (am_flav & ia32_B) { - fprintf(F, " B"); - } - if (am_flav & ia32_I) { - fprintf(F, " I"); - } - if (am_flav & ia32_S) { - fprintf(F, " S"); - } - } - fprintf(F, " (%d)\n", am_flav); - /* dump AM offset */ if(get_ia32_am_offs_int(n) != 0) { fprintf(F, "AM offset = %d\n", get_ia32_am_offs_int(n)); @@ -353,9 +298,6 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { /* commutative */ fprintf(F, "commutative = %d\n", is_ia32_commutative(n)); - /* emit cl */ - fprintf(F, "emit cl instead of ecx = %d\n", is_ia32_emit_cl(n)); - /* got lea */ fprintf(F, "got loea = %d\n", is_ia32_got_lea(n)); @@ -494,14 +436,6 @@ void set_ia32_op_type(ir_node *node, ia32_op_type_t tp) { attr->data.tp = tp; } -/** - * Gets the immediate op type of an ia32 node. - */ -ia32_immop_type_t get_ia32_immop_type(const ir_node *node) { - const ia32_attr_t *attr = get_ia32_attr_const(node); - return attr->data.imm_tp; -} - /** * Gets the supported address mode of an ia32 node */ @@ -526,23 +460,7 @@ void set_ia32_am_support(ir_node *node, ia32_am_type_t am_tp, assert((am_tp == ia32_am_None && arity == ia32_am_arity_none) || (am_tp != ia32_am_None && - ((arity == ia32_am_unary) || (arity == ia32_am_binary)))); -} - -/** - * Gets the address mode flavour of an ia32 node - */ -ia32_am_flavour_t get_ia32_am_flavour(const ir_node *node) { - const ia32_attr_t *attr = get_ia32_attr_const(node); - return attr->data.am_flavour; -} - -/** - * Sets the address mode flavour of an ia32 node - */ -void set_ia32_am_flavour(ir_node *node, ia32_am_flavour_t am_flavour) { - ia32_attr_t *attr = get_ia32_attr(node); - attr->data.am_flavour = am_flavour; + ((arity == ia32_am_unary) || (arity == ia32_am_binary) || (arity == ia32_am_ternary)))); } /** @@ -622,36 +540,6 @@ void set_ia32_am_scale(ir_node *node, int scale) { attr->data.am_scale = scale; } -/** - * Return the tarval of an immediate operation or NULL in case of SymConst - */ -tarval *get_ia32_Immop_tarval(const ir_node *node) { - const ia32_attr_t *attr = get_ia32_attr_const(node); - assert(attr->data.imm_tp == ia32_ImmConst); - return attr->cnst_val.tv; -} - -/** - * Sets the attributes of an immediate operation to the specified tarval - */ -void set_ia32_Immop_tarval(ir_node *node, tarval *tv) { - ia32_attr_t *attr = get_ia32_attr(node); - attr->data.imm_tp = ia32_ImmConst; - attr->cnst_val.tv = tv; -} - -void set_ia32_Immop_symconst(ir_node *node, ir_entity *entity) { - ia32_attr_t *attr = get_ia32_attr(node); - attr->data.imm_tp = ia32_ImmSymConst; - attr->cnst_val.sc = entity; -} - -ir_entity *get_ia32_Immop_symconst(const ir_node *node) { - const ia32_attr_t *attr = get_ia32_attr_const(node); - assert(attr->data.imm_tp == ia32_ImmSymConst); - return attr->cnst_val.sc; -} - /** * Sets the uses_frame flag. */ @@ -700,30 +588,6 @@ int is_ia32_commutative(const ir_node *node) { return attr->data.is_commutative; } -/** - * Sets node emit_cl. - */ -void set_ia32_emit_cl(ir_node *node) { - ia32_attr_t *attr = get_ia32_attr(node); - attr->data.emit_cl = 1; -} - -/** - * Clears node emit_cl. - */ -void clear_ia32_emit_cl(ir_node *node) { - ia32_attr_t *attr = get_ia32_attr(node); - attr->data.emit_cl = 0; -} - -/** - * Checks if node needs %cl. - */ -int is_ia32_emit_cl(const ir_node *node) { - const ia32_attr_t *attr = get_ia32_attr_const(node); - return attr->data.emit_cl; -} - /** * Sets node got_lea. */ @@ -1025,71 +889,6 @@ void set_ia32_orig_node(ir_node *node, const char *name) { * |_| ******************************************************************************************************/ -/** - * Copy the attributes from an ia32_Const to an Immop (Add_i, Sub_i, ...) node - */ -void copy_ia32_Immop_attr(ir_node *node, ir_node *from) { - ia32_immop_type_t immop_type = get_ia32_immop_type(from); - - if(immop_type == ia32_ImmConst) { - set_ia32_Immop_tarval(node, get_ia32_Immop_tarval(from)); - } else if(immop_type == ia32_ImmSymConst) { - set_ia32_Immop_symconst(node, get_ia32_Immop_symconst(from)); - } else { - ia32_attr_t *attr = get_ia32_attr(node); - assert(immop_type == ia32_ImmNone); - attr->data.imm_tp = ia32_ImmNone; - } -} - -/** - * Copy the attributes from a Firm Const/SymConst to an ia32_Const - */ -void set_ia32_Const_attr(ir_node *ia32_cnst, ir_node *cnst) { - assert(is_ia32_Cnst(ia32_cnst) && "Need ia32_Const to set Const attr"); - - switch (get_irn_opcode(cnst)) { - case iro_Const: - set_ia32_Const_tarval(ia32_cnst, get_Const_tarval(cnst)); - break; - case iro_SymConst: - assert(get_SymConst_kind(cnst) == symconst_addr_ent); - set_ia32_Immop_symconst(ia32_cnst, get_SymConst_entity(cnst)); - break; - case iro_Unknown: - assert(0 && "Unknown Const NYI"); - break; - default: - assert(0 && "Cannot create ia32_Const for this opcode"); - } -} - -void set_ia32_Const_tarval(ir_node *ia32_cnst, tarval *tv) { -#if 0 - if(mode_is_reference(get_tarval_mode(tv))) { - if(tarval_is_null(tv)) { - tv = get_tarval_null(mode_Iu); - } else { - long val; - /* workaround... */ - if(!tarval_is_long(tv)) - panic("Can't convert reference tarval to mode_Iu at %+F", ia32_cnst); - val = get_tarval_long(tv); - tv = new_tarval_from_long(val, mode_Iu); - } - } else { - tv = tarval_convert_to(tv, mode_Iu); - } -#else - tv = tarval_convert_to(tv, mode_Iu); -#endif - - assert(tv != get_tarval_bad() && tv != get_tarval_undefined() - && tv != NULL); - set_ia32_Immop_tarval(ia32_cnst, tv); -} - - /** * Sets the AddrMode(S|D) attribute */ @@ -1108,22 +907,6 @@ void set_ia32_AddrMode(ir_node *node, char direction) { } } -/** - * Returns whether or not the node is an immediate operation with Const. - */ -int is_ia32_ImmConst(const ir_node *node) { - const ia32_attr_t *attr = get_ia32_attr_const(node); - return (attr->data.imm_tp == ia32_ImmConst); -} - -/** - * Returns whether or not the node is an immediate operation with SymConst. - */ -int is_ia32_ImmSymConst(const ir_node *node) { - const ia32_attr_t *attr = get_ia32_attr_const(node); - return (attr->data.imm_tp == ia32_ImmSymConst); -} - /** * Returns whether or not the node is an AddrModeS node. */ @@ -1164,14 +947,6 @@ int is_ia32_St(const ir_node *node) { op == iro_ia32_fstp; } -/** - * Checks if node is a Const or xConst/vfConst. - */ -int is_ia32_Cnst(const ir_node *node) { - int op = get_ia32_irn_opcode(node); - return op == iro_ia32_Const || op == iro_ia32_xConst || op == iro_ia32_vfConst; -} - /** * Returns the name of the OUT register at position pos. */ @@ -1306,20 +1081,10 @@ ir_node *get_ia32_result_proj(const ir_node *node) /* default compare operation to compare attributes */ int ia32_compare_attr(const ia32_attr_t *a, const ia32_attr_t *b) { - if (a->data.tp != b->data.tp - || a->data.imm_tp != b->data.imm_tp) - return 1; - - if (a->data.imm_tp == ia32_ImmConst - && a->cnst_val.tv != b->cnst_val.tv) - return 1; - - if (a->data.imm_tp == ia32_ImmSymConst - && a->cnst_val.sc != b->cnst_val.sc) + if (a->data.tp != b->data.tp) return 1; - if (a->data.am_flavour != b->data.am_flavour - || a->data.am_scale != b->data.am_scale + if (a->data.am_scale != b->data.am_scale || a->data.am_sc_sign != b->data.am_sc_sign || a->am_offs != b->am_offs || a->am_sc != b->am_sc diff --git a/ir/be/ia32/ia32_new_nodes.h b/ir/be/ia32/ia32_new_nodes.h index db66c25f3..ba7216ae9 100644 --- a/ir/be/ia32/ia32_new_nodes.h +++ b/ir/be/ia32/ia32_new_nodes.h @@ -69,16 +69,6 @@ ia32_op_type_t get_ia32_op_type(const ir_node *node); */ void set_ia32_op_type(ir_node *node, ia32_op_type_t tp); -/** - * Gets the immediate op type of an ia32 node. - */ -ia32_immop_type_t get_ia32_immop_type(const ir_node *node); - -/** - * Sets the immediate op type of an ia32 node. - */ -void set_ia32_immop_type(ir_node *node, ia32_immop_type_t tp); - /** * Gets the supported addrmode of an ia32 node */ @@ -92,16 +82,6 @@ ia32_am_arity_t get_ia32_am_arity(const ir_node *node); void set_ia32_am_support(ir_node *node, ia32_am_type_t am_tp, ia32_am_arity_t am_arity); -/** - * Gets the addrmode flavour of an ia32 node - */ -ia32_am_flavour_t get_ia32_am_flavour(const ir_node *node); - -/** - * Sets the addrmode flavour of an ia32 node - */ -void set_ia32_am_flavour(ir_node *node, ia32_am_flavour_t am_flavour); - /** * Gets the addressmode offset as long. */ @@ -149,26 +129,6 @@ int get_ia32_am_scale(const ir_node *node); */ void set_ia32_am_scale(ir_node *node, int scale); -/** - * Return the tarval of an immediate operation or NULL if none set - */ -tarval *get_ia32_Immop_tarval(const ir_node *node); - -/** - * Return the symconst entity of an immediate operation or NULL if none set - */ -ir_entity* get_ia32_Immop_symconst(const ir_node *node); - -/** - * Sets the attributes of an immediate operation to the specified tarval - */ -void set_ia32_Immop_tarval(ir_node *node, tarval *tv); - -/** - * Sets the attributes of an immediate operation to the specified SymConst - */ -void set_ia32_Immop_symconst(ir_node *node, ir_entity *entity); - /** * Sets the uses_frame flag. */ @@ -199,21 +159,6 @@ void clear_ia32_commutative(ir_node *node); */ int is_ia32_commutative(const ir_node *node); -/** - * Sets node emit_cl. - */ -void set_ia32_emit_cl(ir_node *node); - -/** - * Clears node emit_cl. - */ -void clear_ia32_emit_cl(ir_node *node); - -/** - * Checks if node is commutative. - */ -int is_ia32_emit_cl(const ir_node *node); - /** * Sets node got_lea. */ @@ -427,11 +372,6 @@ void set_ia32_orig_node(ir_node *node, const char *name); */ ident *ia32_get_ent_ident(ir_entity *ent); -/** - * Copy the attributes from Immop to an Immop - */ -void copy_ia32_Immop_attr(ir_node *node, ir_node *src); - /** * Returns the proj of the result value for nodes that have the usual * (res, Mem) result tuple @@ -451,16 +391,6 @@ void set_ia32_Const_tarval(ir_node *node, tarval *tv); */ void set_ia32_AddrMode(ir_node *node, char direction); -/** - * Returns whether or not the node is an immediate operation with Const. - */ -int is_ia32_ImmConst(const ir_node *node); - -/** - * Returns whether or not the node is an immediate operation with SymConst. - */ -int is_ia32_ImmSymConst(const ir_node *node); - /** * Returns whether or not the node is an AddrModeS node. */ @@ -481,11 +411,6 @@ int is_ia32_Ld(const ir_node *node); */ int is_ia32_St(const ir_node *node); -/** - * Checks if node is a Const or fConst. - */ -int is_ia32_Cnst(const ir_node *node); - /** * Swaps left/right input of a node (and adjusts pnc if needed) */ diff --git a/ir/be/ia32/ia32_nodes_attr.h b/ir/be/ia32/ia32_nodes_attr.h index a4a23612b..298ff574d 100644 --- a/ir/be/ia32/ia32_nodes_attr.h +++ b/ir/be/ia32/ia32_nodes_attr.h @@ -42,23 +42,18 @@ typedef enum { ia32_AddrModeS } ia32_op_type_t; -typedef enum { - ia32_ImmNone = 0, - ia32_ImmConst = 1, - ia32_ImmSymConst = 2 -} ia32_immop_type_t; - typedef enum { ia32_am_None = 0, /**<< no addrmode support */ - ia32_am_Dest = 1, /**<< addrmode for destination only */ + ia32_am_Dest = 1, ia32_am_Source = 2, /**<< addrmode for source only */ - ia32_am_Full = 3, /**<< full addmode support */ + ia32_am_Full = 3 } ia32_am_type_t; typedef enum { - ia32_am_arity_none = 0, - ia32_am_unary = 1, - ia32_am_binary = 2, + ia32_am_arity_none = 0, + ia32_am_unary = 1, + ia32_am_binary = 2, + ia32_am_ternary = 3, } ia32_am_arity_t; /** @@ -75,19 +70,6 @@ enum { ia32_S = (1 << 3) /**< S - Scale is set */ }; -/** Possible Address mode types */ -typedef enum { - ia32_am_N = 0, - ia32_am_O = ia32_O, - ia32_am_B = ia32_B, - ia32_am_I = ia32_I, - ia32_am_IS = ia32_I | ia32_S, - ia32_am_BI = ia32_B | ia32_I, - ia32_am_OB = ia32_O | ia32_B, - ia32_am_OIS = ia32_O | ia32_I | ia32_S, - ia32_am_OBIS = ia32_O | ia32_B | ia32_I | ia32_S -} ia32_am_flavour_t; - enum { ia32_pn_Cmp_Unsigned = 0x100 /**< set this flag in a pnc to indicate an unsigned compare operation */ }; @@ -107,10 +89,8 @@ struct ia32_attr_t { except_attr exc; /**< the exception attribute. MUST be the first one. */ struct ia32_attr_data_bitfield { unsigned tp:3; /**< ia32 node type. */ - unsigned imm_tp:2; /**< ia32 immop type. */ unsigned am_support:2; /**< Indicates the address mode type supported by this node. */ unsigned am_arity : 2; - unsigned am_flavour:4; /**< The concrete address mode characteristics. */ unsigned am_scale:2; /**< The address mode scale for index register. */ unsigned am_sc_sign:1; /**< The sign bit of the address mode symconst. */ @@ -123,8 +103,6 @@ struct ia32_attr_t { unsigned is_commutative:1; /**< Indicates whether op is commutative or not. */ - unsigned emit_cl:1; /**< Indicates whether we must emit cl instead of ecx (needed for shifts). */ - unsigned got_lea:1; /**< Indicates whether or not this node already consumed a LEA. */ unsigned need_stackent:1; /**< Set to 1 if node need space on stack. */ @@ -137,11 +115,6 @@ struct ia32_attr_t { int am_offs; /**< offsets for AddrMode */ ir_entity *am_sc; /**< SymConst for AddrMode */ - union { - tarval *tv; /**< tarval for immediate operations */ - ir_entity *sc; /**< the symconst ident */ - } cnst_val; - ir_mode *ls_mode; /**< Load/Store mode: This is the mode of the value that is manipulated by this node. */ diff --git a/ir/be/ia32/ia32_optimize.c b/ir/be/ia32/ia32_optimize.c index 529ca5d80..dba40d949 100644 --- a/ir/be/ia32/ia32_optimize.c +++ b/ir/be/ia32/ia32_optimize.c @@ -20,7 +20,7 @@ /** * @file * @brief Implements several optimizations for IA32. - * @author Christian Wuerdig + * @author Matthias Braun, Christian Wuerdig * @version $Id$ */ #ifdef HAVE_CONFIG_H @@ -53,15 +53,6 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;) -//#define AGGRESSIVE_AM - -typedef enum { - IA32_AM_CAND_NONE = 0, /**< no addressmode possible with irn inputs */ - IA32_AM_CAND_LEFT = 1, /**< addressmode possible with left input */ - IA32_AM_CAND_RIGHT = 2, /**< addressmode possible with right input */ - IA32_AM_CAND_BOTH = 3 /**< addressmode possible with both inputs */ -} ia32_am_cand_t; - typedef int is_op_func_t(const ir_node *n); typedef ir_node *load_func_t(dbg_info *db, ir_graph *irg, ir_node *block, ir_node *base, ir_node *index, ir_node *mem); @@ -135,7 +126,9 @@ static void ia32_create_Pushs(ir_node *irn, ia32_code_gen_t *cg) { continue; } - if( (get_ia32_am_flavour(node) & ia32_am_IS) != 0) + /* unfortunately we can't support the full AMs possible for push at the + * moment. TODO: fix this */ + if(get_ia32_am_scale(node) > 0 || !is_ia32_NoReg_GP(get_irn_n(node, 1))) break; offset = get_ia32_am_offs_int(node); @@ -180,7 +173,6 @@ static void ia32_create_Pushs(ir_node *irn, ia32_code_gen_t *cg) { push = new_rd_ia32_Push(get_irn_dbg_info(store), irg, block, noreg, noreg, val, curr_sp, mem); set_ia32_am_support(push, ia32_am_Source, ia32_am_unary); - copy_ia32_Immop_attr(push, store); sched_add_before(irn, push); @@ -297,350 +289,6 @@ void ia32_peephole_optimization(ir_graph *irg, ia32_code_gen_t *cg) { * ******************************************************************/ -typedef struct { - ia32_code_gen_t *cg; - heights_t *h; -} ia32_am_opt_env_t; - -static int node_is_ia32_comm(const ir_node *irn) { - return is_ia32_irn(irn) ? is_ia32_commutative(irn) : 0; -} - -static int ia32_get_irn_n_edges(const ir_node *irn) { - const ir_edge_t *edge; - int cnt = 0; - - foreach_out_edge(irn, edge) { - cnt++; - } - - return cnt; -} - -/** - * Determines if pred is a Proj and if is_op_func returns true for it's predecessor. - * - * @param pred The node to be checked - * @param is_op_func The check-function - * @return 1 if conditions are fulfilled, 0 otherwise - */ -static int pred_is_specific_node(const ir_node *pred, is_op_func_t *is_op_func) { - return is_op_func(pred); -} - -/** - * Determines if pred is a Proj and if is_op_func returns true for it's predecessor - * and if the predecessor is in block bl. - * - * @param bl The block - * @param pred The node to be checked - * @param is_op_func The check-function - * @return 1 if conditions are fulfilled, 0 otherwise - */ -static int pred_is_specific_nodeblock(const ir_node *bl, const ir_node *pred, - int (*is_op_func)(const ir_node *n)) -{ - if (is_Proj(pred)) { - pred = get_Proj_pred(pred); - if ((bl == get_nodes_block(pred)) && is_op_func(pred)) { - return 1; - } - } - - return 0; -} - -/** - * Checks if irn is a candidate for address calculation. We avoid transforming - * adds to leas if they have a load as pred, because then we can use AM mode - * for the add later. - * - * - none of the operand must be a Load within the same block OR - * - all Loads must have more than one user OR - * - * @param block The block the Loads must/mustnot be in - * @param irn The irn to check - * return 1 if irn is a candidate, 0 otherwise - */ -static int is_addr_candidate(const ir_node *irn) -{ -#ifndef AGGRESSIVE_AM - const ir_node *block = get_nodes_block(irn); - ir_node *left, *right; - int n; - - left = get_irn_n(irn, 2); - right = get_irn_n(irn, 3); - - if (pred_is_specific_nodeblock(block, left, is_ia32_Ld)) { - n = ia32_get_irn_n_edges(left); - /* load with only one user: don't create LEA */ - if(n == 1) - return 0; - } - - if (pred_is_specific_nodeblock(block, right, is_ia32_Ld)) { - n = ia32_get_irn_n_edges(right); - if(n == 1) - return 0; - } -#endif - - (void) irn; - return 1; -} - -/** - * Checks if irn is a candidate for address mode. - * - * address mode (AM): - * - at least one operand has to be a Load within the same block AND - * - the load must not have other users than the irn AND - * - the irn must not have a frame entity set - * - * @param cg The ia32 code generator - * @param h The height information of the irg - * @param block The block the Loads must/mustnot be in - * @param irn The irn to check - * @return 0 if irn is no candidate, 1 if left load can be used, 2 if right one, 3 for both - */ -static ia32_am_cand_t is_am_candidate(heights_t *h, const ir_node *block, ir_node *irn) { - ir_node *in, *load, *other, *left, *right; - int is_cand = 0, cand; - int arity; - int is_binary; - - if (is_ia32_Ld(irn) || is_ia32_St(irn) || - is_ia32_vfild(irn) || is_ia32_vfist(irn) || - is_ia32_xStoreSimple(irn)) - return 0; - - if(get_ia32_frame_ent(irn) != NULL) - return IA32_AM_CAND_NONE; - - left = get_irn_n(irn, 2); - arity = get_irn_arity(irn); - is_binary = get_ia32_am_arity(irn) == ia32_am_binary; - if(is_binary) { - /* binary op */ - right = get_irn_n(irn, 3); - } else { - assert(get_ia32_am_arity(irn) == ia32_am_unary); - /* unary op */ - right = left; - } - - in = left; - - if (pred_is_specific_nodeblock(block, in, is_ia32_Ld)) { -#ifndef AGGRESSIVE_AM - int n; - n = ia32_get_irn_n_edges(in); - is_cand = (n == 1) ? 1 : is_cand; /* load with more than one user: no AM */ -#else - is_cand = 1; -#endif - - load = get_Proj_pred(in); - other = right; - - /* 8bit Loads are not supported (for binary ops), - * they cannot be used with every register */ - if (get_ia32_am_arity(irn) == ia32_am_binary && - get_mode_size_bits(get_ia32_ls_mode(load)) < 16) { - is_cand = 0; - } - - /* If there is a data dependency of other irn from load: cannot use AM */ - if (is_cand && is_binary && get_nodes_block(other) == block) { - other = skip_Proj(other); - is_cand = heights_reachable_in_block(h, other, load) ? 0 : is_cand; - /* this could happen in loops */ - is_cand = heights_reachable_in_block(h, load, irn) ? 0 : is_cand; - } - } - - cand = is_cand ? IA32_AM_CAND_LEFT : IA32_AM_CAND_NONE; - in = right; - is_cand = 0; - - if (pred_is_specific_nodeblock(block, in, is_ia32_Ld)) { -#ifndef AGGRESSIVE_AM - int n; - n = ia32_get_irn_n_edges(in); - is_cand = (n == 1) ? 1 : is_cand; /* load with more than one user: no AM */ -#else - is_cand = 1; -#endif - - load = get_Proj_pred(in); - other = left; - - /* 8bit Loads are not supported, they cannot be used with every register */ - /* 8bit Loads are not supported (for binary ops), - * they cannot be used with every register */ - if (get_ia32_am_arity(irn) == ia32_am_binary && - get_mode_size_bits(get_ia32_ls_mode(load)) < 16) { - is_cand = 0; - } - - /* If there is a data dependency of other irn from load: cannot use load */ - if (is_cand && is_binary && get_nodes_block(other) == block) { - other = skip_Proj(other); - is_cand = heights_reachable_in_block(h, other, load) ? 0 : is_cand; - /* this could happen in loops */ - is_cand = heights_reachable_in_block(h, load, irn) ? 0 : is_cand; - } - } - - cand = is_cand ? (cand | IA32_AM_CAND_RIGHT) : cand; - - /* if the irn has a frame entity: we do not use address mode */ - return cand; -} - -/** - * Compares the base and index addr and the load/store entities - * and returns 1 if they are equal. - */ -static int load_store_addr_is_equal(const ir_node *load, const ir_node *store, - const ir_node *addr_b, const ir_node *addr_i) -{ - if(get_irn_n(load, 0) != addr_b) - return 0; - if(get_irn_n(load, 1) != addr_i) - return 0; - - if(get_ia32_frame_ent(load) != get_ia32_frame_ent(store)) - return 0; - - if(get_ia32_am_sc(load) != get_ia32_am_sc(store)) - return 0; - if(is_ia32_am_sc_sign(load) != is_ia32_am_sc_sign(store)) - return 0; - if(get_ia32_am_offs_int(load) != get_ia32_am_offs_int(store)) - return 0; - if(get_ia32_ls_mode(load) != get_ia32_ls_mode(store)) - return 0; - - return 1; -} - -typedef enum _ia32_take_lea_attr { - IA32_LEA_ATTR_NONE = 0, - IA32_LEA_ATTR_BASE = (1 << 0), - IA32_LEA_ATTR_INDEX = (1 << 1), - IA32_LEA_ATTR_OFFS = (1 << 2), - IA32_LEA_ATTR_SCALE = (1 << 3), - IA32_LEA_ATTR_AMSC = (1 << 4), - IA32_LEA_ATTR_FENT = (1 << 5) -} ia32_take_lea_attr; - -/** - * Decides if we have to keep the LEA operand or if we can assimilate it. - */ -static int do_new_lea(ir_node *irn, ir_node *base, ir_node *index, ir_node *lea, - int have_am_sc, ia32_code_gen_t *cg) -{ - ir_entity *irn_ent = get_ia32_frame_ent(irn); - ir_entity *lea_ent = get_ia32_frame_ent(lea); - int ret_val = 0; - int is_noreg_base = be_is_NoReg(cg, base); - int is_noreg_index = be_is_NoReg(cg, index); - ia32_am_flavour_t am_flav = get_ia32_am_flavour(lea); - - /* If the Add and the LEA both have a different frame entity set: keep */ - if (irn_ent && lea_ent && (irn_ent != lea_ent)) - return IA32_LEA_ATTR_NONE; - else if (! irn_ent && lea_ent) - ret_val |= IA32_LEA_ATTR_FENT; - - /* If the Add and the LEA both have already an address mode symconst: keep */ - if (have_am_sc && get_ia32_am_sc(lea)) - return IA32_LEA_ATTR_NONE; - else if (get_ia32_am_sc(lea)) - ret_val |= IA32_LEA_ATTR_AMSC; - - /* Check the different base-index combinations */ - - if (! is_noreg_base && ! is_noreg_index) { - /* Assimilate if base is the lea and the LEA is just a Base + Offset calculation */ - if ((base == lea) && ! (am_flav & ia32_I ? 1 : 0)) { - if (am_flav & ia32_O) - ret_val |= IA32_LEA_ATTR_OFFS; - - ret_val |= IA32_LEA_ATTR_BASE; - } - else - return IA32_LEA_ATTR_NONE; - } - else if (! is_noreg_base && is_noreg_index) { - /* Base is set but index not */ - if (base == lea) { - /* Base points to LEA: assimilate everything */ - if (am_flav & ia32_O) - ret_val |= IA32_LEA_ATTR_OFFS; - if (am_flav & ia32_S) - ret_val |= IA32_LEA_ATTR_SCALE; - if (am_flav & ia32_I) - ret_val |= IA32_LEA_ATTR_INDEX; - - ret_val |= IA32_LEA_ATTR_BASE; - } - else if (am_flav & ia32_B ? 0 : 1) { - /* Base is not the LEA but the LEA is an index only calculation: assimilate */ - if (am_flav & ia32_O) - ret_val |= IA32_LEA_ATTR_OFFS; - if (am_flav & ia32_S) - ret_val |= IA32_LEA_ATTR_SCALE; - - ret_val |= IA32_LEA_ATTR_INDEX; - } - else - return IA32_LEA_ATTR_NONE; - } - else if (is_noreg_base && ! is_noreg_index) { - /* Index is set but not base */ - if (index == lea) { - /* Index points to LEA: assimilate everything */ - if (am_flav & ia32_O) - ret_val |= IA32_LEA_ATTR_OFFS; - if (am_flav & ia32_S) - ret_val |= IA32_LEA_ATTR_SCALE; - if (am_flav & ia32_B) - ret_val |= IA32_LEA_ATTR_BASE; - - ret_val |= IA32_LEA_ATTR_INDEX; - } - else if (am_flav & ia32_I ? 0 : 1) { - /* Index is not the LEA but the LEA is a base only calculation: assimilate */ - if (am_flav & ia32_O) - ret_val |= IA32_LEA_ATTR_OFFS; - if (am_flav & ia32_S) - ret_val |= IA32_LEA_ATTR_SCALE; - - ret_val |= IA32_LEA_ATTR_BASE; - } - else - return IA32_LEA_ATTR_NONE; - } - else { - assert(0 && "There must have been set base or index"); - } - - return ret_val; -} - -/** - * Adds res before irn into schedule if irn was scheduled. - * @param irn The schedule point - * @param res The node to be scheduled - */ -static INLINE void try_add_to_sched(ir_node *irn, ir_node *res) { - if (sched_is_scheduled(irn)) - sched_add_before(irn, res); -} - /** * Removes node from schedule if it is not used anymore. If irn is a mode_T node * all it's Projs are removed as well. @@ -666,430 +314,6 @@ static INLINE void try_kill(ir_node *node) be_kill_node(node); } -/** - * Folds Add or Sub to LEA if possible - */ -static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn) { - ir_graph *irg = get_irn_irg(irn); - dbg_info *dbg_info = get_irn_dbg_info(irn); - ir_node *block = get_nodes_block(irn); - ir_node *res = irn; - ir_node *shift = NULL; - ir_node *lea_o = NULL; - ir_node *lea = NULL; - long offs = 0; - long offs_cnst = 0; - long offs_lea = 0; - int scale = 0; - int isadd = 0; - int dolea = 0; - int have_am_sc = 0; - int am_sc_sign = 0; - ir_entity *am_sc = NULL; - ir_entity *lea_ent = NULL; - ir_node *noreg = ia32_new_NoReg_gp(cg); - ir_node *left, *right, *temp; - ir_node *base, *index; - int consumed_left_shift; - ia32_am_flavour_t am_flav; - - if (is_ia32_Add(irn)) - isadd = 1; - - left = get_irn_n(irn, 2); - right = get_irn_n(irn, 3); - - /* "normalize" arguments in case of add with two operands */ - if (isadd && ! be_is_NoReg(cg, right)) { - /* put LEA == ia32_am_O as right operand */ - if (is_ia32_Lea(left) && get_ia32_am_flavour(left) == ia32_am_O) { - set_irn_n(irn, 2, right); - set_irn_n(irn, 3, left); - temp = left; - left = right; - right = temp; - } - - /* put LEA != ia32_am_O as left operand */ - if (is_ia32_Lea(right) && get_ia32_am_flavour(right) != ia32_am_O) { - set_irn_n(irn, 2, right); - set_irn_n(irn, 3, left); - temp = left; - left = right; - right = temp; - } - - /* put SHL as left operand iff left is NOT a LEA */ - if (! is_ia32_Lea(left) && pred_is_specific_node(right, is_ia32_Shl)) { - set_irn_n(irn, 2, right); - set_irn_n(irn, 3, left); - temp = left; - left = right; - right = temp; - } - } - - base = left; - index = noreg; - offs = 0; - scale = 0; - am_flav = 0; - - /* check for operation with immediate */ - if (is_ia32_ImmConst(irn)) { - tarval *tv = get_ia32_Immop_tarval(irn); - - DBG((dbg, LEVEL_1, "\tfound op with imm const")); - - offs_cnst = get_tarval_long(tv); - dolea = 1; - } - else if (isadd && is_ia32_ImmSymConst(irn)) { - DBG((dbg, LEVEL_1, "\tfound op with imm symconst")); - - have_am_sc = 1; - dolea = 1; - am_sc = get_ia32_Immop_symconst(irn); - am_sc_sign = is_ia32_am_sc_sign(irn); - } - - /* determine the operand which needs to be checked */ - temp = be_is_NoReg(cg, right) ? left : right; - - /* check if right operand is AMConst (LEA with ia32_am_O) */ - /* but we can only eat it up if there is no other symconst */ - /* because the linker won't accept two symconsts */ - if (! have_am_sc && is_ia32_Lea(temp) && get_ia32_am_flavour(temp) == ia32_am_O) { - DBG((dbg, LEVEL_1, "\tgot op with LEA am_O")); - - offs_lea = get_ia32_am_offs_int(temp); - am_sc = get_ia32_am_sc(temp); - am_sc_sign = is_ia32_am_sc_sign(temp); - have_am_sc = 1; - dolea = 1; - lea_o = temp; - - if (temp == base) - base = noreg; - else if (temp == right) - right = noreg; - } - - if (isadd) { - /* default for add -> make right operand to index */ - index = right; - dolea = 1; - consumed_left_shift = -1; - - DBG((dbg, LEVEL_1, "\tgot LEA candidate with index %+F\n", index)); - - /* determine the operand which needs to be checked */ - temp = left; - if (is_ia32_Lea(left)) { - temp = right; - consumed_left_shift = 0; - } - - /* check for SHL 1,2,3 */ - if (pred_is_specific_node(temp, is_ia32_Shl)) { - ir_node *right = get_irn_n(temp, n_ia32_Shl_right); - - if (is_ia32_Immediate(right)) { - const ia32_immediate_attr_t *attr - = get_ia32_immediate_attr_const(right); - long shiftval = attr->offset; - - if (shiftval <= 3) { - index = get_irn_n(temp, 2); - consumed_left_shift = consumed_left_shift < 0 ? 1 : 0; - shift = temp; - scale = shiftval; - - DBG((dbg, LEVEL_1, "\tgot scaled index %+F\n", index)); - } - } - } - - /* fix base */ - if (! be_is_NoReg(cg, index)) { - /* if we have index, but left == right -> no base */ - if (left == right) { - base = noreg; - } - else if (consumed_left_shift == 1) { - /* -> base is right operand */ - base = (right == lea_o) ? noreg : right; - } - } - } - - /* Try to assimilate a LEA as left operand */ - if (is_ia32_Lea(left) && (get_ia32_am_flavour(left) != ia32_am_O)) { - /* check if we can assimilate the LEA */ - int take_attr = do_new_lea(irn, base, index, left, have_am_sc, cg); - - if (take_attr == IA32_LEA_ATTR_NONE) { - DBG((dbg, LEVEL_1, "\tleave old LEA, creating new one\n")); - } - else { - DBG((dbg, LEVEL_1, "\tgot LEA as left operand ... assimilating\n")); - lea = left; /* for statistics */ - - if (take_attr & IA32_LEA_ATTR_OFFS) - offs = get_ia32_am_offs_int(left); - - if (take_attr & IA32_LEA_ATTR_AMSC) { - am_sc = get_ia32_am_sc(left); - have_am_sc = 1; - am_sc_sign = is_ia32_am_sc_sign(left); - } - - if (take_attr & IA32_LEA_ATTR_SCALE) - scale = get_ia32_am_scale(left); - - if (take_attr & IA32_LEA_ATTR_BASE) - base = get_irn_n(left, 0); - - if (take_attr & IA32_LEA_ATTR_INDEX) - index = get_irn_n(left, 1); - - if (take_attr & IA32_LEA_ATTR_FENT) - lea_ent = get_ia32_frame_ent(left); - } - } - - /* ok, we can create a new LEA */ - if (dolea) { - res = new_rd_ia32_Lea(dbg_info, irg, block, base, index); - /* we don't want stuff before the barrier... */ - if(be_is_NoReg(cg, base) && be_is_NoReg(cg, index)) { - add_irn_dep(res, get_irg_frame(irg)); - } - - /* add the old offset of a previous LEA */ - add_ia32_am_offs_int(res, offs); - - /* add the new offset */ - if (isadd) { - add_ia32_am_offs_int(res, offs_cnst); - add_ia32_am_offs_int(res, offs_lea); - } else { - /* either lea_O-cnst, -cnst or -lea_O */ - if (offs_cnst != 0) { - add_ia32_am_offs_int(res, offs_lea); - add_ia32_am_offs_int(res, -offs_cnst); - } else { - add_ia32_am_offs_int(res, offs_lea); - } - } - - /* set the address mode symconst */ - if (have_am_sc) { - set_ia32_am_sc(res, am_sc); - if (am_sc_sign) - set_ia32_am_sc_sign(res); - } - - /* copy the frame entity (could be set in case of Add */ - /* which was a FrameAddr) */ - if (lea_ent != NULL) { - set_ia32_frame_ent(res, lea_ent); - set_ia32_use_frame(res); - } else { - set_ia32_frame_ent(res, get_ia32_frame_ent(irn)); - if(is_ia32_use_frame(irn)) - set_ia32_use_frame(res); - } - - /* set scale */ - set_ia32_am_scale(res, scale); - - am_flav = ia32_am_N; - /* determine new am flavour */ - if (offs || offs_cnst || offs_lea || have_am_sc) { - am_flav |= ia32_O; - } - if (! be_is_NoReg(cg, base)) { - am_flav |= ia32_B; - } - if (! be_is_NoReg(cg, index)) { - am_flav |= ia32_I; - } - if (scale > 0) { - am_flav |= ia32_S; - } - set_ia32_am_flavour(res, am_flav); - - set_ia32_op_type(res, ia32_AddrModeS); - - SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(cg, irn)); - - DBG((dbg, LEVEL_1, "\tLEA [%+F + %+F * %d + %d]\n", base, index, scale, get_ia32_am_offs_int(res))); - - assert(irn && "Couldn't find result proj"); - - /* get the result Proj of the Add/Sub */ - try_add_to_sched(irn, res); - - /* exchange the old op with the new LEA */ - try_kill(irn); - exchange(irn, res); - - /* we will exchange it, report here before the Proj is created */ - if (shift && lea && lea_o) { - try_kill(shift); - try_kill(lea); - try_kill(lea_o); - DBG_OPT_LEA4(irn, lea_o, lea, shift, res); - } else if (shift && lea) { - try_kill(shift); - try_kill(lea); - DBG_OPT_LEA3(irn, lea, shift, res); - } else if (shift && lea_o) { - try_kill(shift); - try_kill(lea_o); - DBG_OPT_LEA3(irn, lea_o, shift, res); - } else if (lea && lea_o) { - try_kill(lea); - try_kill(lea_o); - DBG_OPT_LEA3(irn, lea_o, lea, res); - } else if (shift) { - try_kill(shift); - DBG_OPT_LEA2(irn, shift, res); - } else if (lea) { - try_kill(lea); - DBG_OPT_LEA2(irn, lea, res); - } else if (lea_o) { - try_kill(lea_o); - DBG_OPT_LEA2(irn, lea_o, res); - } else { - DBG_OPT_LEA1(irn, res); - } - } - - return res; -} - - -/** - * Merges a Load/Store node with a LEA. - * @param irn The Load/Store node - * @param lea The LEA - */ -static void merge_loadstore_lea(ir_node *irn, ir_node *lea) { - ir_entity *irn_ent = get_ia32_frame_ent(irn); - ir_entity *lea_ent = get_ia32_frame_ent(lea); - - /* If the irn and the LEA both have a different frame entity set: do not merge */ - if (irn_ent != NULL && lea_ent != NULL && (irn_ent != lea_ent)) - return; - else if (irn_ent == NULL && lea_ent != NULL) { - set_ia32_frame_ent(irn, lea_ent); - set_ia32_use_frame(irn); - } - - /* get the AM attributes from the LEA */ - add_ia32_am_offs_int(irn, get_ia32_am_offs_int(lea)); - set_ia32_am_scale(irn, get_ia32_am_scale(lea)); - set_ia32_am_flavour(irn, get_ia32_am_flavour(lea)); - - set_ia32_am_sc(irn, get_ia32_am_sc(lea)); - if (is_ia32_am_sc_sign(lea)) - set_ia32_am_sc_sign(irn); - - set_ia32_op_type(irn, is_ia32_Ld(irn) ? ia32_AddrModeS : ia32_AddrModeD); - - /* set base and index */ - set_irn_n(irn, 0, get_irn_n(lea, 0)); - set_irn_n(irn, 1, get_irn_n(lea, 1)); - - try_kill(lea); - - /* clear remat flag */ - set_ia32_flags(irn, get_ia32_flags(irn) & ~arch_irn_flags_rematerializable); - - if (is_ia32_Ld(irn)) - DBG_OPT_LOAD_LEA(lea, irn); - else - DBG_OPT_STORE_LEA(lea, irn); - -} - -/** - * Sets new_right index of irn to right and new_left index to left. - * Also exchange left and right - */ -static void exchange_left_right(ir_node *irn, ir_node **left, ir_node **right, - int new_left, int new_right) -{ - ir_node *temp; - - assert(is_ia32_commutative(irn)); - - set_irn_n(irn, new_right, *right); - set_irn_n(irn, new_left, *left); - - temp = *left; - *left = *right; - *right = temp; - - /* this is only needed for Compares, but currently ALL nodes - * have this attribute :-) */ - set_ia32_pncode(irn, get_inversed_pnc(get_ia32_pncode(irn))); -} - -/** - * Performs address calculation optimization (create LEAs if possible) - */ -static void optimize_lea(ia32_code_gen_t *cg, ir_node *irn) { - if (! is_ia32_irn(irn)) - return; - - /* Following cases can occur: */ - /* - Sub (l, imm) -> LEA [base - offset] */ - /* - Sub (l, r == LEA with ia32_am_O) -> LEA [base - offset] */ - /* - Add (l, imm) -> LEA [base + offset] */ - /* - Add (l, r == LEA with ia32_am_O) -> LEA [base + offset] */ - /* - Add (l == LEA with ia32_am_O, r) -> LEA [base + offset] */ - /* - Add (l, r) -> LEA [base + index * scale] */ - /* with scale > 1 iff l/r == shl (1,2,3) */ - if (is_ia32_Sub(irn) || is_ia32_Add(irn)) { - ir_node *res; - - if(!is_addr_candidate(irn)) - return; - - DBG((dbg, LEVEL_1, "\tfound address calculation candidate %+F ... ", irn)); - res = fold_addr(cg, irn); - - if (res != irn) - DB((dbg, LEVEL_1, "transformed into %+F\n", res)); - else - DB((dbg, LEVEL_1, "not transformed\n")); - } else if (is_ia32_Ld(irn) || is_ia32_St(irn)) { - /* - Load -> LEA into Load } TODO: If the LEA is used by more than one Load/Store */ - /* - Store -> LEA into Store } it might be better to keep the LEA */ - ir_node *left = get_irn_n(irn, 0); - - if (is_ia32_Lea(left)) { - const ir_edge_t *edge, *ne; - ir_node *src; - - /* merge all Loads/Stores connected to this LEA with the LEA */ - foreach_out_edge_safe(left, edge, ne) { - src = get_edge_src_irn(edge); - - if (src && (get_edge_src_pos(edge) == 0) && (is_ia32_Ld(src) || is_ia32_St(src))) { - DBG((dbg, LEVEL_1, "\nmerging %+F into %+F\n", left, irn)); - if (! is_ia32_got_lea(src)) - merge_loadstore_lea(src, left); - set_ia32_got_lea(src); - } - } - } - } -} - static void optimize_conv_store(ir_node *node) { ir_node *pred; @@ -1236,400 +460,22 @@ static void optimize_conv_conv(ir_node *node) static void optimize_node(ir_node *node, void *env) { - ia32_code_gen_t *cg = env; + (void) env; optimize_load_conv(node); optimize_conv_store(node); optimize_conv_conv(node); - optimize_lea(cg, node); -} - -/** - * Checks for address mode patterns and performs the - * necessary transformations. - * This function is called by a walker. - */ -static void optimize_am(ir_node *irn, void *env) { - ia32_am_opt_env_t *am_opt_env = env; - ia32_code_gen_t *cg = am_opt_env->cg; - ir_graph *irg = get_irn_irg(irn); - heights_t *h = am_opt_env->h; - ir_node *block, *left, *right; - ir_node *store, *load, *mem_proj; - ir_node *addr_b, *addr_i; - int need_exchange_on_fail = 0; - ia32_am_type_t am_support; - ia32_am_arity_t am_arity; - ia32_am_cand_t cand; - ia32_am_cand_t orig_cand; - int dest_possible; - int source_possible; - - static const arch_register_req_t dest_out_reg_req_0 = { - arch_register_req_type_none, - NULL, /* regclass */ - NULL, /* limit bitset */ - -1, /* same pos */ - -1 /* different pos */ - }; - static const arch_register_req_t *dest_am_out_reqs[] = { - &dest_out_reg_req_0 - }; - - if (!is_ia32_irn(irn) || is_ia32_Ld(irn) || is_ia32_St(irn)) - return; - if (is_ia32_Lea(irn)) - return; - - am_support = get_ia32_am_support(irn); - am_arity = get_ia32_am_arity(irn); - block = get_nodes_block(irn); - - /* fold following patterns: - * - op -> Load into AMop with am_Source - * conditions: - * - op is am_Source capable AND - * - the Load is only used by this op AND - * - the Load is in the same block - * - Store -> op -> Load into AMop with am_Dest - * conditions: - * - op is am_Dest capable AND - * - the Store uses the same address as the Load AND - * - the Load is only used by this op AND - * - the Load and Store are in the same block AND - * - nobody else uses the result of the op - */ - if (am_support == ia32_am_None) - return; - - assert(am_arity == ia32_am_unary || am_arity == ia32_am_binary); - - cand = is_am_candidate(h, block, irn); - if (cand == IA32_AM_CAND_NONE) - return; - - orig_cand = cand; - DBG((dbg, LEVEL_1, "\tfound address mode candidate %+F (candleft %d candright %d)... \n", irn, - cand & IA32_AM_CAND_LEFT, cand & IA32_AM_CAND_RIGHT)); - - left = get_irn_n(irn, 2); - if (am_arity == ia32_am_unary) { - assert(get_irn_arity(irn) >= 4); - right = left; - assert(cand == IA32_AM_CAND_BOTH); - } else { - assert(get_irn_arity(irn) >= 5); - right = get_irn_n(irn, 3); - } - - dest_possible = am_support & ia32_am_Dest ? 1 : 0; - source_possible = am_support & ia32_am_Source ? 1 : 0; - - DBG((dbg, LEVEL_2, "\tdest_possible %d source_possible %d ... \n", dest_possible, source_possible)); - - if (dest_possible) { - addr_b = NULL; - addr_i = NULL; - store = NULL; - - /* we should only have 1 user which is a store */ - if (ia32_get_irn_n_edges(irn) == 1) { - ir_node *succ = get_edge_src_irn(get_irn_out_edge_first(irn)); - - if (is_ia32_xStore(succ) || is_ia32_Store(succ)) { - store = succ; - addr_b = get_irn_n(store, 0); - addr_i = get_irn_n(store, 1); - } - } - - if (store == NULL) { - DBG((dbg, LEVEL_2, "\tno store found, not using dest_mode\n")); - dest_possible = 0; - } - } - - if (dest_possible) { - /* normalize nodes, we need the interesting load on the left side */ - if (cand & IA32_AM_CAND_RIGHT) { - load = get_Proj_pred(right); - if (load_store_addr_is_equal(load, store, addr_b, addr_i) - && node_is_ia32_comm(irn)) { - DBG((dbg, LEVEL_2, "\texchanging left/right\n")); - exchange_left_right(irn, &left, &right, 3, 2); - need_exchange_on_fail ^= 1; - if (cand == IA32_AM_CAND_RIGHT) - cand = IA32_AM_CAND_LEFT; - } - } - } - - if (dest_possible) { - if(cand & IA32_AM_CAND_LEFT && is_Proj(left)) { - load = get_Proj_pred(left); - -#ifndef AGGRESSIVE_AM - /* we have to be the only user of the load */ - if (get_irn_n_edges(left) > 1) { - DBG((dbg, LEVEL_2, "\tmatching load has too may users, not using dest_mode\n")); - dest_possible = 0; - } -#endif - } else { - DBG((dbg, LEVEL_2, "\tno matching load found, not using dest_mode")); - dest_possible = 0; - } - } - - if (dest_possible) { - /* the store has to use the loads memory or the same memory - * as the load */ - ir_node *loadmem = get_irn_n(load, 2); - ir_node *storemem = get_irn_n(store, 3); - assert(get_irn_mode(loadmem) == mode_M); - assert(get_irn_mode(storemem) == mode_M); - /* TODO there could be a sync between store and load... */ - if(storemem != loadmem && (!is_Proj(storemem) || get_Proj_pred(storemem) != load)) { - DBG((dbg, LEVEL_2, "\tload/store using different memories, not using dest_mode")); - dest_possible = 0; - } - } - - if (dest_possible) { - /* Compare Load and Store address */ - if (!load_store_addr_is_equal(load, store, addr_b, addr_i)) { - DBG((dbg, LEVEL_2, "\taddresses not equal, not using dest_mode")); - dest_possible = 0; - } - } - - if (dest_possible) { - ir_mode *lsmode = get_ia32_ls_mode(load); - if(get_mode_size_bits(lsmode) != 32) { - dest_possible = 0; - } - } - - if (dest_possible) { - /* all conditions fullfilled, do the transformation */ - assert(cand & IA32_AM_CAND_LEFT); - - /* set new base, index and attributes */ - set_irn_n(irn, 0, addr_b); - set_irn_n(irn, 1, addr_i); - add_ia32_am_offs_int(irn, get_ia32_am_offs_int(load)); - set_ia32_am_scale(irn, get_ia32_am_scale(load)); - set_ia32_am_flavour(irn, get_ia32_am_flavour(load)); - set_ia32_op_type(irn, ia32_AddrModeD); - set_ia32_frame_ent(irn, get_ia32_frame_ent(load)); - set_ia32_ls_mode(irn, get_ia32_ls_mode(load)); - - set_ia32_am_sc(irn, get_ia32_am_sc(load)); - if (is_ia32_am_sc_sign(load)) - set_ia32_am_sc_sign(irn); - - /* connect to Load memory and disconnect Load */ - if (am_arity == ia32_am_binary) { - /* binary AMop */ - set_irn_n(irn, 4, get_irn_n(load, 2)); - set_irn_n(irn, 2, ia32_get_admissible_noreg(cg, irn, 2)); - } else { - /* unary AMop */ - set_irn_n(irn, 3, get_irn_n(load, 2)); - set_irn_n(irn, 2, ia32_get_admissible_noreg(cg, irn, 2)); - } - - /* change node mode and out register requirements */ - set_irn_mode(irn, mode_M); - set_ia32_out_req_all(irn, dest_am_out_reqs); - - /* connect the memory Proj of the Store to the op */ - edges_reroute(store, irn, irg); - - /* clear remat flag */ - set_ia32_flags(irn, get_ia32_flags(irn) & ~arch_irn_flags_rematerializable); - - try_kill(store); - try_kill(load); - DBG_OPT_AM_D(load, store, irn); - - DB((dbg, LEVEL_1, "merged with %+F and %+F into dest AM\n", load, store)); - need_exchange_on_fail = 0; - source_possible = 0; - } - - if (source_possible) { - /* normalize ops, we need the load on the right */ - if(cand == IA32_AM_CAND_LEFT) { - if(node_is_ia32_comm(irn)) { - exchange_left_right(irn, &left, &right, 3, 2); - need_exchange_on_fail ^= 1; - cand = IA32_AM_CAND_RIGHT; - } else { - source_possible = 0; - } - } - } - - if (source_possible) { - /* all conditions fullfilled, do transform */ - assert(cand & IA32_AM_CAND_RIGHT); - load = get_Proj_pred(right); - - if(get_irn_n_edges(right) > 1) { - source_possible = 0; - } -#if 1 - /* TODO: this isn't really needed, but the code below is buggy - as heights won't get recomputed when the graph is reconstructed - so we can only transform loads with the result proj only */ - if(get_irn_n_edges(load) > 1) { - source_possible = 0; - } -#endif - } - - if (source_possible) { - ir_mode *ls_mode = get_ia32_ls_mode(load); - if(get_mode_size_bits(ls_mode) != 32 || ls_mode == mode_D) - source_possible = 0; - - } - - if (source_possible) { - const ia32_attr_t *attr_load = get_ia32_attr_const(load); - ia32_attr_t *attr_irn = get_ia32_attr(irn); - addr_b = get_irn_n(load, 0); - addr_i = get_irn_n(load, 1); - - /* set new base, index and attributes */ - set_irn_n(irn, 0, addr_b); - set_irn_n(irn, 1, addr_i); - add_ia32_am_offs_int(irn, get_ia32_am_offs_int(load)); - set_ia32_am_scale(irn, get_ia32_am_scale(load)); - set_ia32_am_flavour(irn, get_ia32_am_flavour(load)); - set_ia32_op_type(irn, ia32_AddrModeS); - set_ia32_frame_ent(irn, get_ia32_frame_ent(load)); - attr_irn->data.need_64bit_stackent - = attr_load->data.need_64bit_stackent; - attr_irn->data.need_32bit_stackent - = attr_load->data.need_32bit_stackent; - - /* set ls_mode if not already present (conv nodes already have ls_mode - set) */ - if(get_ia32_ls_mode(irn) == NULL) { - set_ia32_ls_mode(irn, get_ia32_ls_mode(load)); - } - - set_ia32_am_sc(irn, get_ia32_am_sc(load)); - if (is_ia32_am_sc_sign(load)) - set_ia32_am_sc_sign(irn); - - /* clear remat flag */ - set_ia32_flags(irn, get_ia32_flags(irn) & ~arch_irn_flags_rematerializable); - - if (is_ia32_use_frame(load)) { - if(get_ia32_frame_ent(load) == NULL) { - set_ia32_need_stackent(irn); - } - set_ia32_use_frame(irn); - } - - /* connect to Load memory and disconnect Load */ - if (am_arity == ia32_am_binary) { - /* binary AMop */ - right = ia32_get_admissible_noreg(cg, irn, 3); - set_irn_n(irn, 3, right); - set_irn_n(irn, 4, get_irn_n(load, n_ia32_Load_mem)); - } else { - /* unary AMop */ - right = ia32_get_admissible_noreg(cg, irn, 2); - set_irn_n(irn, 2, right); - set_irn_n(irn, 3, get_irn_n(load, n_ia32_Load_mem)); - } - - DBG_OPT_AM_S(load, irn); - - /* If Load has a memory Proj, connect it to the op */ - mem_proj = ia32_get_proj_for_mode(load, mode_M); - if (mem_proj != NULL) { - ir_node *res_proj; - ir_mode *mode = get_irn_mode(irn); - - if(mode != mode_T) { - res_proj = new_rd_Proj(get_irn_dbg_info(irn), irg, - get_nodes_block(irn), - new_Unknown(mode_T), mode, 0); - set_irn_mode(irn, mode_T); - edges_reroute(irn, res_proj, irg); - set_Proj_pred(res_proj, irn); - - set_Proj_pred(mem_proj, irn); - set_Proj_proj(mem_proj, 1); - } else { - /* hacky: we need some proj number which is not used yet... */ - set_Proj_proj(mem_proj, -1); - set_Proj_pred(mem_proj, irn); - } - } - - try_kill(load); - need_exchange_on_fail = 0; - - /* immediate are only allowed on the right side */ - if(is_ia32_Immediate(left)) { - exchange_left_right(irn, &left, &right, 3, 2); - } - - DB((dbg, LEVEL_1, "merged with %+F into source AM\n", load)); - } - - /* was exchanged but optimize failed: exchange back */ - if (need_exchange_on_fail) { - exchange_left_right(irn, &left, &right, 3, 2); - } } /** * Performs conv and address mode optimization. */ -void ia32_optimize_graph(ia32_code_gen_t *cg) { - /* if we are supposed to do AM or LEA optimization: recalculate edges */ - if (! (cg->opt & (IA32_OPT_DOAM | IA32_OPT_LEA))) { - /* no optimizations at all */ - return; - } - - /* beware: we cannot optimize LEA and AM in one run because */ - /* LEA optimization adds new nodes to the irg which */ - /* invalidates the phase data */ - - if (cg->opt & IA32_OPT_LEA) { - irg_walk_blkwise_graph(cg->irg, NULL, optimize_node, cg); - } +void ia32_optimize_graph(ia32_code_gen_t *cg) +{ + irg_walk_blkwise_graph(cg->irg, NULL, optimize_node, cg); if (cg->dump) - be_dump(cg->irg, "-lea", dump_ir_block_graph_sched); - - /* hack for now, so these don't get created during optimize, because then - * they will be unknown to the heights module - */ - ia32_new_NoReg_gp(cg); - ia32_new_NoReg_fp(cg); - ia32_new_NoReg_vfp(cg); - - if (cg->opt & IA32_OPT_DOAM) { - /* we need height information for am optimization */ - heights_t *h = heights_new(cg->irg); - ia32_am_opt_env_t env; - - env.cg = cg; - env.h = h; - - irg_walk_blkwise_graph(cg->irg, NULL, optimize_am, &env); - - heights_free(h); - } + be_dump(cg->irg, "-opt", dump_ir_block_graph_sched); } void ia32_init_optimize(void) diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index 5986d8e56..b1630f147 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -253,8 +253,12 @@ $arch = "ia32"; S3 => "${arch}_emit_source_register(env, node, 3);", S4 => "${arch}_emit_source_register(env, node, 4);", S5 => "${arch}_emit_source_register(env, node, 5);", - SB0 => "${arch}_emit_8bit_source_register(env, node, 0);", + SB1 => "${arch}_emit_8bit_source_register(env, node, 1);", + SB2 => "${arch}_emit_8bit_source_register(env, node, 2);", SW0 => "${arch}_emit_16bit_source_register(env, node, 0);", + SI0 => "${arch}_emit_source_register_or_immediate(env, node, 0);", + SI1 => "${arch}_emit_source_register_or_immediate(env, node, 1);", + SI2 => "${arch}_emit_source_register_or_immediate(env, node, 2);", D0 => "${arch}_emit_dest_register(env, node, 0);", D1 => "${arch}_emit_dest_register(env, node, 1);", D2 => "${arch}_emit_dest_register(env, node, 2);", @@ -264,7 +268,6 @@ $arch = "ia32"; X0 => "${arch}_emit_x87_name(env, node, 0);", X1 => "${arch}_emit_x87_name(env, node, 1);", X2 => "${arch}_emit_x87_name(env, node, 2);", - C => "${arch}_emit_immediate(env, node);", SE => "${arch}_emit_extend_suffix(env, get_ia32_ls_mode(node));", ME => "if(get_mode_size_bits(get_ia32_ls_mode(node)) != 32)\n ia32_emit_mode_suffix(env, node);", @@ -387,14 +390,26 @@ Add => { reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, ins => [ "base", "index", "left", "right", "mem" ], emit => '. add%M %binop', + init_attr => "set_ia32_am_support(res, ia32_am_Full, ia32_am_binary);", units => [ "GP" ], mode => $mode_gp, modified_flags => $status_flags }, +AddMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "val", "mem" ], + emit => ". add%M %SI2, %AM", + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + Adc => { reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, emit => '. adc%M %binop', + init_attr => "set_ia32_am_support(res, ia32_am_Full, ia32_am_binary);", units => [ "GP" ], mode => $mode_gp, modified_flags => $status_flags @@ -435,6 +450,7 @@ Mul => { emit => '. mul%M %unop3', outs => [ "EAX", "EDX", "M" ], ins => [ "base", "index", "val_high", "val_low", "mem" ], + init_attr => "set_ia32_am_support(res, ia32_am_Source, ia32_am_binary);", latency => 10, units => [ "GP" ], modified_flags => $status_flags @@ -452,7 +468,9 @@ l_Mul => { IMul => { irn_flags => "R", reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, + ins => [ "base", "index", "left", "right", "mem" ], emit => '. imul%M %binop', + init_attr => "set_ia32_am_support(res, ia32_am_Source, ia32_am_binary);", latency => 5, units => [ "GP" ], mode => $mode_gp, @@ -465,6 +483,7 @@ IMul1OP => { emit => '. imul%M %unop3', outs => [ "EAX", "EDX", "M" ], ins => [ "base", "index", "val_high", "val_low", "mem" ], + init_attr => "set_ia32_am_support(res, ia32_am_Source, ia32_am_binary);", latency => 5, units => [ "GP" ], modified_flags => $status_flags @@ -482,30 +501,65 @@ l_IMul => { And => { irn_flags => "R", reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, + ins => [ "base", "index", "left", "right", "mem" ], + init_attr => "set_ia32_am_support(res, ia32_am_Full, ia32_am_binary);", emit => '. and%M %binop', units => [ "GP" ], mode => $mode_gp, modified_flags => $status_flags }, +AndMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "none" ] }, + emit => '. and%M %SI2, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + Or => { irn_flags => "R", reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, + ins => [ "base", "index", "left", "right", "mem" ], + init_attr => "set_ia32_am_support(res, ia32_am_Full, ia32_am_binary);", emit => '. or%M %binop', units => [ "GP" ], mode => $mode_gp, modified_flags => $status_flags }, +OrMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "val", "mem" ], + emit => '. or%M %SI2, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + Xor => { irn_flags => "R", reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, + ins => [ "base", "index", "left", "right", "mem" ], + init_attr => "set_ia32_am_support(res, ia32_am_Full, ia32_am_binary);", emit => '. xor%M %binop', units => [ "GP" ], mode => $mode_gp, modified_flags => $status_flags }, +XorMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "val", "mem" ], + emit => '. xor%M %SI2, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + l_Xor => { op_flags => "C", cmp_attr => "return 1;", @@ -518,14 +572,28 @@ l_Xor => { Sub => { irn_flags => "R", reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, + ins => [ "base", "index", "left", "right", "mem" ], + init_attr => "set_ia32_am_support(res, ia32_am_Full, ia32_am_binary);", emit => '. sub%M %binop', units => [ "GP" ], mode => $mode_gp, modified_flags => $status_flags }, +SubMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "val", "mem" ], + emit => '. sub%M %SI2, %AM', + units => [ "GP" ], + mode => 'mode_M', + modified_flags => $status_flags +}, + Sbb => { reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "in_r3 !in_r4" ] }, + ins => [ "base", "index", "left", "right", "mem" ], + init_attr => "set_ia32_am_support(res, ia32_am_Full, ia32_am_binary);", emit => '. sbb%M %binop', units => [ "GP" ], mode => $mode_gp, @@ -561,11 +629,15 @@ l_Sbb => { IDiv => { op_flags => "F|L", state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "eax", "edx", "gp", "none" ], out => [ "eax", "edx", "none" ] }, + reg_req => { in => [ "gp", "gp", "eax", "edx", "gp", "none" ], + out => [ "eax", "edx", "none" ] }, + ins => [ "base", "index", "left_low", "left_high", "right", "mem" ], + outs => [ "div_res", "mod_res", "M" ], attr => "ia32_op_flavour_t dm_flav", - init_attr => "attr->data.op_flav = dm_flav;", + init_attr => + "attr->data.op_flav = dm_flav;". + "set_ia32_am_support(res, ia32_am_Full, ia32_am_ternary);", emit => ". idiv%M %unop4", - outs => [ "div_res", "mod_res", "M" ], latency => 25, units => [ "GP" ], modified_flags => $status_flags @@ -574,11 +646,15 @@ IDiv => { Div => { op_flags => "F|L", state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "eax", "edx", "gp", "none" ], out => [ "eax", "edx", "none" ] }, + reg_req => { in => [ "gp", "gp", "eax", "edx", "gp", "none" ], + out => [ "eax", "edx", "none" ] }, + ins => [ "base", "index", "left_low", "left_high", "right", "mem" ], + outs => [ "div_res", "mod_res", "M" ], attr => "ia32_op_flavour_t dm_flav", - init_attr => "attr->data.op_flav = dm_flav;", + init_attr => + "attr->data.op_flav = dm_flav;". + "set_ia32_am_support(res, ia32_am_Full, ia32_am_ternary);", emit => ". div%M %unop4", - outs => [ "div_res", "mod_res", "M" ], latency => 25, units => [ "GP" ], modified_flags => $status_flags @@ -586,17 +662,25 @@ Div => { Shl => { irn_flags => "R", - # "in_r3" would be enough as out requirement, but the register allocator - # does strange things then and doesn't respect the constraint for in4 - # if the same value is attached to in3 and in4 (if you have "i << i" in C) - reg_req => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] }, - ins => [ "base", "index", "left", "right", "mem" ], - emit => '. shl%M %binop', + reg_req => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] }, + ins => [ "left", "right" ], + init_attr => "set_ia32_am_support(res, ia32_am_Dest, ia32_am_binary);", + emit => '. shl %SB1, %S0', units => [ "GP" ], mode => $mode_gp, modified_flags => $status_flags }, +ShlMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "ecx", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "count", "mem" ], + emit => '. shl%M %SI2, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + l_ShlDep => { cmp_attr => "return 1;", # value, cnt, dependency @@ -617,23 +701,10 @@ ShlD => { # reg_req => { in => [ "gp", "gp", "gp", "gp", "ecx", "none" ], out => [ "!in" ] }, irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r5" ] }, - emit => -' -if (get_ia32_immop_type(node) == ia32_ImmNone) { - if (get_ia32_op_type(node) == ia32_AddrModeD) { - . shld%M %%cl, %S3, %AM - } else { - . shld%M %%cl, %S3, %S2 - } -} else { - if (get_ia32_op_type(node) == ia32_AddrModeD) { - . shld%M %C, %S3, %AM - } else { - . shld%M %C, %S3, %S2 - } -} -', + reg_req => { in => [ "gp", "gp", "ecx" ], out => [ "in_r1 !in_r3" ] }, + ins => [ "left_high", "left_low", "right" ], + init_attr => "set_ia32_am_support(res, ia32_am_Dest, ia32_am_ternary);", + emit => '. shld%M %SB2, %S1, %S0', latency => 6, units => [ "GP" ], mode => $mode_gp, @@ -647,13 +718,25 @@ l_ShlD => { Shr => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] }, - emit => '. shr%M %binop', + reg_req => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] }, + ins => [ "val", "count" ], + init_attr => "set_ia32_am_support(res, ia32_am_Dest, ia32_am_binary);", + emit => '. shr %SB1, %S0', units => [ "GP" ], mode => $mode_gp, modified_flags => $status_flags }, +ShrMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "ecx", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "count", "mem" ], + emit => '. shr%M %SI2, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + l_ShrDep => { cmp_attr => "return 1;", # value, cnt, dependency @@ -674,22 +757,10 @@ ShrD => { # reg_req => { in => [ "gp", "gp", "gp", "gp", "ecx", "none" ], out => [ "!in" ] }, irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r5" ] }, - emit => ' -if (get_ia32_immop_type(node) == ia32_ImmNone) { - if (get_ia32_op_type(node) == ia32_AddrModeD) { - . shrd%M %%cl, %S3, %AM - } else { - . shrd%M %%cl, %S3, %S2 - } -} else { - if (get_ia32_op_type(node) == ia32_AddrModeD) { - . shrd%M %C, %S3, %AM - } else { - . shrd%M %C, %S3, %S2 - } -} -', + reg_req => { in => [ "gp", "gp", "ecx" ], out => [ "in_r1 !in_r3" ] }, + ins => [ "left_high", "left_low", "right" ], + init_attr => "set_ia32_am_support(res, ia32_am_Dest, ia32_am_ternary);", + emit => '. shrd%M %SB2, %S1, %S0', latency => 6, units => [ "GP" ], mode => $mode_gp, @@ -703,13 +774,25 @@ l_ShrD => { Sar => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] }, - emit => '. sar%M %binop', + reg_req => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] }, + ins => [ "val", "count" ], + init_attr => "set_ia32_am_support(res, ia32_am_Dest, ia32_am_binary);", + emit => '. sar %SB1, %S0', units => [ "GP" ], mode => $mode_gp, modified_flags => $status_flags }, +SarMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "ecx", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "count", "mem" ], + emit => '. sar%M %SI2, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + l_Sar => { cmp_attr => "return 1;", # value, cnt @@ -724,34 +807,69 @@ l_SarDep => { Ror => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] }, - emit => '. ror%M %binop', + reg_req => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] }, + ins => [ "val", "count" ], + init_attr => "set_ia32_am_support(res, ia32_am_Dest, ia32_am_binary);", + emit => '. ror %SB1, %S0', units => [ "GP" ], mode => $mode_gp, modified_flags => $status_flags }, +RorMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "ecx", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "count", "mem" ], + emit => '. ror%M %SI2, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + Rol => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "ecx", "none" ], out => [ "in_r3 !in_r4" ] }, - emit => '. rol%M %binop', + reg_req => { in => [ "gp", "ecx" ], out => [ "in_r1 !in_r2" ] }, + ins => [ "val", "count" ], + init_attr => "set_ia32_am_support(res, ia32_am_Dest, ia32_am_binary);", + emit => '. rol %SB1, %S0', units => [ "GP" ], mode => $mode_gp, modified_flags => $status_flags }, +RolMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "ecx", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "count", "mem" ], + emit => '. rol%M %SI2, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + # unary operations Neg => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, - emit => '. neg%M %unop2', - ins => [ "base", "index", "val", "mem" ], + reg_req => { in => [ "gp" ], out => [ "in_r1" ] }, + emit => '. neg %S0', + ins => [ "val" ], + init_attr => "set_ia32_am_support(res, ia32_am_Dest, ia32_am_unary);", units => [ "GP" ], mode => $mode_gp, modified_flags => $status_flags }, +NegMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "mem" ], + emit => '. neg%M %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + Minus64Bit => { irn_flags => "R", reg_req => { in => [ "gp", "gp", "gp" ], out => [ "!in", "!in" ] }, @@ -774,35 +892,68 @@ l_Neg => { Inc => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, - emit => '. inc%M %unop2', + reg_req => { in => [ "gp" ], out => [ "in_r1" ] }, + init_attr => "set_ia32_am_support(res, ia32_am_Dest, ia32_am_unary);", + emit => '. inc %S0', units => [ "GP" ], mode => $mode_gp, modified_flags => [ "OF", "SF", "ZF", "AF", "PF" ] }, +IncMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "mem" ], + emit => '. inc%M %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => [ "OF", "SF", "ZF", "AF", "PF" ] +}, + Dec => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, - emit => '. dec%M %unop2', + reg_req => { in => [ "gp" ], out => [ "in_r1" ] }, + init_attr => "set_ia32_am_support(res, ia32_am_Dest, ia32_am_unary);", + emit => '. dec %S0', units => [ "GP" ], mode => $mode_gp, modified_flags => [ "OF", "SF", "ZF", "AF", "PF" ] }, +DecMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "mem" ], + emit => '. dec%M %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => [ "OF", "SF", "ZF", "AF", "PF" ] +}, + Not => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, - ins => [ "base", "index", "val", "mem" ], - emit => '. not%M %unop2', + reg_req => { in => [ "gp" ], out => [ "in_r1" ] }, + ins => [ "val" ], + init_attr => "set_ia32_am_support(res, ia32_am_Dest, ia32_am_unary);", + emit => '. not %S0', units => [ "GP" ], mode => $mode_gp, modified_flags => [] }, +NotMem => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "mem" ], + emit => '. not%M %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => [], +}, + # other operations -CondJmp => { +CmpJmp => { state => "pinned", op_flags => "L|X|Y", reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], @@ -810,7 +961,25 @@ CondJmp => { ins => [ "base", "index", "left", "right", "mem" ], outs => [ "false", "true" ], attr => "long pnc", - init_attr => "attr->pn_code = pnc;", + init_attr => + "attr->pn_code = pnc;". + "set_ia32_am_support(res, ia32_am_Source, ia32_am_binary);", + latency => 3, + units => [ "BRANCH" ], +}, + +CmpJmp8Bit => { + state => "pinned", + op_flags => "L|X|Y", + reg_req => { in => [ "gp", "gp", "eax ebx ecx edx", "eax ebx ecx edx", + "none" ], + out => [ "none", "none"] }, + ins => [ "base", "index", "left", "right", "mem" ], + outs => [ "false", "true" ], + attr => "long pnc", + init_attr => + "attr->pn_code = pnc;". + "set_ia32_am_support(res, ia32_am_Source, ia32_am_binary);", latency => 3, units => [ "BRANCH" ], }, @@ -823,7 +992,25 @@ TestJmp => { ins => [ "base", "index", "left", "right", "mem" ], outs => [ "false", "true" ], attr => "long pnc", - init_attr => "attr->pn_code = pnc;", + init_attr => + "attr->pn_code = pnc;". + "set_ia32_am_support(res, ia32_am_Source, ia32_am_binary);", + latency => 3, + units => [ "BRANCH" ], +}, + +TestJmp8Bit => { + state => "pinned", + op_flags => "L|X|Y", + reg_req => { in => [ "gp", "gp", "eax ebx ecx edx", "eax ebx ecx edx", + "none" ], + out => [ "none", "none" ] }, + ins => [ "base", "index", "left", "right", "mem" ], + outs => [ "false", "true" ], + attr => "long pnc", + init_attr => + "attr->pn_code = pnc;". + "set_ia32_am_support(res, ia32_am_Source, ia32_am_binary);", latency => 3, units => [ "BRANCH" ], }, @@ -840,9 +1027,8 @@ SwitchJmp => { IJmp => { state => "pinned", op_flags => "X", - reg_req => { in => [ "gp", "gp", "gp", "none" ] }, - ins => [ "base", "index", "val", "mem" ], - emit => '. jmp *%unop2', + reg_req => { in => [ "gp" ] }, + emit => '. jmp *%S0', units => [ "BRANCH" ], mode => "mode_X", modified_flags => [] @@ -853,6 +1039,8 @@ Const => { irn_flags => "R", reg_req => { out => [ "gp" ] }, units => [ "GP" ], + attr => "ir_entity *symconst, int symconst_sign, long offset", + attr_type => "ia32_immediate_attr_t", mode => $mode_gp, }, @@ -933,6 +1121,7 @@ FldCW => { op_flags => "L|F", state => "pinned", reg_req => { in => [ "gp", "gp", "none" ], out => [ "fp_cw" ] }, + ins => [ "base", "index", "mem" ], latency => 5, emit => ". fldcw %AM", mode => $mode_fpcw, @@ -944,6 +1133,7 @@ FnstCW => { op_flags => "L|F", state => "pinned", reg_req => { in => [ "gp", "gp", "fp_cw", "none" ], out => [ "none" ] }, + ins => [ "base", "index", "fpcw", "mem" ], latency => 5, emit => ". fnstcw %AM", mode => "mode_M", @@ -996,7 +1186,7 @@ Store => { state => "exc_pinned", reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "none" ] }, ins => [ "base", "index", "val", "mem" ], - emit => '. mov%M %binop', + emit => '. mov%M %SI2, %AM', latency => 2, units => [ "GP" ], mode => "mode_M", @@ -1006,7 +1196,7 @@ Store8Bit => { op_flags => "L|F", state => "exc_pinned", reg_req => { in => [ "gp", "gp", "eax ebx ecx edx", "none" ], out => ["none" ] }, - emit => '. mov%M %binop', + emit => '. mov%M %SB2, %AM', latency => 2, units => [ "GP" ], mode => "mode_M", @@ -1015,6 +1205,7 @@ Store8Bit => { Lea => { irn_flags => "R", reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] }, + ins => [ "base", "index" ], emit => '. leal %AM, %D0', latency => 2, units => [ "GP" ], @@ -1027,6 +1218,7 @@ Push => { emit => '. push%M %unop2', ins => [ "base", "index", "val", "stack", "mem" ], outs => [ "stack:I|S", "M" ], + init_attr => "set_ia32_am_support(res, ia32_am_Source, ia32_am_binary);", latency => 2, units => [ "GP" ], modified_flags => [], @@ -1037,6 +1229,7 @@ Pop => { emit => '. pop%M %DAM1', outs => [ "stack:I|S", "res", "M" ], ins => [ "base", "index", "stack", "mem" ], + init_attr => "set_ia32_am_support(res, ia32_am_Dest, ia32_am_unary);", latency => 3, # Pop is more expensive than Push on Athlon units => [ "GP" ], modified_flags => [], @@ -1062,6 +1255,7 @@ AddSP => { irn_flags => "I", state => "pinned", reg_req => { in => [ "gp", "gp", "esp", "gp", "none" ], out => [ "in_r3", "none" ] }, + init_attr => "set_ia32_am_support(res, ia32_am_Source, ia32_am_binary);", emit => '. addl %binop', outs => [ "stack:S", "M" ], units => [ "GP" ], @@ -1072,6 +1266,7 @@ SubSP => { #irn_flags => "I", state => "pinned", reg_req => { in => [ "gp", "gp", "esp", "gp", "none" ], out => [ "in_r3", "gp", "none" ] }, + init_attr => "set_ia32_am_support(res, ia32_am_Source, ia32_am_binary);", emit => ". subl %binop\n". ". movl %%esp, %D1", outs => [ "stack:I|S", "addr", "M" ], @@ -1087,11 +1282,9 @@ LdTls => { # the int instruction int => { - reg_req => { in => [ "none" ], out => [ "none" ] }, + reg_req => { in => [ "gp" ], out => [ "none" ] }, mode => "mode_M", - attr => "tarval *tv", - init_attr => "\tset_ia32_Immop_tarval(res, tv);", - emit => '. int %C', + emit => '. int %SI0', units => [ "GP" ], cmp_attr => "return 1;", }, @@ -1209,7 +1402,7 @@ xCmp => { mode => "mode_E", }, -xCondJmp => { +xCmpJmp => { state => "pinned", op_flags => "L|X|Y", reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "none", "none" ] }, @@ -1221,16 +1414,6 @@ xCondJmp => { units => [ "SSE" ], }, -xConst => { - op_flags => "c", - irn_flags => "R", - reg_req => { out => [ "xmm" ] }, - emit => '. mov%XXM %C, %D0', - latency => 2, - units => [ "SSE" ], - mode => "mode_E", -}, - # Load / Store xLoad => { @@ -1238,6 +1421,8 @@ xLoad => { state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none" ], out => [ "xmm", "none" ] }, emit => '. mov%XXM %AM, %D0', + attr => "ir_mode *load_mode", + init_attr => "attr->ls_mode = load_mode;", outs => [ "res", "M" ], latency => 2, units => [ "SSE" ], @@ -1371,6 +1556,17 @@ CmpCMov => { mode => $mode_gp, }, +CmpCMov8Bit => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "gp", "gp", "none", "gp", "gp" ], out => [ "in_r7" ] }, + ins => [ "base", "index", "cmp_left", "cmp_right", "mem", "val_true", "val_false" ], + attr => "pn_Cmp pn_code", + init_attr => "attr->pn_code = pn_code;", + latency => 2, + units => [ "GP" ], + mode => $mode_gp, +}, + TestCMov => { irn_flags => "R", reg_req => { in => [ "gp", "gp", "gp", "gp", "none", "gp", "gp" ], @@ -1384,6 +1580,19 @@ TestCMov => { mode => $mode_gp, }, +TestCMov8Bit => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "gp", "gp", "none", "gp", "gp" ], + out => [ "in_r7" ] }, + ins => [ "base", "index", "cmp_left", "cmp_right", "mem", "val_true", + "val_false" ], + attr => "pn_Cmp pn_code", + init_attr => "attr->pn_code = pn_code;", + latency => 2, + units => [ "GP" ], + mode => $mode_gp, +}, + xCmpCMov => { irn_flags => "R", reg_req => { in => [ "xmm", "xmm", "gp", "gp" ], out => [ "in_r4" ] }, @@ -1416,6 +1625,19 @@ CmpSet => { mode => $mode_gp, }, +CmpSet8Bit => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "eax ebx ecx edx", "eax ebx ecx edx", + "none" ], + out => [ "eax ebx ecx edx" ] }, + ins => [ "base", "index", "cmp_left", "cmp_right", "mem" ], + attr => "pn_Cmp pn_code", + init_attr => "attr->pn_code = pn_code;", + latency => 2, + units => [ "GP" ], + mode => $mode_gp, +}, + TestSet => { irn_flags => "R", reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], @@ -1428,6 +1650,19 @@ TestSet => { mode => $mode_gp, }, +TestSet8Bit => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "eax ebx ecx edx", "eax ebx ecx edx", + "none" ], + out => [ "eax ebx ecx edx" ] }, + ins => [ "base", "index", "cmp_left", "cmp_right", "mem" ], + attr => "pn_Cmp pn_code", + init_attr => "attr->pn_code = pn_code;", + latency => 2, + units => [ "GP" ], + mode => $mode_gp, +}, + xCmpSet => { irn_flags => "R", reg_req => { in => [ "gp", "gp", "xmm", "xmm", "none" ], out => [ "eax ebx ecx edx" ] }, @@ -1566,8 +1801,8 @@ vfld => { reg_req => { in => [ "gp", "gp", "none" ], out => [ "vfp", "none" ] }, ins => [ "base", "index", "mem" ], outs => [ "res", "M" ], - attr => "ir_mode *store_mode", - init_attr => "attr->attr.ls_mode = store_mode;", + attr => "ir_mode *load_mode", + init_attr => "attr->attr.ls_mode = load_mode;", latency => 2, units => [ "VFP" ], attr_type => "ia32_x87_attr_t", @@ -1687,19 +1922,9 @@ vfldl2e => { attr_type => "ia32_x87_attr_t", }, -vfConst => { - op_flags => "c", - irn_flags => "R", - reg_req => { out => [ "vfp" ] }, - latency => 3, - units => [ "VFP" ], - mode => "mode_E", - attr_type => "ia32_x87_attr_t", -}, - # other -vfCondJmp => { +vfCmpJmp => { state => "pinned", op_flags => "L|X|Y", reg_req => { in => [ "vfp", "vfp" ], out => [ "none", "none", "eax" ] }, diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index c6f8e02dd..b864b6eea 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -47,6 +47,7 @@ #include "irdom.h" #include "archop.h" #include "error.h" +#include "height.h" #include "../benode_t.h" #include "../besched.h" @@ -63,6 +64,7 @@ #include "ia32_dbg_stat.h" #include "ia32_optimize.h" #include "ia32_util.h" +#include "ia32_address_mode.h" #include "gen_ia32_regalloc_if.h" @@ -89,6 +91,7 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;) /** hold the current code generator during transformation */ static ia32_code_gen_t *env_cg = NULL; static ir_node *initial_fpcw = NULL; +static heights_t *heights = NULL; extern ir_op *get_op_Mulh(void); @@ -96,13 +99,22 @@ typedef ir_node *construct_binop_func(dbg_info *db, ir_graph *irg, ir_node *block, ir_node *base, ir_node *index, ir_node *op1, ir_node *op2, ir_node *mem); +typedef ir_node *construct_shift_func(dbg_info *db, ir_graph *irg, + ir_node *block, ir_node *op1, ir_node *op2); + +typedef ir_node *construct_binop_dest_func(dbg_info *db, ir_graph *irg, + ir_node *block, ir_node *base, ir_node *index, ir_node *op, + ir_node *mem); + +typedef ir_node *construct_unop_dest_func(dbg_info *db, ir_graph *irg, + ir_node *block, ir_node *base, ir_node *index, ir_node *mem); + typedef ir_node *construct_binop_float_func(dbg_info *db, ir_graph *irg, ir_node *block, ir_node *base, ir_node *index, ir_node *op1, ir_node *op2, ir_node *mem, ir_node *fpcw); typedef ir_node *construct_unop_func(dbg_info *db, ir_graph *irg, - ir_node *block, ir_node *base, ir_node *index, ir_node *op, - ir_node *mem); + ir_node *block, ir_node *op); /**************************************************************************************************** * _ _ __ _ _ @@ -133,52 +145,6 @@ static INLINE int mode_needs_gp_reg(ir_mode *mode) { return mode_is_int(mode) || mode_is_reference(mode) || mode == mode_b; } -/** - * Returns 1 if irn is a Const representing 0, 0 otherwise - */ -static INLINE int is_ia32_Const_0(ir_node *irn) { - return is_ia32_irn(irn) && is_ia32_Const(irn) && get_ia32_immop_type(irn) == ia32_ImmConst - && tarval_is_null(get_ia32_Immop_tarval(irn)); -} - -/** - * Returns 1 if irn is a Const representing 1, 0 otherwise - */ -static INLINE int is_ia32_Const_1(ir_node *irn) { - return is_ia32_irn(irn) && is_ia32_Const(irn) && get_ia32_immop_type(irn) == ia32_ImmConst - && tarval_is_one(get_ia32_Immop_tarval(irn)); -} - -/** - * Collects all Projs of a node into the node array. Index is the projnum. - * BEWARE: The caller has to assure the appropriate array size! - */ -static void ia32_collect_Projs(ir_node *irn, ir_node **projs, int size) { - const ir_edge_t *edge; - assert(get_irn_mode(irn) == mode_T && "need mode_T"); - - memset(projs, 0, size * sizeof(projs[0])); - - foreach_out_edge(irn, edge) { - ir_node *proj = get_edge_src_irn(edge); - int proj_proj = get_Proj_proj(proj); - assert(proj_proj < size); - projs[proj_proj] = proj; - } -} - -/** - * Renumbers the proj having pn_old in the array tp pn_new - * and removes the proj from the array. - */ -static INLINE void ia32_renumber_Proj(ir_node **projs, long pn_old, long pn_new) { - fprintf(stderr, "Warning: renumber_Proj used!\n"); - if (projs[pn_old]) { - set_Proj_proj(projs[pn_old], pn_new); - projs[pn_old] = NULL; - } -} - /** * creates a unique ident by adding a number to a tag * @@ -266,15 +232,26 @@ static int is_Const_1(ir_node *node) { return classify_Const(node) == CNST_ONE; } +static int is_Const_Minus_1(ir_node *node) { + tarval *tv; + if(!is_Const(node)) + return 0; + + tv = get_Const_tarval(node); + tv = tarval_neg(tv); + + return classify_tarval(tv) == CNST_ONE; +} + /** * Transforms a Const. */ static ir_node *gen_Const(ir_node *node) { - ir_graph *irg = current_ir_graph; - ir_node *old_block = get_nodes_block(node); - ir_node *block = be_transform_node(old_block); - dbg_info *dbgi = get_irn_dbg_info(node); - ir_mode *mode = get_irn_mode(node); + ir_graph *irg = current_ir_graph; + ir_node *old_block = get_nodes_block(node); + ir_node *block = be_transform_node(old_block); + dbg_info *dbgi = get_irn_dbg_info(node); + ir_mode *mode = get_irn_mode(node); if (mode_is_float(mode)) { ir_node *res = NULL; @@ -297,7 +274,6 @@ static ir_node *gen_Const(ir_node *node) { load = new_rd_ia32_vfld(dbgi, irg, block, noreg, noreg, nomem, mode); set_ia32_op_type(load, ia32_AddrModeS); - set_ia32_am_flavour(load, ia32_am_N); set_ia32_am_sc(load, floatent); set_ia32_flags(load, get_ia32_flags(load) | arch_irn_flags_rematerializable); res = new_r_Proj(irg, block, load, mode_vfp, pn_ia32_vfld_res); @@ -306,11 +282,10 @@ static ir_node *gen_Const(ir_node *node) { } else { floatent = get_entity_for_tv(env_cg, node); - load = new_rd_ia32_xLoad(dbgi, irg, block, noreg, noreg, nomem); + load = new_rd_ia32_xLoad(dbgi, irg, block, noreg, noreg, nomem, + mode); set_ia32_op_type(load, ia32_AddrModeS); - set_ia32_am_flavour(load, ia32_am_N); set_ia32_am_sc(load, floatent); - set_ia32_ls_mode(load, mode); set_ia32_flags(load, get_ia32_flags(load) | arch_irn_flags_rematerializable); res = new_r_Proj(irg, block, load, mode_xmm, pn_ia32_xLoad_res); @@ -330,20 +305,28 @@ static ir_node *gen_Const(ir_node *node) { SET_IA32_ORIG_NODE(load, ia32_get_old_node_name(env_cg, node)); return res; } else { - ir_node *cnst = new_rd_ia32_Const(dbgi, irg, block); + ir_node *cnst; + tarval *tv = get_Const_tarval(node); + long val; + + tv = tarval_convert_to(tv, mode_Iu); + + if(tv == get_tarval_bad() || tv == get_tarval_undefined() + || tv == NULL) { + panic("couldn't convert constant tarval (%+F)", node); + } + val = get_tarval_long(tv); + + cnst = new_rd_ia32_Const(dbgi, irg, block, NULL, 0, val); + SET_IA32_ORIG_NODE(cnst, ia32_get_old_node_name(env_cg, node)); /* see above */ if (get_irg_start_block(irg) == block) { add_irn_dep(cnst, get_irg_frame(irg)); } - set_ia32_Const_attr(cnst, node); - SET_IA32_ORIG_NODE(cnst, ia32_get_old_node_name(env_cg, node)); return cnst; } - - assert(0); - return new_r_Bad(irg); } /** @@ -358,14 +341,20 @@ static ir_node *gen_SymConst(ir_node *node) { ir_node *cnst; if (mode_is_float(mode)) { + ir_node *noreg = ia32_new_NoReg_gp(env_cg); + ir_node *nomem = new_NoMem(); + if (USE_SSE2(env_cg)) - cnst = new_rd_ia32_xConst(dbgi, irg, block); + cnst = new_rd_ia32_xLoad(dbgi, irg, block, noreg, noreg, nomem, mode_E); else - cnst = new_rd_ia32_vfConst(dbgi, irg, block); - //set_ia32_ls_mode(cnst, mode); - set_ia32_ls_mode(cnst, mode_E); + cnst = new_rd_ia32_vfld(dbgi, irg, block, noreg, noreg, nomem, mode_E); + set_ia32_am_sc(cnst, get_SymConst_entity(node)); } else { - cnst = new_rd_ia32_Const(dbgi, irg, block); + if(get_SymConst_kind(node) != symconst_addr_ent) { + panic("backend only support symconst_addr_ent (at %+F)", node); + } + ir_entity *entity = get_SymConst_entity(node); + cnst = new_rd_ia32_Const(dbgi, irg, block, entity, 0, 0); } /* Const Nodes before the initial IncSP are a bad idea, because @@ -375,7 +364,6 @@ static ir_node *gen_SymConst(ir_node *node) { add_irn_dep(cnst, get_irg_frame(irg)); } - set_ia32_Const_attr(cnst, node); SET_IA32_ORIG_NODE(cnst, ia32_get_old_node_name(env_cg, node)); return cnst; @@ -448,47 +436,176 @@ const char *ia32_get_old_node_name(ia32_code_gen_t *cg, ir_node *irn) { } #endif /* NDEBUG */ -/* determine if one operator is an Imm */ -static ir_node *get_immediate_op(ir_node *op1, ir_node *op2) { - if (op1) { - return is_ia32_Cnst(op1) ? op1 : (is_ia32_Cnst(op2) ? op2 : NULL); +static int use_source_address_mode(ir_node *block, ir_node *node, + ir_node *other) +{ + ir_mode *mode; + ir_node *load; + long pn; + + if(!is_Proj(node)) + return 0; + load = get_Proj_pred(node); + pn = get_Proj_proj(node); + if(!is_Load(load) || pn != pn_Load_res) + return 0; + if(get_nodes_block(load) != block) + return 0; + /* we only use address mode if we're the only user of the load */ + if(get_irn_n_edges(node) > 1) + return 0; + + mode = get_irn_mode(node); + if(!mode_needs_gp_reg(mode)) + return 0; + if(get_mode_size_bits(mode) != 32) + return 0; + + /* don't do AM if other node inputs depend on the load (via mem-proj) */ + if(other != NULL && get_nodes_block(other) == block + && heights_reachable_in_block(heights, other, load)) + return 0; + + return 1; +} + +typedef struct ia32_address_mode_t ia32_address_mode_t; +struct ia32_address_mode_t { + ia32_address_t addr; + ir_mode *ls_mode; + ir_node *mem_proj; + ia32_op_type_t op_type; + ir_node *new_op1; + ir_node *new_op2; + int commutative; + int flipped; +}; + +static void build_address(ia32_address_mode_t *am, ir_node *node) +{ + ia32_address_t *addr = &am->addr; + ir_node *load = get_Proj_pred(node); + ir_node *ptr = get_Load_ptr(load); + ir_node *mem = get_Load_mem(load); + ir_node *new_mem = be_transform_node(mem); + ir_node *base; + ir_node *index; + + am->ls_mode = get_Load_mode(load); + am->mem_proj = be_get_Proj_for_pn(load, pn_Load_M); + + /* construct load address */ + ia32_create_address_mode(addr, ptr, 0); + base = addr->base; + index = addr->index; + + if(base == NULL) { + base = ia32_new_NoReg_gp(env_cg); + } else { + base = be_transform_node(base); + } + + if(index == NULL) { + index = ia32_new_NoReg_gp(env_cg); } else { - return is_ia32_Cnst(op2) ? op2 : NULL; + index = be_transform_node(index); } + + addr->base = base; + addr->index = index; + addr->mem = new_mem; } -/* determine if one operator is not an Imm */ -static ir_node *get_expr_op(ir_node *op1, ir_node *op2) { - return !is_ia32_Cnst(op1) ? op1 : (!is_ia32_Cnst(op2) ? op2 : NULL); +static void set_address(ir_node *node, ia32_address_t *addr) +{ + set_ia32_am_scale(node, addr->scale); + set_ia32_am_sc(node, addr->symconst_ent); + set_ia32_am_offs_int(node, addr->offset); + if(addr->symconst_sign) + set_ia32_am_sc_sign(node); + if(addr->use_frame) + set_ia32_use_frame(node); + set_ia32_frame_ent(node, addr->frame_entity); } -static void fold_immediate(ir_node *node, int in1, int in2) { - ir_node *left; - ir_node *right; +static void set_am_attributes(ir_node *node, ia32_address_mode_t *am) +{ + set_address(node, &am->addr); - if (!(env_cg->opt & IA32_OPT_IMMOPS)) - return; + set_ia32_op_type(node, am->op_type); + set_ia32_ls_mode(node, am->ls_mode); + if(am->commutative) + set_ia32_commutative(node); +} - left = get_irn_n(node, in1); - right = get_irn_n(node, in2); - if (! is_ia32_Cnst(right) && is_ia32_Cnst(left)) { - /* we can only set right operand to immediate */ - if(!is_ia32_commutative(node)) - return; - /* exchange left/right */ - set_irn_n(node, in1, right); - set_irn_n(node, in2, ia32_get_admissible_noreg(env_cg, node, in2)); - copy_ia32_Immop_attr(node, left); - } else if(is_ia32_Cnst(right)) { - set_irn_n(node, in2, ia32_get_admissible_noreg(env_cg, node, in2)); - copy_ia32_Immop_attr(node, right); +static void match_arguments(ia32_address_mode_t *am, ir_node *block, + ir_node *op1, ir_node *op2, int commutative, + int use_am_and_immediates) +{ + ia32_address_t *addr = &am->addr; + ir_node *noreg_gp = ia32_new_NoReg_gp(env_cg); + ir_node *new_op1; + ir_node *new_op2; + + memset(am, 0, sizeof(am[0])); + + new_op2 = try_create_Immediate(op2, 0); + if(new_op2 == NULL && use_source_address_mode(block, op2, op1)) { + build_address(am, op2); + new_op1 = be_transform_node(op1); + new_op2 = noreg_gp; + am->op_type = ia32_AddrModeS; + } else if(commutative && (new_op2 == NULL || use_am_and_immediates) && + use_source_address_mode(block, op1, op2)) { + build_address(am, op1); + if(new_op2 != NULL) { + new_op1 = noreg_gp; + } else { + new_op1 = be_transform_node(op2); + new_op2 = noreg_gp; + am->flipped = 1; + } + am->op_type = ia32_AddrModeS; } else { - return; + new_op1 = be_transform_node(op1); + if(new_op2 == NULL) + new_op2 = be_transform_node(op2); + am->op_type = ia32_Normal; } + if(addr->base == NULL) + addr->base = noreg_gp; + if(addr->index == NULL) + addr->index = noreg_gp; + if(addr->mem == NULL) + addr->mem = new_NoMem(); + + am->new_op1 = new_op1; + am->new_op2 = new_op2; + am->commutative = commutative; +} + +static ir_node *fix_mem_proj(ir_node *node, ia32_address_mode_t *am) +{ + ir_graph *irg = current_ir_graph; + ir_mode *mode; + ir_node *load; - clear_ia32_commutative(node); - set_ia32_am_support(node, get_ia32_am_support(node) & ~ia32_am_Source, - get_ia32_am_arity(node)); + if(am->mem_proj == NULL) + return node; + + /* we have to create a mode_T so the old MemProj can attach to us */ + mode = get_irn_mode(node); + load = get_Proj_pred(am->mem_proj); + + mark_irn_visited(load); + be_set_transformed_node(load, node); + + if(mode != mode_T) { + set_irn_mode(node, mode_T); + return new_rd_Proj(NULL, irg, get_nodes_block(node), node, mode, 0); + } else { + return node; + } } /** @@ -502,30 +619,25 @@ static void fold_immediate(ir_node *node, int in1, int in2) { static ir_node *gen_binop(ir_node *node, ir_node *op1, ir_node *op2, construct_binop_func *func, int commutative) { - ir_node *block = be_transform_node(get_nodes_block(node)); - ir_graph *irg = current_ir_graph; - dbg_info *dbgi = get_irn_dbg_info(node); - ir_node *noreg_gp = ia32_new_NoReg_gp(env_cg); - ir_node *nomem = new_NoMem(); + ir_node *src_block = get_nodes_block(node); + ir_node *block = be_transform_node(src_block); + ir_graph *irg = current_ir_graph; + dbg_info *dbgi = get_irn_dbg_info(node); ir_node *new_node; + ia32_address_mode_t am; + ia32_address_t *addr = &am.addr; - ir_node *new_op1 = be_transform_node(op1); - ir_node *new_op2 = create_immediate_or_transform(op2, 0); - if (is_ia32_Immediate(new_op2)) { - commutative = 0; - } - - new_node = func(dbgi, irg, block, noreg_gp, noreg_gp, new_op1, new_op2, nomem); - if (func == new_rd_ia32_IMul) { - set_ia32_am_support(new_node, ia32_am_Source, ia32_am_binary); - } else { - set_ia32_am_support(new_node, ia32_am_Full, ia32_am_binary); - } + match_arguments(&am, src_block, op1, op2, commutative, 0); + new_node = func(dbgi, irg, block, addr->base, addr->index, am.new_op1, + am.new_op2, addr->mem); + set_am_attributes(new_node, &am); + /* we can't use source address mode anymore when using immediates */ + if(is_ia32_Immediate(am.new_op1) || is_ia32_Immediate(am.new_op2)) + set_ia32_am_support(new_node, ia32_am_None, ia32_am_arity_none); SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node)); - if (commutative) { - set_ia32_commutative(new_node); - } + + new_node = fix_mem_proj(new_node, &am); return new_node; } @@ -553,7 +665,6 @@ static ir_node *gen_binop_sse_float(ir_node *node, ir_node *op1, ir_node *op2, new_node = func(dbgi, irg, block, noreg_gp, noreg_gp, new_op1, new_op2, nomem); - set_ia32_am_support(new_node, ia32_am_Source, ia32_am_binary); if (is_op_commutative(get_irn_op(node))) { set_ia32_commutative(new_node); } @@ -599,7 +710,6 @@ static ir_node *gen_binop_x87_float(ir_node *node, ir_node *op1, ir_node *op2, new_node = func(dbgi, irg, block, noreg_gp, noreg_gp, new_op1, new_op2, nomem, get_fpcw()); - set_ia32_am_support(new_node, ia32_am_Source, ia32_am_binary); if (is_op_commutative(get_irn_op(node))) { set_ia32_commutative(new_node); } @@ -618,39 +728,30 @@ static ir_node *gen_binop_x87_float(ir_node *node, ir_node *op1, ir_node *op2, * @return The constructed ia32 node. */ static ir_node *gen_shift_binop(ir_node *node, ir_node *op1, ir_node *op2, - construct_binop_func *func) + construct_shift_func *func) { - ir_node *block = be_transform_node(get_nodes_block(node)); - ir_node *new_op1 = be_transform_node(op1); - ir_node *new_op2; - ir_node *new_op = NULL; - dbg_info *dbgi = get_irn_dbg_info(node); - ir_graph *irg = current_ir_graph; - ir_node *noreg = ia32_new_NoReg_gp(env_cg); - ir_node *nomem = new_NoMem(); + dbg_info *dbgi = get_irn_dbg_info(node); + ir_graph *irg = current_ir_graph; + ir_node *block = get_nodes_block(node); + ir_node *new_block = be_transform_node(block); + ir_node *new_op1 = be_transform_node(op1); + ir_node *new_op2 = create_immediate_or_transform(op2, 0); + ir_node *res; assert(! mode_is_float(get_irn_mode(node)) && "Shift/Rotate with float not supported"); - new_op2 = create_immediate_or_transform(op2, 'N'); - - new_op = func(dbgi, irg, block, noreg, noreg, new_op1, new_op2, nomem); - - /* set AM support */ - set_ia32_am_support(new_op, ia32_am_Dest, ia32_am_binary); - - SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); - - set_ia32_emit_cl(new_op); + res = func(dbgi, irg, new_block, new_op1, new_op2); + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); /* lowered shift instruction may have a dependency operand, handle it here */ if (get_irn_arity(node) == 3) { /* we have a dependency */ ir_node *new_dep = be_transform_node(get_irn_n(node, 2)); - add_irn_dep(new_op, new_dep); + add_irn_dep(res, new_dep); } - return new_op; + return res; } @@ -668,18 +769,46 @@ static ir_node *gen_unop(ir_node *node, ir_node *op, construct_unop_func *func) ir_node *new_node = NULL; ir_graph *irg = current_ir_graph; dbg_info *dbgi = get_irn_dbg_info(node); - ir_node *noreg = ia32_new_NoReg_gp(env_cg); - ir_node *nomem = new_NoMem(); - new_node = func(dbgi, irg, block, noreg, noreg, new_op, nomem); - DB((dbg, LEVEL_1, "INT unop ...")); - set_ia32_am_support(new_node, ia32_am_Dest, ia32_am_unary); + new_node = func(dbgi, irg, block, new_op); SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node)); return new_node; } +static ir_node *create_lea_from_address(dbg_info *dbgi, ir_node *block, + ia32_address_t *addr) +{ + ir_graph *irg = current_ir_graph; + ir_node *base = addr->base; + ir_node *index = addr->index; + ir_node *res; + + if(base == NULL) { + base = ia32_new_NoReg_gp(env_cg); + } else { + base = be_transform_node(base); + } + + if(index == NULL) { + index = ia32_new_NoReg_gp(env_cg); + } else { + index = be_transform_node(index); + } + + res = new_rd_ia32_Lea(dbgi, irg, block, base, index); + set_address(res, addr); + + return res; +} + +static int am_has_immediates(const ia32_address_t *addr) +{ + return addr->offset != 0 || addr->symconst_ent != NULL + || addr->frame_entity || addr->use_frame; +} + /** * Creates an ia32 Add. * @@ -688,23 +817,17 @@ static ir_node *gen_unop(ir_node *node, ir_node *op, construct_unop_func *func) static ir_node *gen_Add(ir_node *node) { ir_node *block = be_transform_node(get_nodes_block(node)); ir_node *op1 = get_Add_left(node); - ir_node *new_op1 = be_transform_node(op1); ir_node *op2 = get_Add_right(node); - ir_node *new_op2 = be_transform_node(op2); - ir_node *new_op = NULL; + ir_node *new_op; + ir_node *new_op1; ir_graph *irg = current_ir_graph; dbg_info *dbgi = get_irn_dbg_info(node); ir_mode *mode = get_irn_mode(node); ir_node *noreg = ia32_new_NoReg_gp(env_cg); - ir_node *nomem = new_NoMem(); - ir_node *expr_op, *imm_op; - - /* Check if immediate optimization is on and */ - /* if it's an operation with immediate. */ - imm_op = (env_cg->opt & IA32_OPT_IMMOPS) ? get_immediate_op(new_op1, new_op2) : NULL; - expr_op = get_expr_op(new_op1, new_op2); - - assert((expr_op || imm_op) && "invalid operands"); + ir_node *src_block = get_nodes_block(node); + ir_node *add_immediate_op; + ia32_address_t addr; + ia32_address_mode_t am; if (mode_is_float(mode)) { if (USE_SSE2(env_cg)) @@ -713,99 +836,90 @@ static ir_node *gen_Add(ir_node *node) { return gen_binop_x87_float(node, op1, op2, new_rd_ia32_vfadd); } - /* integer ADD */ - if (! expr_op) { - ia32_immop_type_t tp1 = get_ia32_immop_type(new_op1); - ia32_immop_type_t tp2 = get_ia32_immop_type(new_op2); - - /* No expr_op means, that we have two const - one symconst and */ - /* one tarval or another symconst - because this case is not */ - /* covered by constant folding */ - /* We need to check for: */ - /* 1) symconst + const -> becomes a LEA */ - /* 2) symconst + symconst -> becomes a const + LEA as the elf */ - /* linker doesn't support two symconsts */ - - if (tp1 == ia32_ImmSymConst && tp2 == ia32_ImmSymConst) { - /* this is the 2nd case */ - new_op = new_rd_ia32_Lea(dbgi, irg, block, new_op1, noreg); - set_ia32_am_sc(new_op, get_ia32_Immop_symconst(new_op2)); - set_ia32_am_flavour(new_op, ia32_am_B); - set_ia32_op_type(new_op, ia32_AddrModeS); - - DBG_OPT_LEA3(new_op1, new_op2, node, new_op); - } else if (tp1 == ia32_ImmSymConst) { - tarval *tv = get_ia32_Immop_tarval(new_op2); - long offs = get_tarval_long(tv); - - new_op = new_rd_ia32_Lea(dbgi, irg, block, noreg, noreg); - add_irn_dep(new_op, get_irg_frame(irg)); - DBG_OPT_LEA3(new_op1, new_op2, node, new_op); - - set_ia32_am_sc(new_op, get_ia32_Immop_symconst(new_op1)); - add_ia32_am_offs_int(new_op, offs); - set_ia32_am_flavour(new_op, ia32_am_OB); - set_ia32_op_type(new_op, ia32_AddrModeS); - } else if (tp2 == ia32_ImmSymConst) { - tarval *tv = get_ia32_Immop_tarval(new_op1); - long offs = get_tarval_long(tv); - - new_op = new_rd_ia32_Lea(dbgi, irg, block, noreg, noreg); - add_irn_dep(new_op, get_irg_frame(irg)); - DBG_OPT_LEA3(new_op1, new_op2, node, new_op); - - add_ia32_am_offs_int(new_op, offs); - set_ia32_am_sc(new_op, get_ia32_Immop_symconst(new_op2)); - set_ia32_am_flavour(new_op, ia32_am_OB); - set_ia32_op_type(new_op, ia32_AddrModeS); - } else { - tarval *tv1 = get_ia32_Immop_tarval(new_op1); - tarval *tv2 = get_ia32_Immop_tarval(new_op2); - tarval *restv = tarval_add(tv1, tv2); - - DEBUG_ONLY(ir_fprintf(stderr, "Warning: add with 2 consts not folded: %+F\n", node)); - - new_op = new_rd_ia32_Const(dbgi, irg, block); - set_ia32_Const_tarval(new_op, restv); - DBG_OPT_LEA3(new_op1, new_op2, node, new_op); - } - + /** + * Rules for an Add: + * 0. Immediate Trees (example Add(Symconst, Const) -> Const) + * 1. Add with immediate -> Lea + * 2. Add with possible source address mode -> Add + * 3. Otherwise -> Lea + */ + memset(&addr, 0, sizeof(addr)); + ia32_create_address_mode(&addr, node, 1); + add_immediate_op = NULL; + /* a constant? */ + if(addr.base == NULL && addr.index == NULL) { + new_op = new_rd_ia32_Const(dbgi, irg, block, addr.symconst_ent, + addr.symconst_sign, addr.offset); + add_irn_dep(new_op, get_irg_frame(irg)); SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); return new_op; - } else if (imm_op) { - if ((env_cg->opt & IA32_OPT_INCDEC) && get_ia32_immop_type(imm_op) == ia32_ImmConst) { - tarval_classification_t class_tv, class_negtv; - tarval *tv = get_ia32_Immop_tarval(imm_op); - - /* optimize tarvals */ - class_tv = classify_tarval(tv); - class_negtv = classify_tarval(tarval_neg(tv)); - - if (class_tv == TV_CLASSIFY_ONE) { /* + 1 == INC */ - DB((dbg, LEVEL_2, "Add(1) to Inc ... ")); - new_op = new_rd_ia32_Inc(dbgi, irg, block, noreg, noreg, expr_op, nomem); - SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); + } + /* add with immediate? */ + if(addr.index == NULL) { + add_immediate_op = addr.base; + } else if(addr.base == NULL && addr.scale == 0) { + add_immediate_op = addr.index; + } + + if(add_immediate_op != NULL) { + if(!am_has_immediates(&addr)) { +#ifdef DEBUG_libfirm + ir_fprintf(stderr, "Optimisation warning Add x,0 (%+F) found\n", + node); +#endif + return be_transform_node(add_immediate_op); + } + if(env_cg->isa->opt & IA32_OPT_INCDEC + && addr.symconst_ent == NULL) { + if(addr.offset == 1) { + ir_node *new_op = be_transform_node(add_immediate_op); + new_op = new_rd_ia32_Inc(dbgi, irg, block, new_op); + SET_IA32_ORIG_NODE(new_op, + ia32_get_old_node_name(env_cg, node)); return new_op; - } else if (class_tv == TV_CLASSIFY_ALL_ONE || class_negtv == TV_CLASSIFY_ONE) { /* + (-1) == DEC */ - DB((dbg, LEVEL_2, "Add(-1) to Dec ... ")); - new_op = new_rd_ia32_Dec(dbgi, irg, block, noreg, noreg, expr_op, nomem); - SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); + } else if(addr.offset == -1) { + ir_node *new_op = be_transform_node(add_immediate_op); + new_op = new_rd_ia32_Dec(dbgi, irg, block, new_op); + SET_IA32_ORIG_NODE(new_op, + ia32_get_old_node_name(env_cg, node)); return new_op; } } + + new_op = create_lea_from_address(dbgi, block, &addr); + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); + return new_op; } - /* This is a normal add */ - new_op = new_rd_ia32_Add(dbgi, irg, block, noreg, noreg, new_op1, new_op2, nomem); + /* test if we can use source address mode */ + memset(&am, 0, sizeof(am)); + new_op1 = NULL; + if(use_source_address_mode(src_block, op2, op1)) { + build_address(&am, op2); + new_op1 = be_transform_node(op1); + } else if(use_source_address_mode(src_block, op1, op2)) { + build_address(&am, op1); + new_op1 = be_transform_node(op2); + } + /* construct an Add with source address mode */ + if(new_op1 != NULL) { + ia32_address_t *am_addr = &am.addr; + new_op = new_rd_ia32_Add(dbgi, irg, block, am_addr->base, + am_addr->index, new_op1, noreg, am_addr->mem); + set_address(new_op, am_addr); + set_ia32_op_type(new_op, ia32_AddrModeS); + set_ia32_ls_mode(new_op, am.ls_mode); + set_ia32_commutative(new_op); + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); - /* set AM support */ - set_ia32_am_support(new_op, ia32_am_Full, ia32_am_binary); - set_ia32_commutative(new_op); + new_op = fix_mem_proj(new_op, &am); - fold_immediate(new_op, 2, 3); + return new_op; + } + /* otherwise construct a lea */ + new_op = create_lea_from_address(dbgi, block, &addr); SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); - return new_op; } @@ -863,7 +977,6 @@ static ir_node *gen_Mulh(ir_node *node) { } set_ia32_commutative(res); - set_ia32_am_support(res, ia32_am_Source, ia32_am_binary); proj_EDX = new_rd_Proj(dbgi, irg, block, res, mode_Iu, pn_EDX); @@ -882,7 +995,7 @@ static ir_node *gen_And(ir_node *node) { ir_node *op2 = get_And_right(node); assert(! mode_is_float(get_irn_mode(node))); - /* check for zero extension first */ + /* is it a zero extension? */ if (is_Const(op2)) { tarval *tv = get_Const_tarval(op2); long v = get_tarval_long(tv); @@ -947,25 +1060,9 @@ static ir_node *gen_Eor(ir_node *node) { * @return The created ia32 Sub node */ static ir_node *gen_Sub(ir_node *node) { - ir_node *block = be_transform_node(get_nodes_block(node)); - ir_node *op1 = get_Sub_left(node); - ir_node *new_op1 = be_transform_node(op1); - ir_node *op2 = get_Sub_right(node); - ir_node *new_op2 = be_transform_node(op2); - ir_node *new_op = NULL; - ir_graph *irg = current_ir_graph; - dbg_info *dbgi = get_irn_dbg_info(node); - ir_mode *mode = get_irn_mode(node); - ir_node *noreg = ia32_new_NoReg_gp(env_cg); - ir_node *nomem = new_NoMem(); - ir_node *expr_op, *imm_op; - - /* Check if immediate optimization is on and */ - /* if it's an operation with immediate. */ - imm_op = (env_cg->opt & IA32_OPT_IMMOPS) ? get_immediate_op(NULL, new_op2) : NULL; - expr_op = get_expr_op(new_op1, new_op2); - - assert((expr_op || imm_op) && "invalid operands"); + ir_node *op1 = get_Sub_left(node); + ir_node *op2 = get_Sub_right(node); + ir_mode *mode = get_irn_mode(node); if (mode_is_float(mode)) { if (USE_SSE2(env_cg)) @@ -974,99 +1071,7 @@ static ir_node *gen_Sub(ir_node *node) { return gen_binop_x87_float(node, op1, op2, new_rd_ia32_vfsub); } - /* integer SUB */ - if (! expr_op) { - ia32_immop_type_t tp1 = get_ia32_immop_type(new_op1); - ia32_immop_type_t tp2 = get_ia32_immop_type(new_op2); - - /* No expr_op means, that we have two const - one symconst and */ - /* one tarval or another symconst - because this case is not */ - /* covered by constant folding */ - /* We need to check for: */ - /* 1) symconst - const -> becomes a LEA */ - /* 2) symconst - symconst -> becomes a const - LEA as the elf */ - /* linker doesn't support two symconsts */ - if (tp1 == ia32_ImmSymConst && tp2 == ia32_ImmSymConst) { - /* this is the 2nd case */ - new_op = new_rd_ia32_Lea(dbgi, irg, block, new_op1, noreg); - set_ia32_am_sc(new_op, get_ia32_Immop_symconst(op2)); - set_ia32_am_sc_sign(new_op); - set_ia32_am_flavour(new_op, ia32_am_B); - - DBG_OPT_LEA3(op1, op2, node, new_op); - } else if (tp1 == ia32_ImmSymConst) { - tarval *tv = get_ia32_Immop_tarval(new_op2); - long offs = get_tarval_long(tv); - - new_op = new_rd_ia32_Lea(dbgi, irg, block, noreg, noreg); - add_irn_dep(new_op, get_irg_frame(irg)); - DBG_OPT_LEA3(op1, op2, node, new_op); - - set_ia32_am_sc(new_op, get_ia32_Immop_symconst(new_op1)); - add_ia32_am_offs_int(new_op, -offs); - set_ia32_am_flavour(new_op, ia32_am_OB); - set_ia32_op_type(new_op, ia32_AddrModeS); - } else if (tp2 == ia32_ImmSymConst) { - tarval *tv = get_ia32_Immop_tarval(new_op1); - long offs = get_tarval_long(tv); - - new_op = new_rd_ia32_Lea(dbgi, irg, block, noreg, noreg); - add_irn_dep(new_op, get_irg_frame(irg)); - DBG_OPT_LEA3(op1, op2, node, new_op); - - add_ia32_am_offs_int(new_op, offs); - set_ia32_am_sc(new_op, get_ia32_Immop_symconst(new_op2)); - set_ia32_am_sc_sign(new_op); - set_ia32_am_flavour(new_op, ia32_am_OB); - set_ia32_op_type(new_op, ia32_AddrModeS); - } else { - tarval *tv1 = get_ia32_Immop_tarval(new_op1); - tarval *tv2 = get_ia32_Immop_tarval(new_op2); - tarval *restv = tarval_sub(tv1, tv2); - - DEBUG_ONLY(ir_fprintf(stderr, "Warning: sub with 2 consts not folded: %+F\n", node)); - - new_op = new_rd_ia32_Const(dbgi, irg, block); - set_ia32_Const_tarval(new_op, restv); - DBG_OPT_LEA3(new_op1, new_op2, node, new_op); - } - - SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); - return new_op; - } else if (imm_op) { - if ((env_cg->opt & IA32_OPT_INCDEC) && get_ia32_immop_type(imm_op) == ia32_ImmConst) { - tarval_classification_t class_tv, class_negtv; - tarval *tv = get_ia32_Immop_tarval(imm_op); - - /* optimize tarvals */ - class_tv = classify_tarval(tv); - class_negtv = classify_tarval(tarval_neg(tv)); - - if (class_tv == TV_CLASSIFY_ONE) { - DB((dbg, LEVEL_2, "Sub(1) to Dec ... ")); - new_op = new_rd_ia32_Dec(dbgi, irg, block, noreg, noreg, expr_op, nomem); - SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); - return new_op; - } else if (class_tv == TV_CLASSIFY_ALL_ONE || class_negtv == TV_CLASSIFY_ONE) { - DB((dbg, LEVEL_2, "Sub(-1) to Inc ... ")); - new_op = new_rd_ia32_Inc(dbgi, irg, block, noreg, noreg, expr_op, nomem); - SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); - return new_op; - } - } - } - - /* This is a normal sub */ - new_op = new_rd_ia32_Sub(dbgi, irg, block, noreg, noreg, new_op1, new_op2, nomem); - - /* set AM support */ - set_ia32_am_support(new_op, ia32_am_Full, ia32_am_binary); - - fold_immediate(new_op, 2, 3); - - SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); - - return new_op; + return gen_binop(node, op1, op2, new_rd_ia32_Sub, 0); } @@ -1093,11 +1098,8 @@ static ir_node *generate_DivMod(ir_node *node, ir_node *dividend, ir_node *res, *proj_div, *proj_mod; ir_node *sign_extension; ir_node *mem, *new_mem; - ir_node *projs[pn_DivMod_max]; int has_exc; - ia32_collect_Projs(node, projs, pn_DivMod_max); - proj_div = proj_mod = NULL; has_exc = 0; switch (dm_flav) { @@ -1132,9 +1134,7 @@ static ir_node *generate_DivMod(ir_node *node, ir_node *dividend, sign_extension = new_rd_ia32_Cltd(dbgi, irg, block, new_dividend, produceval); } else { - sign_extension = new_rd_ia32_Const(dbgi, irg, block); - set_ia32_Immop_tarval(sign_extension, get_tarval_null(mode_Iu)); - + sign_extension = new_rd_ia32_Const(dbgi, irg, block, NULL, 0, 0); add_irn_dep(sign_extension, get_irg_frame(irg)); } @@ -1148,7 +1148,6 @@ static ir_node *generate_DivMod(ir_node *node, ir_node *dividend, set_ia32_exc_label(res, has_exc); set_irn_pinned(res, get_irn_pinned(node)); - set_ia32_am_support(res, ia32_am_Source, ia32_am_binary); SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); @@ -1203,21 +1202,12 @@ static ir_node *gen_Quot(ir_node *node) { if (USE_SSE2(env_cg)) { ir_mode *mode = get_irn_mode(op1); - if (is_ia32_xConst(new_op2)) { - new_op = new_rd_ia32_xDiv(dbgi, irg, block, noreg, noreg, new_op1, noreg, nomem); - set_ia32_am_support(new_op, ia32_am_None, ia32_am_arity_none); - copy_ia32_Immop_attr(new_op, new_op2); - } else { - new_op = new_rd_ia32_xDiv(dbgi, irg, block, noreg, noreg, new_op1, new_op2, nomem); - // Matze: disabled for now, spillslot coalescer fails - set_ia32_am_support(new_op, ia32_am_Source, ia32_am_binary); - } + new_op = new_rd_ia32_xDiv(dbgi, irg, block, noreg, noreg, new_op1, + new_op2, nomem); set_ia32_ls_mode(new_op, mode); } else { new_op = new_rd_ia32_vfdiv(dbgi, irg, block, noreg, noreg, new_op1, new_op2, nomem, get_fpcw()); - // Matze: disabled for now (spillslot coalescer fails) - set_ia32_am_support(new_op, ia32_am_Source, ia32_am_binary); } SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); return new_op; @@ -1230,6 +1220,29 @@ static ir_node *gen_Quot(ir_node *node) { * @return The created ia32 Shl node */ static ir_node *gen_Shl(ir_node *node) { + ir_node *right = get_Shl_right(node); + + /* test wether we can build a lea */ + if(is_Const(right)) { + tarval *tv = get_Const_tarval(right); + if(tarval_is_long(tv)) { + long val = get_tarval_long(tv); + if(val >= 0 && val <= 3) { + ir_graph *irg = current_ir_graph; + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *block = be_transform_node(get_nodes_block(node)); + ir_node *base = ia32_new_NoReg_gp(env_cg); + ir_node *index = be_transform_node(get_Shl_left(node)); + + ir_node *res + = new_rd_ia32_Lea(dbgi, irg, block, base, index); + set_ia32_am_scale(res, val); + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); + return res; + } + } + } + return gen_shift_binop(node, get_Shl_left(node), get_Shl_right(node), new_rd_ia32_Shl); } @@ -1273,7 +1286,7 @@ static ir_node *gen_Shrs(ir_node *node) { return new_rd_ia32_Cltd(dbgi, irg, block, new_op, pval); } } -#if 1 + /* 8 or 16 bit sign extension? */ if(is_Const(right) && is_Shl(left) && mode == mode_Is) { ir_node *shl_left = get_Shl_left(left); @@ -1306,7 +1319,6 @@ static ir_node *gen_Shrs(ir_node *node) { } } } -#endif return gen_shift_binop(node, left, right, new_rd_ia32_Sar); } @@ -1538,42 +1550,53 @@ static ir_node *gen_Abs(ir_node *node) { return res; } - - /** * Transforms a Load. * * @return the created ia32 Load node */ static ir_node *gen_Load(ir_node *node) { - ir_node *old_block = get_nodes_block(node); + ir_node *old_block = get_nodes_block(node); ir_node *block = be_transform_node(old_block); ir_node *ptr = get_Load_ptr(node); - ir_node *new_ptr = be_transform_node(ptr); ir_node *mem = get_Load_mem(node); ir_node *new_mem = be_transform_node(mem); + ir_node *base; + ir_node *index; ir_graph *irg = current_ir_graph; dbg_info *dbgi = get_irn_dbg_info(node); ir_node *noreg = ia32_new_NoReg_gp(env_cg); ir_mode *mode = get_Load_mode(node); ir_mode *res_mode; - ir_node *lptr = new_ptr; - int is_imm = 0; ir_node *new_op; - ia32_am_flavour_t am_flav = ia32_am_B; + ia32_address_t addr; + + /* construct load address */ + memset(&addr, 0, sizeof(addr)); + ia32_create_address_mode(&addr, ptr, 0); + base = addr.base; + index = addr.index; - /* address might be a constant (symconst or absolute address) */ - if (is_ia32_Const(new_ptr)) { - lptr = noreg; - is_imm = 1; + if(base == NULL) { + base = noreg; + } else { + base = be_transform_node(base); + } + + if(index == NULL) { + index = noreg; + } else { + index = be_transform_node(index); } if (mode_is_float(mode)) { if (USE_SSE2(env_cg)) { - new_op = new_rd_ia32_xLoad(dbgi, irg, block, lptr, noreg, new_mem); + new_op = new_rd_ia32_xLoad(dbgi, irg, block, base, index, new_mem, + mode); res_mode = mode_xmm; } else { - new_op = new_rd_ia32_vfld(dbgi, irg, block, lptr, noreg, new_mem, mode); + new_op = new_rd_ia32_vfld(dbgi, irg, block, base, index, new_mem, + mode); res_mode = mode_vfp; } } else { @@ -1582,32 +1605,18 @@ static ir_node *gen_Load(ir_node *node) { /* create a conv node with address mode for smaller modes */ if(get_mode_size_bits(mode) < 32) { - new_op = new_rd_ia32_Conv_I2I(dbgi, irg, block, lptr, noreg, noreg, + new_op = new_rd_ia32_Conv_I2I(dbgi, irg, block, base, index, noreg, new_mem, mode); } else { - new_op = new_rd_ia32_Load(dbgi, irg, block, lptr, noreg, new_mem); + new_op = new_rd_ia32_Load(dbgi, irg, block, base, index, new_mem); } res_mode = mode_Iu; } - /* base is a constant address */ - if (is_imm) { - if (get_ia32_immop_type(new_ptr) == ia32_ImmSymConst) { - set_ia32_am_sc(new_op, get_ia32_Immop_symconst(new_ptr)); - am_flav = ia32_am_N; - } else { - tarval *tv = get_ia32_Immop_tarval(new_ptr); - long offs = get_tarval_long(tv); - - add_ia32_am_offs_int(new_op, offs); - am_flav = ia32_am_O; - } - } - set_irn_pinned(new_op, get_irn_pinned(node)); set_ia32_op_type(new_op, ia32_AddrModeS); - set_ia32_am_flavour(new_op, am_flav); set_ia32_ls_mode(new_op, mode); + set_address(new_op, &addr); /* make sure we are scheduled behind the initial IncSP/Barrier * to avoid spills being placed before it @@ -1622,7 +1631,223 @@ static ir_node *gen_Load(ir_node *node) { return new_op; } +static int use_dest_am(ir_node *block, ir_node *node, ir_node *mem, + ir_node *ptr, ir_mode *mode, ir_node *other) +{ + ir_node *load; + + if(!is_Proj(node)) + return 0; + + /* we only use address mode if we're the only user of the load */ + if(get_irn_n_edges(node) > 1) + return 0; + + load = get_Proj_pred(node); + if(!is_Load(load)) + return 0; + if(get_nodes_block(load) != block) + return 0; + + /* Store should be attached to the load */ + if(!is_Proj(mem) || get_Proj_pred(mem) != load) + return 0; + /* store should have the same pointer as the load */ + if(get_Load_ptr(load) != ptr) + return 0; + + /* don't do AM if other node inputs depend on the load (via mem-proj) */ + if(other != NULL && get_nodes_block(other) == block + && heights_reachable_in_block(heights, other, load)) + return 0; + + assert(get_Load_mode(load) == mode); + + return 1; +} + +static ir_node *dest_am_binop(ir_node *node, ir_node *op1, ir_node *op2, + ir_node *mem, ir_node *ptr, ir_mode *mode, + construct_binop_dest_func *func, int commutative) +{ + ir_node *src_block = get_nodes_block(node); + ir_node *block; + ir_node *noreg_gp = ia32_new_NoReg_gp(env_cg); + ir_graph *irg = current_ir_graph; + dbg_info *dbgi; + ir_node *new_node; + ir_node *new_op; + ia32_address_mode_t am; + ia32_address_t *addr = &am.addr; + memset(&am, 0, sizeof(am)); + + if(use_dest_am(src_block, op1, mem, ptr, mode, op2)) { + build_address(&am, op1); + new_op = create_immediate_or_transform(op2, 0); + } else if(commutative && use_dest_am(src_block, op2, mem, ptr, mode, op1)) { + build_address(&am, op2); + new_op = create_immediate_or_transform(op1, 0); + } else { + return NULL; + } + + if(addr->base == NULL) + addr->base = noreg_gp; + if(addr->index == NULL) + addr->index = noreg_gp; + if(addr->mem == NULL) + addr->mem = new_NoMem(); + + dbgi = get_irn_dbg_info(node); + block = be_transform_node(src_block); + new_node = func(dbgi, irg, block, addr->base, addr->index, new_op, + addr->mem); + set_address(new_node, addr); + set_ia32_op_type(new_node, ia32_AddrModeD); + set_ia32_ls_mode(new_node, mode); + SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node)); + + return new_node; +} + +static ir_node *dest_am_unop(ir_node *node, ir_node *op, ir_node *mem, + ir_node *ptr, ir_mode *mode, + construct_unop_dest_func *func) +{ + ir_node *src_block = get_nodes_block(node); + ir_node *block; + ir_node *noreg_gp = ia32_new_NoReg_gp(env_cg); + ir_graph *irg = current_ir_graph; + dbg_info *dbgi; + ir_node *new_node; + ia32_address_mode_t am; + ia32_address_t *addr = &am.addr; + memset(&am, 0, sizeof(am)); + + if(!use_dest_am(src_block, op, mem, ptr, mode, NULL)) + return NULL; + + build_address(&am, op); + + if(addr->base == NULL) + addr->base = noreg_gp; + if(addr->index == NULL) + addr->index = noreg_gp; + if(addr->mem == NULL) + addr->mem = new_NoMem(); + + dbgi = get_irn_dbg_info(node); + block = be_transform_node(src_block); + new_node = func(dbgi, irg, block, addr->base, addr->index, addr->mem); + set_address(new_node, addr); + set_ia32_op_type(new_node, ia32_AddrModeD); + set_ia32_ls_mode(new_node, mode); + SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node)); + + return new_node; +} + +static ir_node *try_create_dest_am(ir_node *node) { + ir_node *val = get_Store_value(node); + ir_node *mem = get_Store_mem(node); + ir_node *ptr = get_Store_ptr(node); + ir_mode *mode = get_irn_mode(val); + ir_node *op1; + ir_node *op2; + ir_node *new_node; + + /* handle only GP modes for now... */ + if(!mode_needs_gp_reg(mode)) + return NULL; + if(get_mode_size_bits(mode) != 32) + return NULL; + + /* store must be the only user of the val node */ + if(get_irn_n_edges(val) > 1) + return NULL; + + switch(get_irn_opcode(val)) { + case iro_Add: + op1 = get_Add_left(val); + op2 = get_Add_right(val); + if(is_Const_1(op2)) { + new_node = dest_am_unop(val, op1, mem, ptr, mode, + new_rd_ia32_IncMem); + break; + } else if(is_Const_Minus_1(op2)) { + new_node = dest_am_unop(val, op1, mem, ptr, mode, + new_rd_ia32_DecMem); + break; + } + new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, + new_rd_ia32_AddMem, 1); + break; + case iro_Sub: + op1 = get_Sub_left(val); + op2 = get_Sub_right(val); + new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, + new_rd_ia32_SubMem, 0); + break; + case iro_And: + op1 = get_And_left(val); + op2 = get_And_right(val); + new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, + new_rd_ia32_AndMem, 1); + break; + case iro_Or: + op1 = get_Or_left(val); + op2 = get_Or_right(val); + new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, + new_rd_ia32_OrMem, 1); + break; + case iro_Eor: + op1 = get_Eor_left(val); + op2 = get_Eor_right(val); + new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, + new_rd_ia32_XorMem, 1); + break; + case iro_Shl: + op1 = get_Shl_left(val); + op2 = get_Shl_right(val); + new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, + new_rd_ia32_ShlMem, 0); + break; + case iro_Shr: + op1 = get_Shr_left(val); + op2 = get_Shr_right(val); + new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, + new_rd_ia32_ShrMem, 0); + break; + case iro_Shrs: + op1 = get_Shrs_left(val); + op2 = get_Shrs_right(val); + new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, + new_rd_ia32_SarMem, 0); + break; + case iro_Rot: + op1 = get_Rot_left(val); + op2 = get_Rot_right(val); + new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, + new_rd_ia32_RolMem, 0); + break; + /* TODO: match ROR patterns... */ + case iro_Minus: + op1 = get_Minus_op(val); + new_node = dest_am_unop(val, op1, mem, ptr, mode, new_rd_ia32_NegMem); + break; + case iro_Not: + /* TODO this would be ^ 1 with DestAM */ + if(mode == mode_b) + return NULL; + op1 = get_Not_op(val); + new_node = dest_am_unop(val, op1, mem, ptr, mode, new_rd_ia32_NotMem); + break; + default: + return NULL; + } + return new_node; +} /** * Transforms a Store. @@ -1632,7 +1857,8 @@ static ir_node *gen_Load(ir_node *node) { static ir_node *gen_Store(ir_node *node) { ir_node *block = be_transform_node(get_nodes_block(node)); ir_node *ptr = get_Store_ptr(node); - ir_node *new_ptr = be_transform_node(ptr); + ir_node *base; + ir_node *index; ir_node *val = get_Store_value(node); ir_node *new_val; ir_node *mem = get_Store_mem(node); @@ -1640,25 +1866,40 @@ static ir_node *gen_Store(ir_node *node) { ir_graph *irg = current_ir_graph; dbg_info *dbgi = get_irn_dbg_info(node); ir_node *noreg = ia32_new_NoReg_gp(env_cg); - ir_node *sptr = new_ptr; ir_mode *mode = get_irn_mode(val); - int is_imm = 0; ir_node *new_op; - ia32_am_flavour_t am_flav = ia32_am_B; + ia32_address_t addr; - /* address might be a constant (symconst or absolute address) */ - if (is_ia32_Const(new_ptr)) { - sptr = noreg; - is_imm = 1; + /* check for destination address mode */ + new_op = try_create_dest_am(node); + if(new_op != NULL) + return new_op; + + /* construct load address */ + memset(&addr, 0, sizeof(addr)); + ia32_create_address_mode(&addr, ptr, 0); + base = addr.base; + index = addr.index; + + if(base == NULL) { + base = noreg; + } else { + base = be_transform_node(base); + } + + if(index == NULL) { + index = noreg; + } else { + index = be_transform_node(index); } if (mode_is_float(mode)) { new_val = be_transform_node(val); if (USE_SSE2(env_cg)) { - new_op = new_rd_ia32_xStore(dbgi, irg, block, sptr, noreg, new_val, + new_op = new_rd_ia32_xStore(dbgi, irg, block, base, index, new_val, new_mem); } else { - new_op = new_rd_ia32_vfst(dbgi, irg, block, sptr, noreg, new_val, + new_op = new_rd_ia32_vfst(dbgi, irg, block, base, index, new_val, new_mem, mode); } } else { @@ -1667,98 +1908,70 @@ static ir_node *gen_Store(ir_node *node) { mode = mode_Iu; if (get_mode_size_bits(mode) == 8) { - new_op = new_rd_ia32_Store8Bit(dbgi, irg, block, sptr, noreg, + new_op = new_rd_ia32_Store8Bit(dbgi, irg, block, base, index, new_val, new_mem); } else { - new_op = new_rd_ia32_Store(dbgi, irg, block, sptr, noreg, new_val, + new_op = new_rd_ia32_Store(dbgi, irg, block, base, index, new_val, new_mem); } } - /* base is an constant address */ - if (is_imm) { - if (get_ia32_immop_type(new_ptr) == ia32_ImmSymConst) { - set_ia32_am_sc(new_op, get_ia32_Immop_symconst(new_ptr)); - am_flav = ia32_am_N; - } else { - tarval *tv = get_ia32_Immop_tarval(new_ptr); - long offs = get_tarval_long(tv); - - add_ia32_am_offs_int(new_op, offs); - am_flav = ia32_am_O; - } - } - set_irn_pinned(new_op, get_irn_pinned(node)); set_ia32_op_type(new_op, ia32_AddrModeD); - set_ia32_am_flavour(new_op, am_flav); set_ia32_ls_mode(new_op, mode); set_ia32_exc_label(new_op, be_get_Proj_for_pn(node, pn_Store_X_except) != NULL); + set_address(new_op, &addr); SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); return new_op; } -static ir_node *maybe_scale_up(ir_node *new_op, ir_mode *mode, dbg_info *dbgi) -{ - ir_mode *tgt_mode; - ir_node *block; - - if(get_mode_size_bits(mode) == 32) - return new_op; - if(mode == mode_b) - return new_op; - if(is_ia32_Immediate(new_op)) - return new_op; - - if(mode_is_signed(mode)) - tgt_mode = mode_Is; - else - tgt_mode = mode_Iu; - - block = get_nodes_block(new_op); - return create_I2I_Conv(mode, tgt_mode, dbgi, block, new_op); -} - static ir_node *try_create_TestJmp(ir_node *block, dbg_info *dbgi, long pnc, ir_node *cmp_left, ir_node *cmp_right) { - ir_node *new_cmp_left; - ir_node *new_cmp_right; - ir_node *and_left; - ir_node *and_right; + ir_node *arg_left; + ir_node *arg_right; ir_node *res; - ir_node *noreg; - ir_node *nomem; ir_mode *mode; long pure_pnc = pnc & ~ia32_pn_Cmp_Unsigned; + ia32_address_mode_t am; + ia32_address_t *addr = &am.addr; if(cmp_right != NULL && !is_Const_0(cmp_right)) return NULL; if(is_And(cmp_left) && (pure_pnc == pn_Cmp_Eq || pure_pnc == pn_Cmp_Lg)) { - and_left = get_And_left(cmp_left); - and_right = get_And_right(cmp_left); - - mode = get_irn_mode(and_left); - new_cmp_left = be_transform_node(and_left); - new_cmp_right = create_immediate_or_transform(and_right, 0); + mode = get_irn_mode(cmp_left); + arg_left = get_And_left(cmp_left); + arg_right = get_And_right(cmp_left); } else { - mode = get_irn_mode(cmp_left); - new_cmp_left = be_transform_node(cmp_left); - new_cmp_right = be_transform_node(cmp_left); + mode = get_irn_mode(cmp_left); + arg_left = cmp_left; + arg_right = cmp_left; } + if(mode == mode_b) + mode = mode_Iu; + assert(get_mode_size_bits(mode) <= 32); - new_cmp_left = maybe_scale_up(new_cmp_left, mode, dbgi); - new_cmp_right = maybe_scale_up(new_cmp_right, mode, dbgi); - noreg = ia32_new_NoReg_gp(env_cg); - nomem = new_NoMem(); + match_arguments(&am, block, arg_left, arg_right, 1, 1); + if(am.flipped) + pnc = get_inversed_pnc(pnc); + + if(get_mode_size_bits(mode) == 8) { + res = new_rd_ia32_TestJmp8Bit(dbgi, current_ir_graph, block, addr->base, + addr->index, am.new_op1, am.new_op2, + addr->mem, pnc); + } else { + res = new_rd_ia32_TestJmp(dbgi, current_ir_graph, block, addr->base, + addr->index, am.new_op1, am.new_op2, + addr->mem, pnc); + } + set_am_attributes(res, &am); + set_ia32_ls_mode(res, mode); - res = new_rd_ia32_TestJmp(dbgi, current_ir_graph, block, noreg, noreg, - new_cmp_left, new_cmp_right, nomem, pnc); - set_ia32_am_support(res, ia32_am_Source, ia32_am_binary); + res = fix_mem_proj(res, &am); return res; } @@ -1785,12 +1998,11 @@ static ir_node *create_Switch(ir_node *node) } if (switch_min != 0) { - ir_node *noreg = ia32_new_NoReg_gp(env_cg); + ir_node *noreg = ia32_new_NoReg_gp(env_cg); /* if smallest switch case is not 0 we need an additional sub */ new_sel = new_rd_ia32_Lea(dbgi, irg, block, new_sel, noreg); add_ia32_am_offs_int(new_sel, -switch_min); - set_ia32_am_flavour(new_sel, ia32_am_OB); set_ia32_op_type(new_sel, ia32_AddrModeS); SET_IA32_ORIG_NODE(new_sel, ia32_get_old_node_name(env_cg, node)); @@ -1810,20 +2022,21 @@ static ir_node *create_Switch(ir_node *node) * @return The transformed node. */ static ir_node *gen_Cond(ir_node *node) { - ir_node *block = be_transform_node(get_nodes_block(node)); - ir_graph *irg = current_ir_graph; - dbg_info *dbgi = get_irn_dbg_info(node); - ir_node *sel = get_Cond_selector(node); - ir_mode *sel_mode = get_irn_mode(sel); - ir_node *res = NULL; - ir_node *noreg = ia32_new_NoReg_gp(env_cg); + ir_node *src_block = get_nodes_block(node); + ir_node *block = be_transform_node(src_block); + ir_graph *irg = current_ir_graph; + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *sel = get_Cond_selector(node); + ir_mode *sel_mode = get_irn_mode(sel); + ir_node *res = NULL; + ir_node *noreg = ia32_new_NoReg_gp(env_cg); + ir_node *nomem = new_NoMem(); ir_node *cmp; ir_node *cmp_a; ir_node *cmp_b; ir_node *new_cmp_a; ir_node *new_cmp_b; ir_mode *cmp_mode; - ir_node *nomem = new_NoMem(); long pnc; if (sel_mode != mode_b) { @@ -1855,32 +2068,36 @@ static ir_node *gen_Cond(ir_node *node) { } } - new_cmp_a = be_transform_node(cmp_a); - new_cmp_b = create_immediate_or_transform(cmp_b, 0); - if (mode_is_float(cmp_mode)) { + new_cmp_a = be_transform_node(cmp_a); + new_cmp_b = create_immediate_or_transform(cmp_b, 0); if (USE_SSE2(env_cg)) { - res = new_rd_ia32_xCondJmp(dbgi, irg, block, noreg, noreg, cmp_a, - cmp_b, nomem, pnc); + res = new_rd_ia32_xCmpJmp(dbgi, irg, block, noreg, noreg, cmp_a, + cmp_b, nomem, pnc); set_ia32_commutative(res); - set_ia32_am_support(res, ia32_am_Source, ia32_am_binary); set_ia32_ls_mode(res, cmp_mode); } else { - res = new_rd_ia32_vfCondJmp(dbgi, irg, block, cmp_a, cmp_b, pnc); + res = new_rd_ia32_vfCmpJmp(dbgi, irg, block, cmp_a, cmp_b, pnc); set_ia32_commutative(res); } } else { - /** workaround smaller compare modes with converts... - * We could easily support 16bit compares, for 8 bit we have to set - * additional register constraints, which we don't do yet - */ - new_cmp_a = maybe_scale_up(new_cmp_a, cmp_mode, dbgi); - new_cmp_b = maybe_scale_up(new_cmp_b, cmp_mode, dbgi); - - res = new_rd_ia32_CondJmp(dbgi, irg, block, noreg, noreg, - new_cmp_a, new_cmp_b, nomem, pnc); - set_ia32_commutative(res); - set_ia32_am_support(res, ia32_am_Source, ia32_am_binary); + ia32_address_mode_t am; + ia32_address_t *addr = &am.addr; + match_arguments(&am, src_block, cmp_a, cmp_b, 1, 1); + if(am.flipped) + pnc = get_inversed_pnc(pnc); + + if(get_mode_size_bits(cmp_mode) == 8) { + res = new_rd_ia32_CmpJmp8Bit(dbgi, irg, block, addr->base, + addr->index, am.new_op1, am.new_op2, + addr->mem, pnc); + } else { + res = new_rd_ia32_CmpJmp(dbgi, irg, block, addr->base, addr->index, + am.new_op1, am.new_op2, addr->mem, pnc); + } + set_am_attributes(res, &am); + assert(cmp_mode != NULL); + set_ia32_ls_mode(res, cmp_mode); } SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); @@ -1915,15 +2132,15 @@ static ir_node *gen_CopyB(ir_node *node) { rem = size & 0x3; /* size % 4 */ size >>= 2; - res = new_rd_ia32_Const(dbgi, irg, block); + res = new_rd_ia32_Const(dbgi, irg, block, NULL, 0, size); add_irn_dep(res, be_abi_get_start_barrier(env_cg->birg->abi)); - set_ia32_Immop_tarval(res, new_tarval_from_long(size, mode_Is)); res = new_rd_ia32_CopyB(dbgi, irg, block, new_dst, new_src, res, new_mem); - set_ia32_Immop_tarval(res, new_tarval_from_long(rem, mode_Is)); + /* we misuse the pncode field for the copyb size */ + set_ia32_pncode(res, rem); } else { res = new_rd_ia32_CopyB_i(dbgi, irg, block, new_dst, new_src, new_mem); - set_ia32_Immop_tarval(res, new_tarval_from_long(size, mode_Is)); + set_ia32_pncode(res, size); } SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); @@ -1948,13 +2165,16 @@ ir_node *gen_be_Copy(ir_node *node) static ir_node *create_set(long pnc, ir_node *cmp_left, ir_node *cmp_right, dbg_info *dbgi, ir_node *block) { - ir_graph *irg = current_ir_graph; - ir_node *noreg = ia32_new_NoReg_gp(env_cg); - ir_node *nomem = new_rd_NoMem(irg); + ir_graph *irg = current_ir_graph; + ir_node *new_block = be_transform_node(block); + ir_node *noreg = ia32_new_NoReg_gp(env_cg); + ir_node *nomem = new_rd_NoMem(irg); ir_mode *mode; - ir_node *new_cmp_left; - ir_node *new_cmp_right; + ir_node *arg_left; + ir_node *arg_right; ir_node *res; + ia32_address_mode_t am; + ia32_address_t *addr = &am.addr; /* can we use a test instruction? */ if(cmp_right == NULL || is_Const_0(cmp_right)) { @@ -1964,42 +2184,63 @@ static ir_node *create_set(long pnc, ir_node *cmp_left, ir_node *cmp_right, ir_node *and_left = get_And_left(cmp_left); ir_node *and_right = get_And_right(cmp_left); - mode = get_irn_mode(and_left); - new_cmp_left = be_transform_node(and_left); - new_cmp_right = create_immediate_or_transform(and_right, 0); + mode = get_irn_mode(and_left); + arg_left = and_left; + arg_right = and_right; } else { - mode = get_irn_mode(cmp_left); - new_cmp_left = be_transform_node(cmp_left); - new_cmp_right = be_transform_node(cmp_left); + mode = get_irn_mode(cmp_left); + arg_left = cmp_left; + arg_right = cmp_left; } assert(get_mode_size_bits(mode) <= 32); - new_cmp_left = maybe_scale_up(new_cmp_left, mode, dbgi); - new_cmp_right = maybe_scale_up(new_cmp_right, mode, dbgi); - res = new_rd_ia32_TestSet(dbgi, current_ir_graph, block, noreg, noreg, - new_cmp_left, new_cmp_right, nomem, pnc); - set_ia32_am_support(res, ia32_am_Source, ia32_am_binary); + match_arguments(&am, block, arg_left, arg_right, 1, 1); + if(am.flipped) + pnc = get_inversed_pnc(pnc); - res = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, block, noreg, noreg, res, - nomem, mode_Bu); + if(get_mode_size_bits(mode) == 8) { + res = new_rd_ia32_TestSet8Bit(dbgi, irg, new_block, addr->base, + addr->index, am.new_op1, am.new_op2, + addr->mem, pnc); + } else { + res = new_rd_ia32_TestSet(dbgi, irg, new_block, addr->base, + addr->index, am.new_op1, am.new_op2, + addr->mem, pnc); + } + set_am_attributes(res, &am); + set_ia32_ls_mode(res, mode); + + res = fix_mem_proj(res, &am); + + res = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, new_block, noreg, noreg, res, + nomem, mode_Bu); return res; } mode = get_irn_mode(cmp_left); + assert(get_mode_size_bits(mode) <= 32); - new_cmp_left = be_transform_node(cmp_left); - new_cmp_right = create_immediate_or_transform(cmp_right, 0); + match_arguments(&am, block, cmp_left, cmp_right, 1, 1); + if(am.flipped) + pnc = get_inversed_pnc(pnc); - assert(get_mode_size_bits(mode) <= 32); - new_cmp_left = maybe_scale_up(new_cmp_left, mode, dbgi); - new_cmp_right = maybe_scale_up(new_cmp_right, mode, dbgi); + if(get_mode_size_bits(mode) == 8) { + res = new_rd_ia32_CmpSet8Bit(dbgi, irg, new_block, addr->base, + addr->index, am.new_op1, am.new_op2, + addr->mem, pnc); + } else { + res = new_rd_ia32_CmpSet(dbgi, irg, new_block, addr->base, addr->index, + am.new_op1, am.new_op2, addr->mem, pnc); + } + set_am_attributes(res, &am); + set_ia32_ls_mode(res, mode); + + res = fix_mem_proj(res, &am); - res = new_rd_ia32_CmpSet(dbgi, irg, block, noreg, noreg, new_cmp_left, - new_cmp_right, nomem, pnc); - res = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, block, noreg, noreg, res, nomem, - mode_Bu); + res = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, new_block, noreg, noreg, res, + nomem, mode_Bu); return res; } @@ -2009,6 +2250,7 @@ static ir_node *create_cmov(long pnc, ir_node *cmp_left, ir_node *cmp_right, dbg_info *dbgi, ir_node *block) { ir_graph *irg = current_ir_graph; + ir_node *new_block = be_transform_node(block); ir_node *new_val_true = be_transform_node(val_true); ir_node *new_val_false = be_transform_node(val_false); ir_node *noreg = ia32_new_NoReg_gp(env_cg); @@ -2016,6 +2258,7 @@ static ir_node *create_cmov(long pnc, ir_node *cmp_left, ir_node *cmp_right, ir_node *new_cmp_left; ir_node *new_cmp_right; ir_node *res; + ir_mode *mode; /* cmovs with unknowns are pointless... */ if(is_Unknown(val_true)) { @@ -2039,28 +2282,49 @@ static ir_node *create_cmov(long pnc, ir_node *cmp_left, ir_node *cmp_right, ir_node *and_left = get_And_left(cmp_left); ir_node *and_right = get_And_right(cmp_left); + mode = get_irn_mode(and_left); new_cmp_left = be_transform_node(and_left); new_cmp_right = create_immediate_or_transform(and_right, 0); } else { + mode = get_irn_mode(cmp_left); new_cmp_left = be_transform_node(cmp_left); new_cmp_right = be_transform_node(cmp_left); } - res = new_rd_ia32_TestCMov(dbgi, current_ir_graph, block, noreg, noreg, - new_cmp_left, new_cmp_right, nomem, - new_val_true, new_val_false, pnc); - set_ia32_am_support(res, ia32_am_Source, ia32_am_binary); + assert(get_mode_size_bits(mode) <= 32); + + if(get_mode_size_bits(mode) == 8) { + res = new_rd_ia32_TestCMov8Bit(dbgi, current_ir_graph, new_block, + noreg, noreg, new_cmp_left, + new_cmp_right, nomem, new_val_true, + new_val_false, pnc); + } else { + res = new_rd_ia32_TestCMov(dbgi, current_ir_graph, new_block, noreg, + noreg, new_cmp_left, new_cmp_right, + nomem, new_val_true, new_val_false, pnc); + } + set_ia32_ls_mode(res, mode); return res; } + mode = get_irn_mode(cmp_left); new_cmp_left = be_transform_node(cmp_left); new_cmp_right = create_immediate_or_transform(cmp_right, 0); - res = new_rd_ia32_CmpCMov(dbgi, irg, block, noreg, noreg, new_cmp_left, - new_cmp_right, nomem, new_val_true, new_val_false, - pnc); - set_ia32_am_support(res, ia32_am_Source, ia32_am_binary); + /* no support for 8,16 bit modes yet */ + assert(get_mode_size_bits(mode) <= 32); + + if(get_mode_size_bits(mode) == 8) { + res = new_rd_ia32_CmpCMov8Bit(dbgi, irg, new_block, noreg, noreg, + new_cmp_left, new_cmp_right, nomem, + new_val_true, new_val_false, pnc); + } else { + res = new_rd_ia32_CmpCMov(dbgi, irg, new_block, noreg, noreg, + new_cmp_left, new_cmp_right, nomem, + new_val_true, new_val_false, pnc); + } + set_ia32_ls_mode(res, mode); return res; } @@ -2076,7 +2340,7 @@ static ir_node *gen_Psi(ir_node *node) { ir_node *psi_default = get_Psi_default(node); ia32_code_gen_t *cg = env_cg; ir_node *cond = get_Psi_cond(node, 0); - ir_node *block = be_transform_node(get_nodes_block(node)); + ir_node *block = get_nodes_block(node); dbg_info *dbgi = get_irn_dbg_info(node); ir_node *new_op; ir_node *cmp_left; @@ -2123,34 +2387,6 @@ static ir_node *gen_Psi(ir_node *node) { } -/** - * Following conversion rules apply: - * - * INT -> INT - * ============ - * 1) n bit -> m bit n > m (downscale) - * always ignored - * 2) n bit -> m bit n == m (sign change) - * always ignored - * 3) n bit -> m bit n < m (upscale) - * a) source is signed: movsx - * b) source is unsigned: and with lower bits sets - * - * INT -> FLOAT - * ============== - * SSE(1/2) convert to float or double (cvtsi2ss/sd) - * - * FLOAT -> INT - * ============== - * SSE(1/2) convert from float or double to 32bit int (cvtss/sd2si) - * - * FLOAT -> FLOAT - * ================ - * SSE(1/2) convert from float or double to double or float (cvtss/sd2sd/ss) - * x87 is mode_E internally, conversions happen only at load and store - * in non-strict semantic - */ - /** * Create a conversion from x87 state register to general purpose. */ @@ -2173,7 +2409,6 @@ static ir_node *gen_x87_fp_to_gp(ir_node *node) { set_irn_pinned(fist, op_pin_state_floats); set_ia32_use_frame(fist); set_ia32_op_type(fist, ia32_AddrModeD); - set_ia32_am_flavour(fist, ia32_am_B); assert(get_mode_size_bits(mode) <= 32); /* exception we can only store signed 32 bit integers, so for unsigned @@ -2191,7 +2426,6 @@ static ir_node *gen_x87_fp_to_gp(ir_node *node) { set_irn_pinned(load, op_pin_state_floats); set_ia32_use_frame(load); set_ia32_op_type(load, ia32_AddrModeS); - set_ia32_am_flavour(load, ia32_am_B); set_ia32_ls_mode(load, mode_Is); if(get_ia32_ls_mode(fist) == mode_Ls) { ia32_attr_t *attr = get_ia32_attr(load); @@ -2220,14 +2454,12 @@ static ir_node *create_strict_conv(ir_mode *tgt_mode, ir_node *node) tgt_mode); set_ia32_use_frame(store); set_ia32_op_type(store, ia32_AddrModeD); - set_ia32_am_flavour(store, ia32_am_OB); SET_IA32_ORIG_NODE(store, ia32_get_old_node_name(env_cg, node)); load = new_rd_ia32_vfld(dbgi, irg, block, frame, noreg, store, tgt_mode); set_ia32_use_frame(load); set_ia32_op_type(load, ia32_AddrModeS); - set_ia32_am_flavour(load, ia32_am_OB); SET_IA32_ORIG_NODE(load, ia32_get_old_node_name(env_cg, node)); res = new_r_Proj(irg, block, load, mode_E, pn_ia32_vfld_res); @@ -2256,12 +2488,10 @@ static ir_node *gen_x87_gp_to_fp(ir_node *node, ir_mode *src_mode) { if (src_bits == 8) { new_op = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, block, noreg, noreg, new_op, nomem, src_mode); - set_ia32_am_support(new_op, ia32_am_Source, ia32_am_unary); SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); mode = mode_Is; } else if (src_bits < 32) { new_op = new_rd_ia32_Conv_I2I(dbgi, irg, block, noreg, noreg, new_op, nomem, src_mode); - set_ia32_am_support(new_op, ia32_am_Source, ia32_am_unary); SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); mode = mode_Is; } @@ -2273,7 +2503,6 @@ static ir_node *gen_x87_gp_to_fp(ir_node *node, ir_mode *src_mode) { set_ia32_use_frame(store); set_ia32_op_type(store, ia32_AddrModeD); - set_ia32_am_flavour(store, ia32_am_OB); set_ia32_ls_mode(store, mode_Iu); /* exception for 32bit unsigned, do a 64bit spill+load */ @@ -2304,7 +2533,6 @@ static ir_node *gen_x87_gp_to_fp(ir_node *node, ir_mode *src_mode) { set_ia32_use_frame(fild); set_ia32_op_type(fild, ia32_AddrModeS); - set_ia32_am_flavour(fild, ia32_am_OB); set_ia32_ls_mode(fild, store_mode); res = new_r_Proj(irg, block, fild, mode_vfp, pn_ia32_vfild_res); @@ -2344,7 +2572,6 @@ static ir_node *create_I2I_Conv(ir_mode *src_mode, ir_mode *tgt_mode, res = new_rd_ia32_Conv_I2I(dbgi, irg, new_block, noreg, noreg, new_op, nomem, smaller_mode); } - set_ia32_am_support(res, ia32_am_Source, ia32_am_unary); return res; } @@ -2429,9 +2656,6 @@ static ir_node *gen_Conv(ir_node *node) { if (USE_SSE2(env_cg)) { res = new_rd_ia32_Conv_I2FP(dbgi, irg, block, noreg, noreg, new_op, nomem); set_ia32_ls_mode(res, tgt_mode); - if(src_bits == 32) { - set_ia32_am_support(res, ia32_am_Source, ia32_am_unary); - } } else { res = gen_x87_gp_to_fp(node, src_mode); if(get_Conv_strict(node)) { @@ -2991,7 +3215,6 @@ static ir_node *gen_be_FrameAddr(ir_node *node) { res = new_rd_ia32_Lea(dbgi, irg, block, new_op, noreg); set_ia32_frame_ent(res, arch_get_frame_entity(env_cg->arch_env, node)); set_ia32_use_frame(res); - set_ia32_am_flavour(res, ia32_am_OB); SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); @@ -3062,13 +3285,11 @@ static ir_node *gen_be_Return(ir_node *node) { set_ia32_ls_mode(sse_store, mode); set_ia32_op_type(sse_store, ia32_AddrModeD); set_ia32_use_frame(sse_store); - set_ia32_am_flavour(sse_store, ia32_am_B); /* load into x87 register */ fld = new_rd_ia32_vfld(dbgi, irg, block, frame, noreg, sse_store, mode); set_ia32_op_type(fld, ia32_AddrModeS); set_ia32_use_frame(fld); - set_ia32_am_flavour(fld, ia32_am_B); mproj = new_r_Proj(irg, block, fld, mode_M, pn_ia32_vfld_M); fld = new_r_Proj(irg, block, fld, mode_vfp, pn_ia32_vfld_res); @@ -3122,7 +3343,6 @@ static ir_node *gen_be_AddSP(ir_node *node) { /* ia32 stack grows in reverse direction, make a SubSP */ new_op = new_rd_ia32_SubSP(dbgi, irg, block, noreg, noreg, new_sp, new_sz, nomem); - set_ia32_am_support(new_op, ia32_am_Source, ia32_am_binary); SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); return new_op; @@ -3147,7 +3367,6 @@ static ir_node *gen_be_SubSP(ir_node *node) { /* ia32 stack grows in reverse direction, make an AddSP */ new_op = new_rd_ia32_AddSP(dbgi, irg, block, noreg, noreg, new_sp, new_sz, nomem); - set_ia32_am_support(new_op, ia32_am_Source, ia32_am_binary); SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); return new_op; @@ -3162,21 +3381,15 @@ static ir_node *gen_Unknown(ir_node *node) { ir_mode *mode = get_irn_mode(node); if (mode_is_float(mode)) { -#if 0 - /* Unknown nodes are buggy in x87 sim, use zero for now... */ - if (USE_SSE2(env_cg)) - else - return ia32_new_Unknown_vfp(env_cg); -#else - if (!USE_SSE2(env_cg)) { + if (USE_SSE2(env_cg)) { + return ia32_new_Unknown_xmm(env_cg); + } else { + /* Unknown nodes are buggy in x87 sim, use zero for now... */ ir_graph *irg = current_ir_graph; dbg_info *dbgi = get_irn_dbg_info(node); ir_node *block = get_irg_start_block(irg); return new_rd_ia32_vfldz(dbgi, irg, block); - } else { - return ia32_new_Unknown_xmm(env_cg); } -#endif } else if (mode_needs_gp_reg(mode)) { return ia32_new_Unknown_gp(env_cg); } else { @@ -3211,7 +3424,8 @@ static ir_node *gen_Phi(ir_node *node) { /* phi nodes allow loops, so we use the old arguments for now * and fix this later */ - phi = new_ir_node(dbgi, irg, block, op_Phi, mode, get_irn_arity(node), get_irn_in(node) + 1); + phi = new_ir_node(dbgi, irg, block, op_Phi, mode, get_irn_arity(node), + get_irn_in(node) + 1); copy_node_attr(node, phi); be_duplicate_deps(node, phi); @@ -3225,20 +3439,8 @@ static ir_node *gen_Phi(ir_node *node) { * Transform IJmp */ static ir_node *gen_IJmp(ir_node *node) { - ir_node *block = be_transform_node(get_nodes_block(node)); - ir_graph *irg = current_ir_graph; - dbg_info *dbgi = get_irn_dbg_info(node); - ir_node *new_op = be_transform_node(get_IJmp_target(node)); - ir_node *noreg = ia32_new_NoReg_gp(env_cg); - ir_node *nomem = new_NoMem(); - ir_node *new_node; - - new_node = new_rd_ia32_IJmp(dbgi, irg, block, noreg, noreg, new_op, nomem); - set_ia32_am_support(new_node, ia32_am_Source, ia32_am_unary); - - SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node)); - - return new_node; + /* TODO: support AM */ + return gen_unop(node, get_IJmp_target(node), new_rd_ia32_IJmp); } @@ -3279,7 +3481,6 @@ static ir_node *gen_lowered_Load(ir_node *node, construct_load_func func) new_op = func(dbgi, irg, block, new_ptr, noreg, new_mem); set_ia32_op_type(new_op, ia32_AddrModeS); - set_ia32_am_flavour(new_op, ia32_am_OB); set_ia32_am_offs_int(new_op, 0); set_ia32_am_scale(new_op, 1); set_ia32_am_sc(new_op, get_ia32_am_sc(node)); @@ -3314,17 +3515,13 @@ static ir_node *gen_lowered_Store(ir_node *node, construct_store_func func) ir_mode *mode = get_ia32_ls_mode(node); ir_node *new_op; long am_offs; - ia32_am_flavour_t am_flav = ia32_B; new_op = func(dbgi, irg, block, new_ptr, noreg, new_val, new_mem); - if ((am_offs = get_ia32_am_offs_int(node)) != 0) { - am_flav |= ia32_O; - add_ia32_am_offs_int(new_op, am_offs); - } + am_offs = get_ia32_am_offs_int(node); + add_ia32_am_offs_int(new_op, am_offs); set_ia32_op_type(new_op, ia32_AddrModeD); - set_ia32_am_flavour(new_op, am_flav); set_ia32_ls_mode(new_op, mode); set_ia32_frame_ent(new_op, get_ia32_frame_ent(node)); set_ia32_use_frame(new_op); @@ -3412,18 +3609,14 @@ static ir_node *gen_ia32_l_vfist(ir_node *node) { ir_node *trunc_mode = ia32_new_Fpu_truncate(env_cg); ir_node *new_op; long am_offs; - ia32_am_flavour_t am_flav = ia32_B; new_op = new_rd_ia32_vfist(dbgi, irg, block, new_ptr, noreg, new_val, trunc_mode, new_mem); - if ((am_offs = get_ia32_am_offs_int(node)) != 0) { - am_flav |= ia32_O; - add_ia32_am_offs_int(new_op, am_offs); - } + am_offs = get_ia32_am_offs_int(node); + add_ia32_am_offs_int(new_op, am_offs); set_ia32_op_type(new_op, ia32_AddrModeD); - set_ia32_am_flavour(new_op, am_flav); set_ia32_ls_mode(new_op, mode); set_ia32_frame_ent(new_op, get_ia32_frame_ent(node)); set_ia32_use_frame(new_op); @@ -3454,7 +3647,6 @@ static ir_node *gen_ia32_l_vfdiv(ir_node *node) { vfdiv = new_rd_ia32_vfdiv(dbgi, irg, block, noreg, noreg, new_left, new_right, new_NoMem(), fpcw); clear_ia32_commutative(vfdiv); - set_ia32_am_support(vfdiv, ia32_am_Source, ia32_am_binary); SET_IA32_ORIG_NODE(vfdiv, ia32_get_old_node_name(env_cg, node)); @@ -3482,7 +3674,6 @@ static ir_node *gen_ia32_l_Mul(ir_node *node) { ir_node *muls = new_rd_ia32_Mul(dbgi, irg, block, noreg, noreg, new_left, new_right, new_NoMem()); clear_ia32_commutative(muls); - set_ia32_am_support(muls, ia32_am_Source, ia32_am_binary); SET_IA32_ORIG_NODE(muls, ia32_get_old_node_name(env_cg, node)); @@ -3533,67 +3724,22 @@ static ir_node *gen_lowered_64bit_shifts(ir_node *node, ir_node *op1, ir_node *op2, ir_node *count) { ir_node *block = be_transform_node(get_nodes_block(node)); - ir_node *new_op1 = be_transform_node(op1); - ir_node *new_op2 = be_transform_node(op2); ir_node *new_op = NULL; - ir_node *new_count = be_transform_node(count); ir_graph *irg = current_ir_graph; dbg_info *dbgi = get_irn_dbg_info(node); - ir_node *noreg = ia32_new_NoReg_gp(env_cg); - ir_node *nomem = new_NoMem(); - ir_node *imm_op; - tarval *tv; - - assert(! mode_is_float(get_irn_mode(node)) && "Shift/Rotate with float not supported"); - - /* Check if immediate optimization is on and */ - /* if it's an operation with immediate. */ - imm_op = (env_cg->opt & IA32_OPT_IMMOPS) ? get_immediate_op(NULL, new_count) : NULL; - - /* Limit imm_op within range imm8 */ - if (imm_op) { - tv = get_ia32_Immop_tarval(imm_op); - - if (tv) { - tv = tarval_mod(tv, new_tarval_from_long(32, get_tarval_mode(tv))); - set_ia32_Immop_tarval(imm_op, tv); - } - else { - imm_op = NULL; - } - } - - /* integer operations */ - if (imm_op) { - /* This is ShiftD with const */ - DB((dbg, LEVEL_1, "ShiftD with immediate ...")); + ir_node *new_op1 = be_transform_node(op1); + ir_node *new_op2 = create_immediate_or_transform(op2, 'I'); + ir_node *new_count = be_transform_node(count); - if (is_ia32_l_ShlD(node)) - new_op = new_rd_ia32_ShlD(dbgi, irg, block, noreg, noreg, - new_op1, new_op2, noreg, nomem); - else - new_op = new_rd_ia32_ShrD(dbgi, irg, block, noreg, noreg, - new_op1, new_op2, noreg, nomem); - copy_ia32_Immop_attr(new_op, imm_op); - } - else { - /* This is a normal ShiftD */ - DB((dbg, LEVEL_1, "ShiftD binop ...")); - if (is_ia32_l_ShlD(node)) - new_op = new_rd_ia32_ShlD(dbgi, irg, block, noreg, noreg, - new_op1, new_op2, new_count, nomem); - else - new_op = new_rd_ia32_ShrD(dbgi, irg, block, noreg, noreg, - new_op1, new_op2, new_count, nomem); - } + /* TODO proper AM support */ - /* set AM support */ - set_ia32_am_support(new_op, ia32_am_Dest, ia32_am_binary); + if (is_ia32_l_ShlD(node)) + new_op = new_rd_ia32_ShlD(dbgi, irg, block, new_op1, new_op2, new_count); + else + new_op = new_rd_ia32_ShrD(dbgi, irg, block, new_op1, new_op2, new_count); SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); - set_ia32_emit_cl(new_op); - return new_op; } @@ -3637,15 +3783,13 @@ static ir_node *gen_ia32_l_X87toSSE(ir_node *node) { set_ia32_frame_ent(res, get_ia32_frame_ent(node)); set_ia32_use_frame(res); set_ia32_ls_mode(res, get_ia32_ls_mode(node)); - set_ia32_am_flavour(res, ia32_B); set_ia32_op_type(res, ia32_AddrModeD); /* Load MEM -> SSE */ - res = new_rd_ia32_xLoad(dbgi, irg, block, new_ptr, noreg, res); + res = new_rd_ia32_xLoad(dbgi, irg, block, new_ptr, noreg, res, + get_ia32_ls_mode(node)); set_ia32_frame_ent(res, get_ia32_frame_ent(node)); set_ia32_use_frame(res); - set_ia32_ls_mode(res, get_ia32_ls_mode(node)); - set_ia32_am_flavour(res, ia32_B); set_ia32_op_type(res, ia32_AddrModeS); res = new_rd_Proj(dbgi, irg, block, res, mode_xmm, pn_ia32_xLoad_res); @@ -3694,7 +3838,6 @@ static ir_node *gen_ia32_l_SSEtoX87(ir_node *node) { set_ia32_frame_ent(res, fent); set_ia32_use_frame(res); set_ia32_ls_mode(res, lsmode); - set_ia32_am_flavour(res, ia32_B); set_ia32_op_type(res, ia32_AddrModeD); mem = res; } @@ -3704,7 +3847,6 @@ static ir_node *gen_ia32_l_SSEtoX87(ir_node *node) { set_ia32_frame_ent(res, fent); set_ia32_use_frame(res); add_ia32_am_offs_int(res, offs); - set_ia32_am_flavour(res, ia32_B); set_ia32_op_type(res, ia32_AddrModeS); res = new_rd_Proj(dbgi, irg, block, res, mode_vfp, pn_ia32_vfld_res); @@ -3784,19 +3926,39 @@ static ir_node *gen_Proj_be_SubSP(ir_node *node) { * Transform and renumber the Projs from a Load. */ static ir_node *gen_Proj_Load(ir_node *node) { + ir_node *new_pred; ir_node *block = be_transform_node(get_nodes_block(node)); ir_node *pred = get_Proj_pred(node); - ir_node *new_pred = be_transform_node(pred); ir_graph *irg = current_ir_graph; dbg_info *dbgi = get_irn_dbg_info(node); long proj = get_Proj_proj(node); + + /* loads might be part of source address mode matches, so we don't + transform the ProjMs yet (with the exception of loads whose result is + not used) + */ + if (is_Load(pred) && proj == pn_Load_M && get_irn_n_edges(pred) > 1) { + assert(pn_ia32_Load_M == 1); /* convention: mem-result of Source-AM + nodes is 1 */ + /* this is needed, because sometimes we have loops that are only + reachable through the ProjM */ + be_enqueue_preds(node); + /* do it in 2 steps, to silence firm verifier */ + ir_node *res = new_rd_Proj(dbgi, irg, block, pred, mode_M, pn_Load_M); + set_Proj_proj(res, pn_ia32_Load_M); + return res; + } + /* renumber the proj */ + new_pred = be_transform_node(pred); if (is_ia32_Load(new_pred)) { if (proj == pn_Load_res) { - return new_rd_Proj(dbgi, irg, block, new_pred, mode_Iu, pn_ia32_Load_res); + return new_rd_Proj(dbgi, irg, block, new_pred, mode_Iu, + pn_ia32_Load_res); } else if (proj == pn_Load_M) { - return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, pn_ia32_Load_M); + return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, + pn_ia32_Load_M); } } else if(is_ia32_Conv_I2I(new_pred)) { set_irn_mode(new_pred, mode_T); @@ -3807,16 +3969,31 @@ static ir_node *gen_Proj_Load(ir_node *node) { } } else if (is_ia32_xLoad(new_pred)) { if (proj == pn_Load_res) { - return new_rd_Proj(dbgi, irg, block, new_pred, mode_xmm, pn_ia32_xLoad_res); + return new_rd_Proj(dbgi, irg, block, new_pred, mode_xmm, + pn_ia32_xLoad_res); } else if (proj == pn_Load_M) { - return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, pn_ia32_xLoad_M); + return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, + pn_ia32_xLoad_M); } } else if (is_ia32_vfld(new_pred)) { if (proj == pn_Load_res) { - return new_rd_Proj(dbgi, irg, block, new_pred, mode_vfp, pn_ia32_vfld_res); + return new_rd_Proj(dbgi, irg, block, new_pred, mode_vfp, + pn_ia32_vfld_res); } else if (proj == pn_Load_M) { - return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, pn_ia32_vfld_M); + return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, + pn_ia32_vfld_M); + } + } else { + /* can happen for ProJMs when source address mode happened for the + node */ + + /* however it should not be the result proj, as that would mean the + load had multiple users and should not have been used for + SourceAM */ + if(proj != pn_Load_M) { + panic("internal error: transformed node not a Load"); } + return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, 1); } assert(0); @@ -4041,30 +4218,16 @@ static ir_node *gen_Proj_be_Call(ir_node *node) { call_mem, mode); set_ia32_op_type(fstp, ia32_AddrModeD); set_ia32_use_frame(fstp); - set_ia32_am_flavour(fstp, ia32_am_B); /* load into SSE register */ - sse_load = new_rd_ia32_xLoad(dbgi, irg, block, frame, noreg, fstp); - set_ia32_ls_mode(sse_load, mode); + sse_load = new_rd_ia32_xLoad(dbgi, irg, block, frame, noreg, fstp, + mode); set_ia32_op_type(sse_load, ia32_AddrModeS); set_ia32_use_frame(sse_load); - set_ia32_am_flavour(sse_load, ia32_am_B); sse_load = new_rd_Proj(dbgi, irg, block, sse_load, mode_xmm, pn_ia32_xLoad_res); -#if 0 - /* now: create new Keep whith all former ins and one additional in - the result Proj */ - - /* get a Proj representing a caller save register */ - p = be_get_Proj_for_pn(call, pn_be_Call_first_res + 1); - assert(is_Proj(p) && "Proj expected."); - - /* user of the the proj is the Keep */ - p = get_edge_src_irn(get_irn_out_edge_first(p)); - assert(be_is_Keep(p) && "Keep expected."); -#endif - return sse_load; } @@ -4091,7 +4254,7 @@ static ir_node *gen_Proj_Cmp(ir_node *node) ir_node *cmp_right = get_Cmp_right(cmp); ir_mode *cmp_mode = get_irn_mode(cmp_left); dbg_info *dbgi = get_irn_dbg_info(cmp); - ir_node *block = be_transform_node(get_nodes_block(node)); + ir_node *block = get_nodes_block(node); ir_node *res; assert(!mode_is_float(cmp_mode)); @@ -4250,6 +4413,7 @@ static void register_transformers(void) GEN(Const); GEN(SymConst); + GEN(Unknown); /* we should never see these nodes */ BAD(Raise); @@ -4274,9 +4438,6 @@ static void register_transformers(void) GEN(be_SubSP); GEN(be_Copy); - /* set the register for all Unknown nodes */ - GEN(Unknown); - op_Mulh = get_op_Mulh(); if (op_Mulh) GEN(Mulh); @@ -4329,7 +4490,7 @@ void add_missing_keep_walker(ir_node *node, void *data) ir_node *proj = get_edge_src_irn(edge); int pn = get_Proj_proj(proj); - assert(pn < n_outs); + assert(get_irn_mode(proj) == mode_M || pn < n_outs); found_projs |= 1 << pn; } @@ -4377,12 +4538,16 @@ void add_missing_keeps(ia32_code_gen_t *cg) /* do the transformation */ void ia32_transform_graph(ia32_code_gen_t *cg) { register_transformers(); - env_cg = cg; + env_cg = cg; initial_fpcw = NULL; + + heights = heights_new(cg->irg); + be_transform_graph(cg->birg, ia32_pretransform_node, cg); - edges_verify(cg->irg); + + heights_free(heights); + heights = NULL; add_missing_keeps(cg); - edges_verify(cg->irg); } void ia32_init_transform(void) diff --git a/ir/be/ia32/ia32_x87.c b/ir/be/ia32/ia32_x87.c index d2cf8cc75..ca09d3b40 100644 --- a/ir/be/ia32/ia32_x87.c +++ b/ir/be/ia32/ia32_x87.c @@ -1226,7 +1226,6 @@ static int sim_store(x87_state *state, ir_node *n, ir_op *op, ir_op *op_p) { set_ia32_frame_ent(vfld, get_ia32_frame_ent(n)); if (is_ia32_use_frame(n)) set_ia32_use_frame(vfld); - set_ia32_am_flavour(vfld, get_ia32_am_flavour(n)); set_ia32_op_type(vfld, ia32_am_Source); add_ia32_am_offs_int(vfld, get_ia32_am_offs_int(n)); set_ia32_am_sc(vfld, get_ia32_am_sc(n)); @@ -1329,15 +1328,15 @@ GEN_STORE(fist) * * @return NO_NODE_ADDED */ -static int sim_fCondJmp(x87_state *state, ir_node *n) { +static int sim_fCmpJmp(x87_state *state, ir_node *n) { int op1_idx; int op2_idx = -1; int pop_cnt = 0; ia32_x87_attr_t *attr; ir_op *dst; x87_simulator *sim = state->sim; - ir_node *op1_node = get_irn_n(n, n_ia32_vfCondJmp_left); - ir_node *op2_node = get_irn_n(n, n_ia32_vfCondJmp_right); + ir_node *op1_node = get_irn_n(n, n_ia32_vfCmpJmp_left); + ir_node *op2_node = get_irn_n(n, n_ia32_vfCmpJmp_right); const arch_register_t *op1 = x87_get_irn_register(sim, op1_node); const arch_register_t *op2 = x87_get_irn_register(sim, op2_node); int reg_index_1 = arch_register_get_index(op1); @@ -2228,7 +2227,7 @@ static void x87_init_simulator(x87_simulator *sim, ir_graph *irg, ASSOC_IA32(fchs); ASSOC_IA32(fist); ASSOC_IA32(fst); - ASSOC_IA32(fCondJmp); + ASSOC_IA32(fCmpJmp); ASSOC_BE(Copy); ASSOC_BE(Call); ASSOC_BE(Spill); -- 2.20.1