X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_transform.c;h=12964ac87f5122c8c9b7d9adc88cee7496735583;hb=6ef0d11278cb4d11676371841ddb8f227233252b;hp=09fc6ea72d3dbfcf8d6ee0e35b5d395715b1d559;hpb=74194113b6ad5cf692412a8fe50957305ed6a7b3;p=libfirm diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index 09fc6ea72..12964ac87 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -29,6 +29,7 @@ #endif #include +#include #include "irargs_t.h" #include "irnode_t.h" @@ -47,6 +48,7 @@ #include "irdom.h" #include "archop.h" #include "error.h" +#include "array_t.h" #include "height.h" #include "../benode_t.h" @@ -131,46 +133,46 @@ static ir_node *create_I2I_Conv(ir_mode *src_mode, ir_mode *tgt_mode, ir_node *op, ir_node *orig_node); /** Return non-zero is a node represents the 0 constant. */ -static int is_Const_0(ir_node *node) { +static bool is_Const_0(ir_node *node) { return is_Const(node) && is_Const_null(node); } /** Return non-zero is a node represents the 1 constant. */ -static int is_Const_1(ir_node *node) { +static bool is_Const_1(ir_node *node) { return is_Const(node) && is_Const_one(node); } /** Return non-zero is a node represents the -1 constant. */ -static int is_Const_Minus_1(ir_node *node) { +static bool is_Const_Minus_1(ir_node *node) { return is_Const(node) && is_Const_all_one(node); } /** * returns true if constant can be created with a simple float command */ -static int is_simple_x87_Const(ir_node *node) +static bool is_simple_x87_Const(ir_node *node) { tarval *tv = get_Const_tarval(node); if (tarval_is_null(tv) || tarval_is_one(tv)) - return 1; + return true; /* TODO: match all the other float constants */ - return 0; + return false; } /** * returns true if constant can be created with a simple float command */ -static int is_simple_sse_Const(ir_node *node) +static bool is_simple_sse_Const(ir_node *node) { tarval *tv = get_Const_tarval(node); ir_mode *mode = get_tarval_mode(tv); if (mode == mode_F) - return 1; + return true; if (tarval_is_null(tv) || tarval_is_one(tv)) - return 1; + return true; if (mode == mode_D) { unsigned val = get_tarval_sub_bits(tv, 0) | @@ -179,11 +181,11 @@ static int is_simple_sse_Const(ir_node *node) (get_tarval_sub_bits(tv, 3) << 24); if (val == 0) /* lower 32bit are zero, really a 32bit constant */ - return 1; + return true; } /* TODO: match all the other float constants */ - return 0; + return false; } /** @@ -431,44 +433,6 @@ ir_entity *ia32_gen_fp_known_const(ia32_known_const_t kct) { return ent_cache[kct]; } -static int prevents_AM(ir_node *const block, ir_node *const am_candidate, - ir_node *const other) -{ - if (get_nodes_block(other) != block) - return 0; - - if (is_Sync(other)) { - int i; - - for (i = get_Sync_n_preds(other) - 1; i >= 0; --i) { - ir_node *const pred = get_Sync_pred(other, i); - - if (get_nodes_block(pred) != block) - continue; - - /* Do not block ourselves from getting eaten */ - if (is_Proj(pred) && get_Proj_pred(pred) == am_candidate) - continue; - - if (!heights_reachable_in_block(heights, pred, am_candidate)) - continue; - - return 1; - } - - return 0; - } else { - /* Do not block ourselves from getting eaten */ - if (is_Proj(other) && get_Proj_pred(other) == am_candidate) - return 0; - - if (!heights_reachable_in_block(heights, other, am_candidate)) - return 0; - - return 1; - } -} - /** * return true if the node is a Proj(Load) and could be used in source address * mode for another node. Will return only true if the @p other node is not @@ -530,6 +494,7 @@ struct ia32_address_mode_t { ia32_address_t addr; ir_mode *ls_mode; ir_node *mem_proj; + ir_node *am_node; ia32_op_type_t op_type; ir_node *new_op1; ir_node *new_op2; @@ -580,6 +545,7 @@ static void build_address(ia32_address_mode_t *am, ir_node *node) am->pinned = get_irn_pinned(load); am->ls_mode = get_Load_mode(load); am->mem_proj = be_get_Proj_for_pn(load, pn_Load_M); + am->am_node = node; /* construct load address */ ia32_create_address_mode(addr, ptr, /*force=*/0); @@ -771,20 +737,19 @@ static void match_arguments(ia32_address_mode_t *am, ir_node *block, } am->op_type = ia32_AddrModeS; } else { + am->op_type = ia32_Normal; + if (flags & match_try_am) { am->new_op1 = NULL; am->new_op2 = NULL; - am->op_type = ia32_Normal; return; } new_op1 = (op1 == NULL ? NULL : be_transform_node(op1)); if (new_op2 == NULL) new_op2 = be_transform_node(op2); - am->op_type = ia32_Normal; - am->ls_mode = get_irn_mode(op2); - if (flags & match_mode_neutral) - am->ls_mode = mode_Iu; + am->ls_mode = + (flags & match_mode_neutral ? mode_Iu : get_irn_mode(op2)); } if (addr->base == NULL) addr->base = noreg_gp; @@ -798,6 +763,12 @@ static void match_arguments(ia32_address_mode_t *am, ir_node *block, am->commutative = commutative; } +static void set_transformed_and_mark(ir_node *const old_node, ir_node *const new_node) +{ + mark_irn_visited(old_node); + be_set_transformed_node(old_node, new_node); +} + static ir_node *fix_mem_proj(ir_node *node, ia32_address_mode_t *am) { ir_mode *mode; @@ -810,8 +781,7 @@ static ir_node *fix_mem_proj(ir_node *node, ia32_address_mode_t *am) mode = get_irn_mode(node); load = get_Proj_pred(am->mem_proj); - mark_irn_visited(load); - be_set_transformed_node(load, node); + set_transformed_and_mark(load, node); if (mode != mode_T) { set_irn_mode(node, mode_T); @@ -849,7 +819,7 @@ static ir_node *gen_binop(ir_node *node, ir_node *op1, ir_node *op2, 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_am_support(new_node, ia32_am_none); SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node)); new_node = fix_mem_proj(new_node, &am); @@ -899,7 +869,7 @@ static ir_node *gen_binop_flags(ir_node *node, construct_binop_flags_func *func, 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_am_support(new_node, ia32_am_none); SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node)); new_node = fix_mem_proj(new_node, &am); @@ -1209,37 +1179,32 @@ static ir_node *gen_Mul(ir_node *node) { */ static ir_node *gen_Mulh(ir_node *node) { - ir_node *block = get_nodes_block(node); - ir_node *new_block = be_transform_node(block); - ir_graph *irg = current_ir_graph; - dbg_info *dbgi = get_irn_dbg_info(node); - ir_mode *mode = get_irn_mode(node); - ir_node *op1 = get_Mulh_left(node); - ir_node *op2 = get_Mulh_right(node); - ir_node *proj_res_high; - ir_node *new_node; - ia32_address_mode_t am; - ia32_address_t *addr = &am.addr; + ir_node *block = get_nodes_block(node); + ir_node *new_block = be_transform_node(block); + ir_graph *irg = current_ir_graph; + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *op1 = get_Mulh_left(node); + ir_node *op2 = get_Mulh_right(node); + ir_mode *mode = get_irn_mode(node); + construct_binop_func *func; + ir_node *proj_res_high; + ir_node *new_node; + ia32_address_mode_t am; + ia32_address_t *addr = &am.addr; assert(!mode_is_float(mode) && "Mulh with float not supported"); assert(get_mode_size_bits(mode) == 32); match_arguments(&am, block, op1, op2, NULL, match_commutative | match_am); - if (mode_is_signed(mode)) { - new_node = new_rd_ia32_IMul1OP(dbgi, irg, new_block, addr->base, - addr->index, addr->mem, am.new_op1, - am.new_op2); - } else { - new_node = new_rd_ia32_Mul(dbgi, irg, new_block, addr->base, - addr->index, addr->mem, am.new_op1, - am.new_op2); - } + func = mode_is_signed(mode) ? new_rd_ia32_IMul1OP : new_rd_ia32_Mul; + new_node = func(dbgi, irg, new_block, addr->base, addr->index, addr->mem, + am.new_op1, am.new_op2); 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_am_support(new_node, ia32_am_none); SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node)); assert(get_irn_mode(new_node) == mode_T); @@ -2021,12 +1986,6 @@ static int use_dest_am(ir_node *block, ir_node *node, ir_node *mem, return 1; } -static void set_transformed_and_mark(ir_node *const old_node, ir_node *const new_node) -{ - mark_irn_visited(old_node); - be_set_transformed_node(old_node, new_node); -} - 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, @@ -2038,6 +1997,7 @@ static ir_node *dest_am_binop(ir_node *node, ir_node *op1, ir_node *op2, ir_node *noreg_gp = ia32_new_NoReg_gp(env_cg); ir_graph *irg = current_ir_graph; dbg_info *dbgi; + ir_node *new_mem; ir_node *new_node; ir_node *new_op; ir_node *mem_proj; @@ -2067,13 +2027,15 @@ static ir_node *dest_am_binop(ir_node *node, ir_node *op1, ir_node *op2, if(addr->mem == NULL) addr->mem = new_NoMem(); - dbgi = get_irn_dbg_info(node); - block = be_transform_node(src_block); + dbgi = get_irn_dbg_info(node); + block = be_transform_node(src_block); + new_mem = transform_AM_mem(irg, block, am.am_node, mem, addr->mem); + if(get_mode_size_bits(mode) == 8) { new_node = func8bit(dbgi, irg, block, addr->base, addr->index, - addr->mem, new_op); + new_mem, new_op); } else { - new_node = func(dbgi, irg, block, addr->base, addr->index, addr->mem, + new_node = func(dbgi, irg, block, addr->base, addr->index, new_mem, new_op); } set_address(new_node, addr); @@ -2092,12 +2054,13 @@ 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_graph *irg = current_ir_graph; - ir_node *src_block = get_nodes_block(node); - ir_node *block; + ir_graph *irg = current_ir_graph; + ir_node *src_block = get_nodes_block(node); + ir_node *block; dbg_info *dbgi; - ir_node *new_node; - ir_node *mem_proj; + ir_node *new_mem; + ir_node *new_node; + ir_node *mem_proj; ia32_address_mode_t am; ia32_address_t *addr = &am.addr; memset(&am, 0, sizeof(am)); @@ -2109,7 +2072,8 @@ static ir_node *dest_am_unop(ir_node *node, ir_node *op, ir_node *mem, dbgi = get_irn_dbg_info(node); block = be_transform_node(src_block); - new_node = func(dbgi, irg, block, addr->base, addr->index, addr->mem); + new_mem = transform_AM_mem(irg, block, am.am_node, mem, addr->mem); + new_node = func(dbgi, irg, block, addr->base, addr->index, new_mem); set_address(new_node, addr); set_ia32_op_type(new_node, ia32_AddrModeD); set_ia32_ls_mode(new_node, mode); @@ -2700,10 +2664,10 @@ static ir_node *create_Ucomi(ir_node *node) } /** - * helper function: checks wether all Cmp projs are Lg or Eq which is needed + * helper function: checks whether all Cmp projs are Lg or Eq which is needed * to fold an and into a test node */ -static int can_fold_test_and(ir_node *node) +static bool can_fold_test_and(ir_node *node) { const ir_edge_t *edge; @@ -2712,10 +2676,84 @@ static int can_fold_test_and(ir_node *node) ir_node *proj = get_edge_src_irn(edge); pn_Cmp pnc = get_Proj_proj(proj); if(pnc != pn_Cmp_Eq && pnc != pn_Cmp_Lg) - return 0; + return false; } - return 1; + return true; +} + +/** + * returns true if it is assured, that the upper bits of a node are "clean" + * which means for a 16 or 8 bit value, that the upper bits in the register + * are 0 for unsigned and a copy of the last significant bit for unsigned + * numbers. + */ +static bool upper_bits_clean(ir_node *transformed_node, ir_mode *mode) +{ + assert(ia32_mode_needs_gp_reg(mode)); + if (get_mode_size_bits(mode) >= 32) + return true; + + if (is_Proj(transformed_node)) + return upper_bits_clean(get_Proj_pred(transformed_node), mode); + + if (is_ia32_Conv_I2I(transformed_node) + || is_ia32_Conv_I2I8Bit(transformed_node)) { + ir_mode *smaller_mode = get_ia32_ls_mode(transformed_node); + if (mode_is_signed(smaller_mode) != mode_is_signed(mode)) + return false; + if (get_mode_size_bits(smaller_mode) > get_mode_size_bits(mode)) + return false; + + return true; + } + + if (is_ia32_Shr(transformed_node) && !mode_is_signed(mode)) { + ir_node *right = get_irn_n(transformed_node, n_ia32_Shr_count); + if (is_ia32_Immediate(right) || is_ia32_Const(right)) { + const ia32_immediate_attr_t *attr + = get_ia32_immediate_attr_const(right); + if (attr->symconst == 0 + && (unsigned) attr->offset >= (32 - get_mode_size_bits(mode))) { + return true; + } + } + return upper_bits_clean(get_irn_n(transformed_node, n_ia32_Shr_val), mode); + } + + if (is_ia32_And(transformed_node) && !mode_is_signed(mode)) { + ir_node *right = get_irn_n(transformed_node, n_ia32_And_right); + if (is_ia32_Immediate(right) || is_ia32_Const(right)) { + const ia32_immediate_attr_t *attr + = get_ia32_immediate_attr_const(right); + if (attr->symconst == 0 + && (unsigned) attr->offset + <= (0xffffffff >> (32 - get_mode_size_bits(mode)))) { + return true; + } + } + /* TODO recurse? */ + } + + /* TODO recurse on Or, Xor, ... if appropriate? */ + + if (is_ia32_Immediate(transformed_node) + || is_ia32_Const(transformed_node)) { + const ia32_immediate_attr_t *attr + = get_ia32_immediate_attr_const(transformed_node); + if (mode_is_signed(mode)) { + long shifted = attr->offset >> (get_mode_size_bits(mode) - 1); + if (shifted == 0 || shifted == -1) + return true; + } else { + unsigned long shifted = (unsigned long) attr->offset; + shifted >>= get_mode_size_bits(mode); + if (shifted == 0) + return true; + } + } + + return false; } /** @@ -2754,22 +2792,35 @@ static ir_node *gen_Cmp(ir_node *node) /* Test(and_left, and_right) */ ir_node *and_left = get_And_left(left); ir_node *and_right = get_And_right(left); - ir_mode *mode = get_irn_mode(and_left); + + /* matze: code here used mode instead of cmd_mode, I think it is always + * the same as cmp_mode, but I leave this here to see if this is really + * true... + */ + assert(get_irn_mode(and_left) == cmp_mode); match_arguments(&am, block, and_left, and_right, NULL, match_commutative | match_am | match_8bit_am | match_16bit_am | match_am_and_immediates | match_immediate | match_8bit | match_16bit); - if (get_mode_size_bits(mode) == 8) { + + /* use 32bit compare mode if possible since the opcode is smaller */ + if (upper_bits_clean(am.new_op1, cmp_mode) && + upper_bits_clean(am.new_op2, cmp_mode)) { + cmp_mode = mode_is_signed(cmp_mode) ? mode_Is : mode_Iu; + } + + if (get_mode_size_bits(cmp_mode) == 8) { new_node = new_rd_ia32_Test8Bit(dbgi, irg, new_block, addr->base, - addr->index, addr->mem, am.new_op1, - am.new_op2, am.ins_permuted, - cmp_unsigned); + addr->index, addr->mem, am.new_op1, + am.new_op2, am.ins_permuted, + cmp_unsigned); } else { new_node = new_rd_ia32_Test(dbgi, irg, new_block, addr->base, - addr->index, addr->mem, am.new_op1, - am.new_op2, am.ins_permuted, cmp_unsigned); + addr->index, addr->mem, am.new_op1, + am.new_op2, am.ins_permuted, + cmp_unsigned); } } else { /* Cmp(left, right) */ @@ -2777,6 +2828,12 @@ static ir_node *gen_Cmp(ir_node *node) match_commutative | match_am | match_8bit_am | match_16bit_am | match_am_and_immediates | match_immediate | match_8bit | match_16bit); + /* use 32bit compare mode if possible since the opcode is smaller */ + if (upper_bits_clean(am.new_op1, cmp_mode) && + upper_bits_clean(am.new_op2, cmp_mode)) { + cmp_mode = mode_is_signed(cmp_mode) ? mode_Is : mode_Iu; + } + if (get_mode_size_bits(cmp_mode) == 8) { new_node = new_rd_ia32_Cmp8Bit(dbgi, irg, new_block, addr->base, addr->index, addr->mem, am.new_op1, @@ -3217,6 +3274,17 @@ static ir_node *create_I2I_Conv(ir_mode *src_mode, ir_mode *tgt_mode, match_arguments(&am, block, NULL, op, NULL, match_8bit | match_16bit | match_am | match_8bit_am | match_16bit_am); + + if (upper_bits_clean(am.new_op2, smaller_mode)) { + /* unnecessary conv. in theory it shouldn't have been AM */ + assert(is_ia32_NoReg_GP(addr->base)); + assert(is_ia32_NoReg_GP(addr->index)); + assert(is_NoMem(addr->mem)); + assert(am.addr.offset == 0); + assert(am.addr.symconst_ent == NULL); + return am.new_op2; + } + if (smaller_bits == 8) { new_node = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, new_block, addr->base, addr->index, addr->mem, am.new_op2, @@ -3490,8 +3558,7 @@ static ir_node *gen_be_Return(ir_node *node) { arity, in); copy_node_attr(barrier, new_barrier); be_duplicate_deps(barrier, new_barrier); - be_set_transformed_node(barrier, new_barrier); - mark_irn_visited(barrier); + set_transformed_and_mark(barrier, new_barrier); /* transform normally */ return be_duplicate_node(node); @@ -3505,7 +3572,8 @@ static ir_node *gen_be_AddSP(ir_node *node) ir_node *sz = get_irn_n(node, be_pos_AddSP_size); ir_node *sp = get_irn_n(node, be_pos_AddSP_old_sp); - return gen_binop(node, sp, sz, new_rd_ia32_SubSP, match_am); + return gen_binop(node, sp, sz, new_rd_ia32_SubSP, + match_am | match_immediate); } /** @@ -3516,7 +3584,8 @@ static ir_node *gen_be_SubSP(ir_node *node) ir_node *sz = get_irn_n(node, be_pos_SubSP_size); ir_node *sp = get_irn_n(node, be_pos_SubSP_old_sp); - return gen_binop(node, sp, sz, new_rd_ia32_AddSP, match_am); + return gen_binop(node, sp, sz, new_rd_ia32_AddSP, + match_am | match_immediate); } /** @@ -3913,8 +3982,7 @@ static ir_node *gen_Proj_be_AddSP(ir_node *node) { return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, pn_ia32_SubSP_M); } - assert(0); - return new_rd_Unknown(irg, get_irn_mode(node)); + panic("No idea how to transform proj->AddSP"); } /** @@ -3937,8 +4005,7 @@ static ir_node *gen_Proj_be_SubSP(ir_node *node) { return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, pn_ia32_AddSP_M); } - assert(0); - return new_rd_Unknown(irg, get_irn_mode(node)); + panic("No idea how to transform proj->SubSP"); } /** @@ -4036,8 +4103,7 @@ static ir_node *gen_Proj_Load(ir_node *node) { return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, 1); } - assert(0); - return new_rd_Unknown(irg, get_irn_mode(node)); + panic("No idea how to transform proj"); } /** @@ -4049,7 +4115,6 @@ static ir_node *gen_Proj_DivMod(ir_node *node) { ir_node *new_pred = be_transform_node(pred); ir_graph *irg = current_ir_graph; dbg_info *dbgi = get_irn_dbg_info(node); - ir_mode *mode = get_irn_mode(node); long proj = get_Proj_proj(node); assert(is_ia32_Div(new_pred) || is_ia32_IDiv(new_pred)); @@ -4104,8 +4169,7 @@ static ir_node *gen_Proj_DivMod(ir_node *node) { break; } - assert(0); - return new_rd_Unknown(irg, mode); + panic("No idea how to transform proj->DivMod"); } /** @@ -4117,7 +4181,6 @@ static ir_node *gen_Proj_CopyB(ir_node *node) { ir_node *new_pred = be_transform_node(pred); ir_graph *irg = current_ir_graph; dbg_info *dbgi = get_irn_dbg_info(node); - ir_mode *mode = get_irn_mode(node); long proj = get_Proj_proj(node); switch(proj) { @@ -4132,8 +4195,7 @@ static ir_node *gen_Proj_CopyB(ir_node *node) { break; } - assert(0); - return new_rd_Unknown(irg, mode); + panic("No idea how to transform proj->CopyB"); } /** @@ -4145,7 +4207,6 @@ static ir_node *gen_Proj_Quot(ir_node *node) { ir_node *new_pred = be_transform_node(pred); ir_graph *irg = current_ir_graph; dbg_info *dbgi = get_irn_dbg_info(node); - ir_mode *mode = get_irn_mode(node); long proj = get_Proj_proj(node); switch(proj) { @@ -4169,8 +4230,7 @@ static ir_node *gen_Proj_Quot(ir_node *node) { break; } - assert(0); - return new_rd_Unknown(irg, mode); + panic("No idea how to transform proj->Quot"); } static ir_node *gen_be_Call(ir_node *node) { @@ -4350,8 +4410,7 @@ static ir_node *gen_Proj(ir_node *node) { if (proj == pn_Store_M) { return be_transform_node(pred); } else { - assert(0); - return new_r_Bad(current_ir_graph); + panic("No idea how to transform proj->Store"); } case iro_Load: return gen_Proj_Load(node);