X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fopt%2Fopt_confirms.c;h=ee23ee53a01a1de0c3824fa136bcd20b87e8a146;hb=f274dcf35aa0d3f4748387dbddfe50e8d7d44951;hp=65054e1b9e2000d73c89cdae7a652b8dc9649ebc;hpb=f9b481ef5234d6d1e63d164f5cd630ed7ecbbb28;p=libfirm diff --git a/ir/opt/opt_confirms.c b/ir/opt/opt_confirms.c index 65054e1b9..ee23ee53a 100644 --- a/ir/opt/opt_confirms.c +++ b/ir/opt/opt_confirms.c @@ -14,10 +14,14 @@ # include "config.h" #endif +#undef DEBUG_CONFIRM + #include "tv_t.h" #include "iropt_t.h" #include "iropt_dbg.h" #include "opt_confirms.h" +#include "irflag_t.h" +#include "irprintf.h" enum range_tags { MIN_INCLUDED = 0x00, /**< [min, ... */ @@ -40,7 +44,40 @@ 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 /* DEBUG_CONFIRM */ + +/* * Check, if the value of a node is != 0. * * This is a often needed case, so we handle here Confirm @@ -57,7 +94,7 @@ int value_not_zero(ir_node *n) while (get_irn_op(n) == op_Confirm) { /* * Note: A Confirm is never after a Const. So, - * we simply can check the bound for beeing a Const + * we simply can check the bound for being a Const * without the fear that is might be hidden by a further Confirm. */ tv = value_of(get_Confirm_bound(n)); @@ -107,6 +144,39 @@ int value_not_zero(ir_node *n) #undef RET_ON } +/* + * Check, if the value of a node cannot represent a NULL pointer. + * + * - Casts are skipped + * - If sel_based_null_check_elim is enabled, all + * Sel nodes can be skipped. + * - A SymConst(entity) is NEVER a NULL pointer + * - Confirms are evaluated + */ +int value_not_null(ir_node *n) +{ + ir_op *op; + + n = skip_Cast(n); + op = get_irn_op(n); + assert(mode_is_reference(get_irn_mode(n))); + if (get_opt_sel_based_null_check_elim()) { + /* skip all Sel nodes and Cast's */ + while (op == op_Sel) { + n = skip_Cast(get_Sel_ptr(n)); + op = get_irn_op(n); + } + } + if (op == op_SymConst && get_SymConst_kind(n) == symconst_addr_ent) + return 1; + if (op == op_Confirm) { + if (get_Confirm_cmp(n) == pn_Cmp_Lg && + classify_Const(get_Confirm_bound(n)) == CNST_NULL) + return 1; + } + return 0; +} + /* * Check, if the value of a node can be confirmed >= 0 or <= 0, * If the mode of the value did not honor signed zeros, else @@ -249,7 +319,7 @@ static interval_t *get_interval_from_tv(interval_t *iv, tarval *tv) * * @param iv an empty interval, will be filled * @param bound the bound value - * @param pnc the Confirm pnc relation + * @param pnc the Confirm compare relation * * @return the filled interval or NULL if no interval * can be created (happens only on floating point @@ -357,7 +427,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; @@ -393,6 +463,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 intervals 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: @@ -456,19 +549,30 @@ 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. * + * @param cmp the Cmp node * @param left the left operand of the Cmp * @param right the right operand of the Cmp + * @param pnc the compare relation */ 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; @@ -497,30 +601,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; } @@ -542,19 +683,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,16 +729,70 @@ tarval *computed_value_Cmp_Confirm(ir_node *cmp, ir_node *left, ir_node *right, return tv; } -/** For debugging. Prints an interval */ -static void print_iv(const interval_t *iv) { +#ifdef DEBUG_CONFIRM +/** + * For debugging. Prints an interval into a string. + * + * @param buf address of a string buffer + * @param len length of the string buffer + * @param iv the interval + */ +static int iv_snprintf(char *buf, size_t len, const interval_t *iv) { char smin[64], smax[64]; - tarval_snprintf(smin, sizeof(smin), iv->min); - tarval_snprintf(smax, sizeof(smax), iv->max); + 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, ""); +} + +/** + * For debugging. Prints an interval compare. + * + * @param l_iv the left interval + * @param r_iv the right interval + * @param pnc the compare relation + */ +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); - printf("%c%s, %s%c\n", - iv->flags & MIN_EXCLUDED ? '(' : '[', - smin, smax, - iv->flags & MAX_EXCLUDED ? ')' : ']' - ); + ir_printf("%s %= %s", sl, pnc, sr); } + +/** + * For debugging. call *compare_iv() and prints inputs and result. + * + * @param l_iv the left interval + * @param r_iv the right interval + * @param pnc the compare relation + */ +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 */