From cbad497b164779690cd1e4ff25d2a82dba2eef05 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Wed, 22 Aug 2012 16:41:09 +0200 Subject: [PATCH] add more Conv(Conv) localopt rules --- include/libfirm/irmode.h | 17 ++++-- ir/ir/irmode.c | 42 ++++++++------ ir/ir/iropt.c | 115 +++++++++++++++++++++++++++++---------- ir/ir/iropt_t.h | 5 ++ ir/opt/convopt.c | 16 +++--- 5 files changed, 136 insertions(+), 59 deletions(-) diff --git a/include/libfirm/irmode.h b/include/libfirm/irmode.h index 4795f08b2..b22e34753 100644 --- a/include/libfirm/irmode.h +++ b/include/libfirm/irmode.h @@ -330,20 +330,25 @@ FIRM_API int mode_is_datab (const ir_mode *mode); FIRM_API int mode_is_dataM (const ir_mode *mode); /** - * Returns true if sm can be converted to lm without loss - * according to firm definition. + * Returns true if a value of mode @p sm can be converted to mode @p lm without + * loss. * - * Note that mode_Iu is NOT smaller than mode_Is here. + * That is the interpretation of the numbers does not changes, so you a signed + * integer mode is never smaller than an unsigned integer mode since the + * unsigned mode can't represent negative numbers in a way that they are + * interpreted as negative numbers. * * @see values_in_mode() */ FIRM_API int smaller_mode(const ir_mode *sm, const ir_mode *lm); /** - * Returns true if a value of mode sm can be converted into mode lm - * and backwards without loss. + * Returns true if no information is lost when converting a value of mode @p sm + * into mode @p lm (and back to mode @p sm). * - * Note that mode_Iu values CAN be converted in mode_Is and back. + * So the interpretation of the values may change in the intermediate mode @p sm + * (for example when converting negative signed integer numbers into unsigned + * integers) but after a conversion back they are exactly the same value. * * @see smaller_mode() */ diff --git a/ir/ir/irmode.c b/ir/ir/irmode.c index 736d3de72..f41605439 100644 --- a/ir/ir/irmode.c +++ b/ir/ir/irmode.c @@ -506,28 +506,34 @@ int smaller_mode(const ir_mode *sm, const ir_mode *lm) int values_in_mode(const ir_mode *sm, const ir_mode *lm) { - ir_mode_arithmetic arith; - - assert(sm); - assert(lm); - - if (sm == lm) return 1; + if (sm == lm) + return true; if (sm == mode_b) - return mode_is_int(lm); - - arith = get_mode_arithmetic(sm); - if (arith != get_mode_arithmetic(lm)) - return 0; - - switch (arith) { - case irma_twos_complement: - case irma_ieee754: + return mode_is_int(lm) || mode_is_float(lm); + + ir_mode_arithmetic larith = get_mode_arithmetic(lm); + ir_mode_arithmetic sarith = get_mode_arithmetic(sm); + switch (larith) { + case irma_x86_extended_float: + case irma_ieee754: + if (sarith == irma_ieee754 || sarith == irma_x86_extended_float) { return get_mode_size_bits(sm) <= get_mode_size_bits(lm); - - default: - return 0; + } else if (sarith == irma_twos_complement) { + unsigned int_mantissa = get_mode_size_bits(sm) - (mode_is_signed(sm) ? 1 : 0); + unsigned float_mantissa = get_mode_mantissa_size(lm) + 1; + return int_mantissa <= float_mantissa; + } + break; + case irma_twos_complement: + if (sarith == irma_twos_complement) { + return get_mode_size_bits(sm) <= get_mode_size_bits(lm); + } + break; + case irma_none: + break; } + return false; } ir_mode *get_reference_mode_signed_eq(ir_mode *mode) diff --git a/ir/ir/iropt.c b/ir/ir/iropt.c index 0667f74c3..d37db02cc 100644 --- a/ir/ir/iropt.c +++ b/ir/ir/iropt.c @@ -50,6 +50,7 @@ #include "firm_types.h" #include "bitfiddle.h" #include "be.h" +#include "error.h" #include "entity_t.h" @@ -1109,34 +1110,10 @@ static ir_node *equivalent_node_Conv(ir_node *n) ir_node *b = get_Conv_op(a); ir_mode *b_mode = get_irn_mode(b); - if (n_mode == b_mode) { - if (n_mode == mode_b) { - n = b; /* Convb(Conv*(xxxb(...))) == xxxb(...) */ - DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV); - return n; - } else if (get_mode_arithmetic(n_mode) == get_mode_arithmetic(a_mode)) { - if (values_in_mode(b_mode, a_mode)) { - n = b; /* ConvS(ConvL(xxxS(...))) == xxxS(...) */ - DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV); - return n; - } - } - if (mode_is_int(n_mode) && get_mode_arithmetic(a_mode) == irma_ieee754) { - /* ConvI(ConvF(I)) -> I, iff float mantissa >= int mode */ - unsigned int_mantissa = get_mode_size_bits(n_mode) - (mode_is_signed(n_mode) ? 1 : 0); - unsigned float_mantissa = get_mode_mantissa_size(a_mode); - - if (float_mantissa >= int_mantissa) { - n = b; - DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV); - return n; - } - } - if (is_Conv(b) && smaller_mode(b_mode, a_mode)) { - n = b; /* ConvA(ConvB(ConvA(...))) == ConvA(...) */ - DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV); - return n; - } + if (n_mode == b_mode && values_in_mode(b_mode, a_mode)) { + n = b; + DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV); + return n; } } return n; @@ -5487,6 +5464,77 @@ static ir_node *transform_node_Rotl(ir_node *n) return n; } +/** + * returns mode size for may_leave_out_middle_mode + */ +static unsigned get_significand_size(ir_mode *mode) +{ + const ir_mode_arithmetic arithmetic = get_mode_arithmetic(mode); + switch (arithmetic) { + case irma_ieee754: + case irma_x86_extended_float: + return get_mode_mantissa_size(mode) + 1; + case irma_twos_complement: + return get_mode_size_bits(mode); + case irma_none: + panic("Conv node with irma_none mode?"); + } + panic("unexpected mode_arithmetic in get_significand_size"); +} + +/** + * Returns true if a conversion from mode @p m0 to @p m1 has the same effect + * as converting from @p m0 to @p m1 and then to @p m2. + * Classifying the 3 modes as the big(b), middle(m) and small(s) mode this + * gives the following truth table: + * s -> b -> m : true + * s -> m -> b : !signed(s) || signed(m) + * m -> b -> s : true + * m -> s -> b : false + * b -> s -> m : false + * b -> m -> s : true + * + * s -> b -> b : true + * s -> s -> b : false + * + * additional float constraints: + * F -> F -> F: fine + * F -> I -> I: signedness of Is must match + * I -> F -> I: signedness of Is must match + * I -> I -> F: signedness of Is must match + * F -> I -> F: bad + * I -> F -> F: fine + * F -> F -> I: fine + * at least 1 float involved: signedness must match + */ +bool may_leave_out_middle_conv(ir_mode *m0, ir_mode *m1, ir_mode *m2) +{ + int n_floats = mode_is_float(m0) + mode_is_float(m1) + mode_is_float(m2); + if (n_floats == 1) { +#if 0 + int n_signed = mode_is_signed(m0) + mode_is_signed(m1) + + mode_is_signed(m2); + /* we assume that float modes are always signed */ + if ((n_signed & 1) != 1) + return false; +#else + /* because overflow gives strange results we don't touch this case */ + return false; +#endif + } else if (n_floats == 2 && !mode_is_float(m1)) { + return false; + } + + unsigned size0 = get_significand_size(m0); + unsigned size1 = get_significand_size(m1); + unsigned size2 = get_significand_size(m2); + if (size1 < size2 && size0 >= size1) + return false; + if (size1 >= size2) + return true; + return !mode_is_signed(m0) || mode_is_signed(m1); +} + /** * Transform a Conv. */ @@ -5496,6 +5544,17 @@ static ir_node *transform_node_Conv(ir_node *n) ir_mode *mode = get_irn_mode(n); ir_node *a = get_Conv_op(n); + if (is_Conv(a)) { + ir_mode *a_mode = get_irn_mode(a); + ir_node *b = get_Conv_op(a); + ir_mode *b_mode = get_irn_mode(b); + if (may_leave_out_middle_conv(b_mode, a_mode, mode)) { + dbg_info *dbgi = get_irn_dbg_info(n); + ir_node *block = get_nodes_block(n); + return new_rd_Conv(dbgi, block, b, mode); + } + } + if (mode != mode_b && is_const_Phi(a)) { /* Do NOT optimize mode_b Conv's, this leads to remaining * Phib nodes later, because the conv_b_lower operation diff --git a/ir/ir/iropt_t.h b/ir/ir/iropt_t.h index effa924e3..ebf8cad11 100644 --- a/ir/ir/iropt_t.h +++ b/ir/ir/iropt_t.h @@ -138,6 +138,11 @@ ir_node *ir_get_abs_op(const ir_node *sel, ir_node *mux_false, bool ir_is_optimizable_mux(const ir_node *sel, const ir_node *mux_false, const ir_node *mux_true); +/** + * Returns true if Conv_m0(Conv_m1( x_m2)) is equivalent to Conv_m0(x_m2) + */ +bool may_leave_out_middle_conv(ir_mode *m0, ir_mode *m1, ir_mode *m2); + void ir_register_opt_node_ops(void); #endif diff --git a/ir/opt/convopt.c b/ir/opt/convopt.c index ee9b382de..fac7e328d 100644 --- a/ir/opt/convopt.c +++ b/ir/opt/convopt.c @@ -109,7 +109,6 @@ static int get_conv_costs(const ir_node *node, ir_mode *dest_mode) return 0; if (is_Const(node)) { - /* TODO tarval module is incomplete and can't convert floats to ints */ return conv_const_tv(node, dest_mode) == tarval_bad ? 1 : 0; } @@ -155,10 +154,14 @@ static int get_conv_costs(const ir_node *node, ir_mode *dest_mode) ir_node *pred = get_Conv_op(node); ir_mode *pred_mode = get_irn_mode(pred); - if (!values_in_mode(dest_mode, pred_mode)) { + if (smaller_mode(pred_mode, dest_mode)) { + return get_conv_costs(get_Conv_op(node), dest_mode) - 1; + } + if (may_leave_out_middle_conv(pred_mode, mode, dest_mode)) { + return 0; + } else { return 1; } - return get_conv_costs(get_Conv_op(node), dest_mode) - 1; } if (!is_optimizable_node(node, dest_mode)) { @@ -197,7 +200,6 @@ static ir_node *conv_transform(ir_node *node, ir_mode *dest_mode) return node; if (is_Const(node)) { - /* TODO tarval module is incomplete and can't convert floats to ints */ ir_tarval *tv = conv_const_tv(node, dest_mode); if (tv == tarval_bad) { return place_conv(node, dest_mode); @@ -224,10 +226,10 @@ static ir_node *conv_transform(ir_node *node, ir_mode *dest_mode) ir_node *pred = get_Conv_op(node); ir_mode *pred_mode = get_irn_mode(pred); - if (!values_in_mode(dest_mode, pred_mode)) { - return place_conv(node, dest_mode); + if (smaller_mode(pred_mode, dest_mode)) { + return conv_transform(get_Conv_op(node), dest_mode); } - return conv_transform(get_Conv_op(node), dest_mode); + return place_conv(node, dest_mode); } if (!is_optimizable_node(node, dest_mode)) { -- 2.20.1