X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fopt%2Fopt_confirms.c;h=f005c273f14602088d899362cdc61dc9a2a35958;hb=f1a1a6092d9e4ebd9e22dd1c57d76ef8aeda74fc;hp=9c73b3e4e4d7ff4621cbfb91ff05a6941c639282;hpb=05e879d227e8ec8712a4ffc1c3d8bf82ca583f09;p=libfirm diff --git a/ir/opt/opt_confirms.c b/ir/opt/opt_confirms.c index 9c73b3e4e..f005c273f 100644 --- a/ir/opt/opt_confirms.c +++ b/ir/opt/opt_confirms.c @@ -14,10 +14,13 @@ # include "config.h" #endif +#undef DEBUG_CONFIRM + #include "tv_t.h" #include "iropt_t.h" #include "iropt_dbg.h" #include "opt_confirms.h" +#include "irprintf.h" enum range_tags { MIN_INCLUDED = 0x00, /**< [min, ... */ @@ -40,6 +43,39 @@ typedef struct _interval_t { unsigned char flags; /**< border flags */ } interval_t; +#ifdef DEBUG_CONFIRM + +#define compare_iv(l_iv, r_iv, pnc) compare_iv_dbg(l_iv, r_iv, pnc) + +/* forward */ +static tarval *compare_iv_dbg(const interval_t *l_iv, const interval_t *r_iv, pn_Cmp pnc); + +/* triangle */ +#define DBG_OUT_TR(l_pnc, l_bound, r_pnc, r_bound, pnc, v) \ + ir_printf("In %e:\na %= %n && b %= %n ==> a %= b == %s\n", \ + get_irg_entity(current_ir_graph), \ + l_pnc, l_bound, r_pnc, r_bound, pnc, v); + +/* right side */ +#define DBG_OUT_R(r_pnc, r_bound, left, pnc, right, v) \ + ir_printf("In %e:\na %= %n ==> %n %= %n == %s\n", \ + get_irg_entity(current_ir_graph), \ + r_pnc, r_bound, left, pnc, right, v); + +/* left side */ +#define DBG_OUT_L(l_pnc, l_bound, left, pnc, right, v) \ + ir_printf("In %e:\na %= %n ==> %n %= %n == %s\n", \ + get_irg_entity(current_ir_graph), \ + l_pnc, l_bound, left, pnc, right, v); + +#else + +#define DBG_OUT_TR(l_pnc, l_bound, r_pnc, r_bound, pnc, v) +#define DBG_OUT_R(r_pnc, r_bound, left, pnc, right, v) +#define DBG_OUT_L(l_pnc, l_bound, left, pnc, right, v) + +#endif + /** * Check, if the value of a node is != 0. * @@ -260,20 +296,15 @@ static interval_t *get_interval(interval_t *iv, ir_node *bound, pn_Cmp pnc) tarval *tv = value_of(bound); if (tv == tarval_bad) { - if (mode_is_float(mode)) { - /* NaN could be included which we cannot handle */ - iv->min = tarval_bad; - iv->max = tarval_bad; - iv->flags = MIN_EXCLUDED | MAX_EXCLUDED; - return NULL; - } - else { - /* [-oo, +oo] */ - iv->min = get_mode_min(mode); - iv->max = get_mode_max(mode); - iv->flags = MIN_INCLUDED | MAX_INCLUDED; - return iv; - } + /* There is nothing we could do here. For integer + * modes we could return [-oo, +oo], but there is + * nothing we could deduct from such an interval. + * So, speed things up and return unknown. + */ + iv->min = tarval_bad; + iv->max = tarval_bad; + iv->flags = MIN_EXCLUDED | MAX_EXCLUDED; + return NULL; } if (mode_is_float(mode)) { @@ -294,35 +325,35 @@ static interval_t *get_interval(interval_t *iv, ir_node *bound, pn_Cmp pnc) iv->min = iv->max = tv; iv->flags = MIN_INCLUDED | MAX_INCLUDED; - return iv; + break; case pn_Cmp_Le: /* [-oo, tv] */ iv->min = get_mode_min(mode); iv->max = tv; iv->flags = MIN_INCLUDED | MAX_INCLUDED; - return iv; + break; case pn_Cmp_Lt: /* [-oo, tv) */ iv->min = get_mode_min(mode); iv->max = tv; iv->flags = MIN_INCLUDED | MAX_EXCLUDED; - return iv; + break; case pn_Cmp_Gt: /* (tv, +oo] */ iv->min = tv; iv->max = get_mode_max(mode); iv->flags = MIN_EXCLUDED | MAX_INCLUDED; - return iv; + break; case pn_Cmp_Ge: /* [tv, +oo] */ iv->min = tv; iv->max = get_mode_max(mode); iv->flags = MIN_INCLUDED | MAX_INCLUDED; - return iv; + break; case pn_Cmp_Leg: /* @@ -333,7 +364,7 @@ static interval_t *get_interval(interval_t *iv, ir_node *bound, pn_Cmp pnc) iv->min = get_mode_min(mode); iv->max = get_mode_max(mode); iv->flags = MIN_INCLUDED | MAX_INCLUDED; - return iv; + break; default: /* @@ -345,6 +376,10 @@ static interval_t *get_interval(interval_t *iv, ir_node *bound, pn_Cmp pnc) iv->flags = MIN_EXCLUDED | MAX_EXCLUDED; return NULL; } + + if (iv->min != tarval_bad && iv->max != tarval_bad) + return iv; + return NULL; } /** @@ -358,7 +393,7 @@ static interval_t *get_interval(interval_t *iv, ir_node *bound, pn_Cmp pnc) * tarval_b_true or tarval_b_false it it can be evaluated, * tarval_bad else */ -static tarval *compare_iv(const interval_t *l_iv, const interval_t *r_iv, pn_Cmp pnc) +static tarval *(compare_iv)(const interval_t *l_iv, const interval_t *r_iv, pn_Cmp pnc) { pn_Cmp res; unsigned flags; @@ -372,7 +407,7 @@ static tarval *compare_iv(const interval_t *l_iv, const interval_t *r_iv, pn_Cmp if (pnc & pn_Cmp_Uo) { tarval *t; - pnc = get_negated_pnc(pnc); + pnc = get_negated_pnc(pnc, get_tarval_mode(l_iv->min)); t = tv_true; tv_true = tv_false; tv_false = t; @@ -394,6 +429,29 @@ static tarval *compare_iv(const interval_t *l_iv, const interval_t *r_iv, pn_Cmp /* two intervals can be compared for equality only if they are a single value */ if (l_iv->min == l_iv->max && r_iv->min == r_iv->max) return tarval_cmp(l_iv->min, r_iv->min) == pn_Cmp_Eq ? tv_true : tv_false; + + /* if both interval do not intersect, it is never equal */ + res = tarval_cmp(l_iv->max, r_iv->min); + + /* b < c ==> [a,b] != [c,d] */ + if (res == pn_Cmp_Lt) + return tv_false; + + /* b <= c ==> [a,b) != [c,d] AND [a,b] != (c,d] */ + if ((l_iv->flags & MAX_EXCLUDED || r_iv->flags & MIN_EXCLUDED) + && (res == pn_Cmp_Eq)) + return tv_false; + + res = tarval_cmp(r_iv->max, l_iv->min); + + /* d < a ==> [c,d] != [a,b] */ + if (res == pn_Cmp_Lt) + return tv_false; + + /* d <= a ==> [c,d) != [a,b] AND [c,d] != (a,b] */ + if ((r_iv->flags & MAX_EXCLUDED || l_iv->flags & MIN_EXCLUDED) + && (res == pn_Cmp_Eq)) + return tv_false; break; case pn_Cmp_Lg: @@ -457,6 +515,14 @@ static tarval *compare_iv(const interval_t *l_iv, const interval_t *r_iv, pn_Cmp return tarval_bad; } +/** + * Returns non-zero, if a given relation is transitive. + */ +static int is_transitive(pn_Cmp pnc) { + return (pn_Cmp_False < pnc && pnc < pn_Cmp_Lg); +} + + /** * Return the value of a Cmp if one or both predecessors * are Confirm nodes. @@ -467,9 +533,10 @@ static tarval *compare_iv(const interval_t *l_iv, const interval_t *r_iv, pn_Cmp tarval *computed_value_Cmp_Confirm(ir_node *cmp, ir_node *left, ir_node *right, pn_Cmp pnc) { ir_node *l_bound; - pn_Cmp l_pnc; + pn_Cmp l_pnc, res_pnc, neg_pnc; interval_t l_iv, r_iv; tarval *tv; + ir_mode *mode; if (get_irn_op(right) == op_Confirm) { ir_node *t; @@ -498,30 +565,67 @@ tarval *computed_value_Cmp_Confirm(ir_node *cmp, ir_node *left, ir_node *right, pn_Cmp r_pnc = get_Confirm_cmp(right); /* - * check for == or != can sometime be made WITHOUT constant bounds - * Beware of NaN's. + * some check can be made WITHOUT constant bounds */ - if (! mode_is_float(get_irn_mode(left)) && - (pnc == pn_Cmp_Eq || pnc == pn_Cmp_Lg)) { - /* l == r if bound(l) == bound(r) AND pnc(l) == pnc(r) == '=' */ - if (r_bound == l_bound && r_pnc == l_pnc && r_pnc == pn_Cmp_Eq) { - DBG_EVAL_CONFIRM(cmp); - return pnc == pn_Cmp_Eq ? tarval_b_true : tarval_b_false; + if (r_bound == l_bound) { + if (is_transitive(l_pnc)) { + pn_Cmp r_inc_pnc = get_inversed_pnc(r_pnc); + + /* + * triangle inequality: + * + * a CMP B && B CMP b => a CMP b, !(a ~CMP b) + * + * We handle correctly cases with some <=/>= here + */ + if ((l_pnc & ~pn_Cmp_Eq) == (r_inc_pnc & ~pn_Cmp_Eq)) { + res_pnc = (l_pnc & ~pn_Cmp_Eq) | (l_pnc & r_inc_pnc & pn_Cmp_Eq); + + if ((pnc == res_pnc) || ((pnc & ~pn_Cmp_Eq) == res_pnc)) { + DBG_OUT_TR(l_pnc, l_bound, r_pnc, r_bound, pnc, "true"); + DBG_EVAL_CONFIRM(cmp); + return tarval_b_true; + } + else { + pn_Cmp neg_pnc = get_negated_pnc(pnc, get_irn_mode(left)); + + if ((neg_pnc == res_pnc) || ((neg_pnc & ~pn_Cmp_Eq) == res_pnc)) { + DBG_OUT_TR(l_pnc, l_bound, r_pnc, r_bound, pnc, "false"); + DBG_EVAL_CONFIRM(cmp); + return tarval_b_false; + } + } + } } + } + + /* + * Here, we check only the right Confirm, as the left Confirms are + * checked later anyway. + */ + if (left == r_bound) { /* - * Here, we check only the right Confirm, as the left Confirms are - * checked later anyway. + * l == bound(r) AND pnc(r) == pnc: + * + * We know that a CMP b and check for that */ + if ((r_pnc == pnc) || (r_pnc == (pnc & ~pn_Cmp_Eq))) { + DBG_OUT_R(r_pnc, r_bound, left, pnc, right, "true"); + DBG_EVAL_CONFIRM(cmp); + return tarval_b_true; + } + /* + * l == bound(r) AND pnc(r) != pnc: + * + * We know that a CMP b and check for a ~CMP b + */ + else { + mode = get_irn_mode(left); + neg_pnc = get_negated_pnc(pnc, mode); - if (left == r_bound && (r_pnc == pn_Cmp_Eq || r_pnc == pn_Cmp_Lg)) { - /* l == bound(r) AND pnc(r) == pnc */ - if (r_pnc == pnc) { - DBG_EVAL_CONFIRM(cmp); - return tarval_b_true; - } - /* l == bound(r) AND pnc(r) != pnc */ - else { + if ((r_pnc == neg_pnc) || (r_pnc == (neg_pnc & ~pn_Cmp_Eq))) { + DBG_OUT_R(r_pnc, r_bound, left, pnc, right, "false"); DBG_EVAL_CONFIRM(cmp); return tarval_b_false; } @@ -543,19 +647,30 @@ tarval *computed_value_Cmp_Confirm(ir_node *cmp, ir_node *left, ir_node *right, /* from Here, check only left Confirm */ /* - * checks for == or != can sometime be made WITHOUT constant bounds - * Beware of NaN's. + * some checks can be made WITHOUT constant bounds */ - if (! mode_is_float(get_irn_mode(left)) && - (pnc == pn_Cmp_Eq || pnc == pn_Cmp_Lg)) { - if (right == l_bound && (l_pnc == pn_Cmp_Eq || l_pnc == pn_Cmp_Lg)) { - /* r == bound(l) AND pnc(l) == pnc */ - if (l_pnc == pnc) { - DBG_EVAL_CONFIRM(cmp); - return tarval_b_true; - } - /* r == bound(l) AND pnc(l) != pnc */ - else { + if (right == l_bound) { + /* + * r == bound(l) AND pnc(l) == pnc: + * + * We know that a CMP b and check for that + */ + if ((l_pnc == pnc) || (l_pnc == (pnc & ~pn_Cmp_Eq))) { + DBG_OUT_L(l_pnc, l_bound, left, pnc, right, "true"); + DBG_EVAL_CONFIRM(cmp); + return tarval_b_true; + } + /* + * r == bound(l) AND pnc(l) is Not(pnc): + * + * We know that a CMP b and check for a ~CMP b + */ + else { + mode = get_irn_mode(left); + neg_pnc = get_negated_pnc(pnc, mode); + + if ((l_pnc == neg_pnc) || (l_pnc == (neg_pnc & ~pn_Cmp_Eq))) { + DBG_OUT_L(l_pnc, l_bound, left, pnc, right, "false"); DBG_EVAL_CONFIRM(cmp); return tarval_b_false; } @@ -577,3 +692,59 @@ tarval *computed_value_Cmp_Confirm(ir_node *cmp, ir_node *left, ir_node *right, return tv; } + +/** + * For debugging. Prints an interval into a string. + */ +static int iv_snprintf(char *buf, size_t len, const interval_t *iv) { + char smin[64], smax[64]; + + if (iv) { + tarval_snprintf(smin, sizeof(smin), iv->min); + + if (iv->min != iv->max || (iv->flags & (MIN_EXCLUDED|MAX_EXCLUDED))) { + tarval_snprintf(smax, sizeof(smax), iv->max); + + return snprintf(buf, len, "%c%s, %s%c", + iv->flags & MIN_EXCLUDED ? '(' : '[', + smin, smax, + iv->flags & MAX_EXCLUDED ? ')' : ']' + ); + } + else + return snprintf(buf, len, "%s", smin); + } + return snprintf(buf, len, ""); +} + +#ifdef DEBUG_CONFIRM +/** + * For debugging. Prints an interval compare + */ +static void print_iv_cmp(const interval_t *l_iv, const interval_t *r_iv, pn_Cmp pnc) +{ + char sl[128], sr[128]; + + iv_snprintf(sl, sizeof(sl), l_iv); + iv_snprintf(sr, sizeof(sr), r_iv); + + ir_printf("%s %= %s", sl, pnc, sr); +} + +/** + * For debugging. call *compare_iv() and prints inputs and result + */ +static tarval *compare_iv_dbg(const interval_t *l_iv, const interval_t *r_iv, pn_Cmp pnc) +{ + tarval *tv = (compare_iv)(l_iv, r_iv, pnc); + + if (tv == tarval_bad) + return tv; + + ir_printf("In %e:\n", get_irg_entity(current_ir_graph)); + print_iv_cmp(l_iv, r_iv, pnc); + ir_printf(" = %T\n", tv); + return tv; +} + +#endif /* DEBUG_CONFIRM */