From 7f34faa1fcd5a4547f67ffb41c597921ea1d2d2f Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Fri, 24 Aug 2012 18:49:53 +0200 Subject: [PATCH] factorize upper_bits_clean and use in sparc+ia32 This needed some rewriting as ia32 previously checked already transformed nodes while sparc was checking nodes before transformation. Change ia32 to check nodes before transformation too. Also improved some code in sparc+ia32. --- ir/be/betranshlp.c | 160 ++++++++++++++++++++++++++++++---- ir/be/betranshlp.h | 16 ++++ ir/be/ia32/ia32_transform.c | 130 ++++++--------------------- ir/be/sparc/sparc_transform.c | 115 ++---------------------- 4 files changed, 193 insertions(+), 228 deletions(-) diff --git a/ir/be/betranshlp.c b/ir/be/betranshlp.c index d848e4d22..5428ee441 100644 --- a/ir/be/betranshlp.c +++ b/ir/be/betranshlp.c @@ -143,25 +143,6 @@ static ir_node *transform_end(ir_node *node) return new_end; } -void be_start_transform_setup(void) -{ - ir_clear_opcodes_generic_func(); - - be_set_transform_function(op_Bad, be_duplicate_node); - be_set_transform_function(op_be_Copy, be_duplicate_node); - be_set_transform_function(op_be_CopyKeep, be_duplicate_node); - be_set_transform_function(op_be_IncSP, be_duplicate_node); - be_set_transform_function(op_be_Keep, be_duplicate_node); - be_set_transform_function(op_be_Return, be_duplicate_node); - be_set_transform_function(op_be_Start, be_duplicate_node); - be_set_transform_function(op_Block, transform_block); - be_set_transform_function(op_End, transform_end); - be_set_transform_function(op_NoMem, be_duplicate_node); - be_set_transform_function(op_Pin, be_duplicate_node); - be_set_transform_function(op_Start, be_duplicate_node); - be_set_transform_function(op_Sync, be_duplicate_node); -} - ir_node *be_duplicate_node(ir_node *node) { ir_node *block = be_transform_node(get_nodes_block(node)); @@ -401,3 +382,144 @@ void be_transform_graph(ir_graph *irg, arch_pretrans_nodes *func) /* recalculate edges */ edges_activate(irg); } + +bool be_upper_bits_clean(const ir_node *node, ir_mode *mode) +{ + ir_op *op = get_irn_op(node); + if (op->ops.generic1 == NULL) + return false; + upper_bits_clean_func func = (upper_bits_clean_func)op->ops.generic1; + return func(node, mode); +} + +static bool bit_binop_upper_bits_clean(const ir_node *node, ir_mode *mode) +{ + return be_upper_bits_clean(get_binop_left(node), mode) + && be_upper_bits_clean(get_binop_right(node), mode); +} + +static bool mux_upper_bits_clean(const ir_node *node, ir_mode *mode) +{ + return be_upper_bits_clean(get_Mux_true(node), mode) + && be_upper_bits_clean(get_Mux_false(node), mode); +} + +static bool and_upper_bits_clean(const ir_node *node, ir_mode *mode) +{ + if (!mode_is_signed(mode)) { + return be_upper_bits_clean(get_And_left(node), mode) + || be_upper_bits_clean(get_And_right(node), mode); + } else { + return bit_binop_upper_bits_clean(node, mode); + } +} + +static bool shr_upper_bits_clean(const ir_node *node, ir_mode *mode) +{ + if (mode_is_signed(mode)) { + /* TODO */ + return false; + } else { + const ir_node *right = get_Shr_right(node); + if (is_Const(right)) { + ir_tarval *tv = get_Const_tarval(right); + long val = get_tarval_long(tv); + if (val >= 32 - (long)get_mode_size_bits(mode)) + return true; + } + return be_upper_bits_clean(get_Shr_left(node), mode); + } +} + +static bool shrs_upper_bits_clean(const ir_node *node, ir_mode *mode) +{ + return be_upper_bits_clean(get_Shrs_left(node), mode); +} + +static bool const_upper_bits_clean(const ir_node *node, ir_mode *mode) +{ + ir_tarval *tv = get_Const_tarval(node); + long val = get_tarval_long(tv); + if (mode_is_signed(mode)) { + long shifted = val >> (get_mode_size_bits(mode)-1); + return shifted == 0 || shifted == -1; + } else { + unsigned long shifted = (unsigned long)val; + shifted >>= get_mode_size_bits(mode)-1; + shifted >>= 1; + return shifted == 0; + } +} + +static bool conv_upper_bits_clean(const ir_node *node, ir_mode *mode) +{ + ir_mode *dest_mode = get_irn_mode(node); + const ir_node *op = get_Conv_op(node); + ir_mode *src_mode = get_irn_mode(op); + if (mode_is_float(src_mode)) + return true; + + unsigned src_bits = get_mode_size_bits(src_mode); + unsigned dest_bits = get_mode_size_bits(dest_mode); + /* downconvs are a nop */ + if (src_bits >= dest_bits) + return be_upper_bits_clean(op, mode); + /* upconvs are fine if src is big enough or if sign matches */ + if (src_bits <= get_mode_size_bits(mode) + && mode_is_signed(src_mode) == mode_is_signed(mode)) + return true; + return false; +} + +static bool proj_upper_bits_clean(const ir_node *node, ir_mode *mode) +{ + const ir_node *pred = get_Proj_pred(node); + switch (get_irn_opcode(pred)) { + case iro_Load: { + ir_mode *load_mode = get_Load_mode(pred); + unsigned load_bits = get_mode_size_bits(load_mode); + if (load_bits > get_mode_size_bits(mode)) + return false; + if (mode_is_signed(load_mode) != mode_is_signed(mode)) + return false; + return true; + } + default: + break; + } + return false; +} + +void be_set_upper_bits_clean_function(ir_op *op, upper_bits_clean_func func) +{ + op->ops.generic1 = (op_func)func; +} + +void be_start_transform_setup(void) +{ + ir_clear_opcodes_generic_func(); + + be_set_transform_function(op_Bad, be_duplicate_node); + be_set_transform_function(op_be_Copy, be_duplicate_node); + be_set_transform_function(op_be_CopyKeep, be_duplicate_node); + be_set_transform_function(op_be_IncSP, be_duplicate_node); + be_set_transform_function(op_be_Keep, be_duplicate_node); + be_set_transform_function(op_be_Return, be_duplicate_node); + be_set_transform_function(op_be_Start, be_duplicate_node); + be_set_transform_function(op_Block, transform_block); + be_set_transform_function(op_End, transform_end); + be_set_transform_function(op_NoMem, be_duplicate_node); + be_set_transform_function(op_Pin, be_duplicate_node); + be_set_transform_function(op_Start, be_duplicate_node); + be_set_transform_function(op_Sync, be_duplicate_node); + + be_set_upper_bits_clean_function(op_And, and_upper_bits_clean); + be_set_upper_bits_clean_function(op_Const, const_upper_bits_clean); + be_set_upper_bits_clean_function(op_Conv, conv_upper_bits_clean); + be_set_upper_bits_clean_function(op_Eor, bit_binop_upper_bits_clean); + be_set_upper_bits_clean_function(op_Mux, mux_upper_bits_clean); + be_set_upper_bits_clean_function(op_Or, bit_binop_upper_bits_clean); + be_set_upper_bits_clean_function(op_Proj, proj_upper_bits_clean); + be_set_upper_bits_clean_function(op_Shr, shr_upper_bits_clean); + be_set_upper_bits_clean_function(op_Shrs, shrs_upper_bits_clean); +} diff --git a/ir/be/betranshlp.h b/ir/be/betranshlp.h index 4e4784639..96a9c0464 100644 --- a/ir/be/betranshlp.h +++ b/ir/be/betranshlp.h @@ -84,4 +84,20 @@ void be_enqueue_preds(ir_node *node); */ void be_transform_graph(ir_graph *irg, arch_pretrans_nodes *func); +typedef bool (*upper_bits_clean_func)(const ir_node *node, ir_mode *mode); + +/** + * register a test function for be_upper_bits_clean for a specific node + * type. + */ +void be_set_upper_bits_clean_function(ir_op *op, upper_bits_clean_func func); + +/** + * 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 signed + * numbers. + */ +bool be_upper_bits_clean(const ir_node *node, ir_mode *mode); + #endif diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index fd840ff37..1542fcf5e 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -2908,85 +2908,18 @@ static ir_node *create_Ucomi(ir_node *node) return new_node; } -/** - * 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 signed - * 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); - - switch (get_ia32_irn_opcode(transformed_node)) { - case iro_ia32_Conv_I2I: - case iro_ia32_Conv_I2I8Bit: { - 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; - } - - case iro_ia32_Shr: - if (mode_is_signed(mode)) { - return false; /* TODO handle signed modes */ - } else { - 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); - } - - case iro_ia32_Sar: - /* TODO too conservative if shift amount is constant */ - return upper_bits_clean(get_irn_n(transformed_node, n_ia32_Sar_val), mode); - - case iro_ia32_And: - if (!mode_is_signed(mode)) { - return - upper_bits_clean(get_irn_n(transformed_node, n_ia32_And_right), mode) || - upper_bits_clean(get_irn_n(transformed_node, n_ia32_And_left), mode); - } - /* TODO if one is known to be zero extended, then || is sufficient */ - /* FALLTHROUGH */ - case iro_ia32_Or: - case iro_ia32_Xor: - return - upper_bits_clean(get_irn_n(transformed_node, n_ia32_binary_right), mode) && - upper_bits_clean(get_irn_n(transformed_node, n_ia32_binary_left), mode); - - case iro_ia32_Const: - case iro_ia32_Immediate: { - 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); - return shifted == 0 || shifted == -1; - } else { - unsigned long shifted = (unsigned long)attr->offset; - shifted >>= get_mode_size_bits(mode)-1; - shifted >>= 1; - return shifted == 0; - } - } - - default: - return false; +static bool ia32_mux_upper_bits_clean(const ir_node *node, ir_mode *mode) +{ + ir_node *mux_true = get_Mux_true(node); + ir_node *mux_false = get_Mux_false(node); + ir_mode *mux_mode = get_irn_mode(node); + /* mux nodes which get transformed to the set instruction are not clean */ + if (is_Const(mux_true) && is_Const(mux_false) + && get_mode_size_bits(mux_mode) == 8) { + return false; } + return be_upper_bits_clean(mux_true, mode) + && be_upper_bits_clean(mux_false, mode); } /** @@ -3034,8 +2967,9 @@ static ir_node *gen_Cmp(ir_node *node) match_am_and_immediates | match_immediate); /* 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)) { + if (am.op_type == ia32_Normal && + be_upper_bits_clean(and_left, cmp_mode) && + be_upper_bits_clean(and_right, cmp_mode)) { cmp_mode = mode_is_signed(cmp_mode) ? mode_Is : mode_Iu; } @@ -3056,8 +2990,9 @@ static ir_node *gen_Cmp(ir_node *node) match_16bit_am | match_am_and_immediates | match_immediate); /* 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)) { + if (am.op_type == ia32_Normal && + be_upper_bits_clean(left, cmp_mode) && + be_upper_bits_clean(right, cmp_mode)) { cmp_mode = mode_is_signed(cmp_mode) ? mode_Is : mode_Iu; } @@ -3737,7 +3672,7 @@ static ir_node *gen_x87_gp_to_fp(ir_node *node, ir_mode *src_mode) /* first convert to 32 bit signed if necessary */ if (get_mode_size_bits(src_mode) < 32) { - if (!upper_bits_clean(new_op, src_mode)) { + if (!be_upper_bits_clean(op, src_mode)) { new_op = create_Conv_I2I(dbgi, block, noreg_GP, noreg_GP, nomem, new_op, src_mode); SET_IA32_ORIG_NODE(new_op, node); } @@ -3800,16 +3735,11 @@ static ir_node *create_I2I_Conv(ir_mode *src_mode, ir_mode *tgt_mode, { ir_node *new_block = be_transform_node(block); ir_node *new_node; - ir_mode *smaller_mode; ia32_address_mode_t am; ia32_address_t *addr = &am.addr; (void) node; - if (get_mode_size_bits(src_mode) < get_mode_size_bits(tgt_mode)) { - smaller_mode = src_mode; - } else { - smaller_mode = tgt_mode; - } + assert(get_mode_size_bits(src_mode) < get_mode_size_bits(tgt_mode)); #ifdef DEBUG_libfirm if (is_Const(op)) { @@ -3818,25 +3748,19 @@ static ir_node *create_I2I_Conv(ir_mode *src_mode, ir_mode *tgt_mode, } #endif + if (be_upper_bits_clean(op, src_mode)) { + return be_transform_node(op); + } + match_arguments(&am, block, NULL, op, NULL, 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; - } - new_node = create_Conv_I2I(dbgi, new_block, addr->base, addr->index, - addr->mem, am.new_op2, smaller_mode); + addr->mem, am.new_op2, src_mode); set_am_attributes(new_node, &am); /* match_arguments assume that out-mode = in-mode, this isn't true here * so fix it */ - set_ia32_ls_mode(new_node, smaller_mode); + set_ia32_ls_mode(new_node, src_mode); SET_IA32_ORIG_NODE(new_node, node); new_node = fix_mem_proj(new_node, &am); return new_node; @@ -3936,7 +3860,7 @@ static ir_node *gen_Conv(ir_node *node) return be_transform_node(op); } else { /* to int */ - if (src_bits == tgt_bits) { + if (src_bits >= tgt_bits) { DB((dbg, LEVEL_1, "omitting unnecessary Conv(%+F, %+F) ...", src_mode, tgt_mode)); return be_transform_node(op); @@ -5729,6 +5653,8 @@ static void register_transformers(void) be_set_transform_function(op_Switch, gen_Switch); be_set_transform_function(op_SymConst, gen_SymConst); be_set_transform_function(op_Unknown, ia32_gen_Unknown); + + be_set_upper_bits_clean_function(op_Mux, ia32_mux_upper_bits_clean); } /** diff --git a/ir/be/sparc/sparc_transform.c b/ir/be/sparc/sparc_transform.c index 33453f049..8cbc7a8c1 100644 --- a/ir/be/sparc/sparc_transform.c +++ b/ir/be/sparc/sparc_transform.c @@ -150,95 +150,6 @@ static ir_node *gen_sign_extension(dbg_info *dbgi, ir_node *block, ir_node *op, return rshift_node; } -/** - * 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 signed - * numbers. - */ -static bool upper_bits_clean(ir_node *node, ir_mode *mode) -{ - switch ((ir_opcode)get_irn_opcode(node)) { - case iro_And: - if (!mode_is_signed(mode)) { - return upper_bits_clean(get_And_left(node), mode) - || upper_bits_clean(get_And_right(node), mode); - } - /* FALLTHROUGH */ - case iro_Or: - case iro_Eor: - return upper_bits_clean(get_binop_left(node), mode) - && upper_bits_clean(get_binop_right(node), mode); - - case iro_Shr: - if (mode_is_signed(mode)) { - return false; /* TODO */ - } else { - ir_node *right = get_Shr_right(node); - if (is_Const(right)) { - ir_tarval *tv = get_Const_tarval(right); - long val = get_tarval_long(tv); - if (val >= 32 - (long)get_mode_size_bits(mode)) - return true; - } - return upper_bits_clean(get_Shr_left(node), mode); - } - - case iro_Shrs: - return upper_bits_clean(get_Shrs_left(node), mode); - - case iro_Const: { - ir_tarval *tv = get_Const_tarval(node); - long val = get_tarval_long(tv); - if (mode_is_signed(mode)) { - long shifted = val >> (get_mode_size_bits(mode)-1); - return shifted == 0 || shifted == -1; - } else { - unsigned long shifted = (unsigned long)val; - shifted >>= get_mode_size_bits(mode)-1; - shifted >>= 1; - return shifted == 0; - } - } - - case iro_Conv: { - ir_mode *dest_mode = get_irn_mode(node); - ir_node *op = get_Conv_op(node); - ir_mode *src_mode = get_irn_mode(op); - unsigned src_bits = get_mode_size_bits(src_mode); - unsigned dest_bits = get_mode_size_bits(dest_mode); - /* downconvs are a nop */ - if (src_bits <= dest_bits) - return upper_bits_clean(op, mode); - if (dest_bits <= get_mode_size_bits(mode) - && mode_is_signed(dest_mode) == mode_is_signed(mode)) - return true; - return false; - } - - case iro_Proj: { - ir_node *pred = get_Proj_pred(node); - switch (get_irn_opcode(pred)) { - case iro_Load: { - ir_mode *load_mode = get_Load_mode(pred); - unsigned load_bits = get_mode_size_bits(load_mode); - unsigned bits = get_mode_size_bits(mode); - if (load_bits > bits) - return false; - if (mode_is_signed(mode) != mode_is_signed(load_mode)) - return false; - return true; - } - default: - break; - } - } - default: - break; - } - return false; -} - /** * Extend a value to 32 bit signed/unsigned depending on its mode. * @@ -290,9 +201,10 @@ static bool is_imm_encodeable(const ir_node *node) static bool needs_extension(ir_node *op) { ir_mode *mode = get_irn_mode(op); - if (get_mode_size_bits(mode) >= get_mode_size_bits(mode_gp)) + unsigned gp_bits = get_mode_size_bits(mode_gp); + if (get_mode_size_bits(mode) >= gp_bits) return false; - return !upper_bits_clean(op, mode); + return !be_upper_bits_clean(op, mode); } /** @@ -1451,31 +1363,20 @@ static ir_node *gen_Conv(ir_node *node) return create_itof(dbgi, block, new_op, dst_mode); } } else { /* complete in gp registers */ - int min_bits; - ir_mode *min_mode; - - if (src_bits == dst_bits || dst_mode == mode_b) { + if (src_bits >= dst_bits || dst_mode == mode_b) { /* kill unnecessary conv */ return be_transform_node(op); } - if (src_bits < dst_bits) { - min_bits = src_bits; - min_mode = src_mode; - } else { - min_bits = dst_bits; - min_mode = dst_mode; - } - - if (upper_bits_clean(op, min_mode)) { + if (be_upper_bits_clean(op, src_mode)) { return be_transform_node(op); } new_op = be_transform_node(op); - if (mode_is_signed(min_mode)) { - return gen_sign_extension(dbgi, block, new_op, min_bits); + if (mode_is_signed(src_mode)) { + return gen_sign_extension(dbgi, block, new_op, src_bits); } else { - return gen_zero_extension(dbgi, block, new_op, min_bits); + return gen_zero_extension(dbgi, block, new_op, src_bits); } } } -- 2.20.1