X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fana%2Fvrp.c;h=b82d6e6fb89e980682ed2e4122900d49ff160bad;hb=aa2711d21433864eb3e8281bd24b41810a8b1230;hp=8ca7590c3ff33f0b041ae973860850a1f090f98e;hpb=e0e9e9ace61d3ec46e4d09c7ab2c6947b17b2778;p=libfirm diff --git a/ir/ana/vrp.c b/ir/ana/vrp.c index 8ca7590c3..b82d6e6fb 100644 --- a/ir/ana/vrp.c +++ b/ir/ana/vrp.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1995-2009 University of Karlsruhe. All right reserved. + * Copyright (C) 1995-2010 University of Karlsruhe. All right reserved. * * This file is part of libFirm. * @@ -19,645 +19,618 @@ /** * @file - * @brief analyze graph to provide value range information - * @author Jonas Fietz - * @version $Id$ + * @brief analyze graph to provide value range information + * @author Jonas Fietz + * @version $Id$ */ +#include "config.h" #include "irtypes.h" #include "vrp.h" +#include "iroptimize.h" #include "irouts.h" #include "irgraph_t.h" +#include "irgopt.h" #include "irpass.h" -#include "list.h" #include "irgwalk.h" #include "iredges.h" #include "tv.h" +#include "irop.h" +#include "pdeq.h" +#include "irphase_t.h" +#include "bitset.h" +#include "debug.h" + +DEBUG_ONLY(static firm_dbg_module_t *dbg); + +typedef struct vrp_env_t { + waitq *workqueue; + bitset_t *visited; +} vrp_env_t; + +static vrp_attr *get_vrp_attr(const ir_node *node) +{ + return (vrp_attr*) get_or_set_irn_phase_info(node, PHASE_VRP); +} - -static char v; -static void *VISITED = &v; - -typedef struct worklist_t worklist_t; -struct worklist_t { - struct list_head nodes; - ir_node *node; -}; - -struct vrp_env_t { - worklist_t *worklist; -}; - -int update_vrp_data( ir_node *node) { - - tarval *new_bits_set = get_tarval_bad(); - tarval *new_bits_not_set = get_tarval_bad(); - tarval *new_range_bottom = get_tarval_bad(); - tarval *new_range_top = get_tarval_bad(); - ir_node *new_bits_node = NULL; - ir_node *new_range_node = NULL; +static int vrp_update_node(ir_node *node) +{ + ir_tarval *new_bits_set = get_tarval_bad(); + ir_tarval *new_bits_not_set = get_tarval_bad(); + ir_tarval *new_range_bottom = get_tarval_bad(); + ir_tarval *new_range_top = get_tarval_bad(); enum range_types new_range_type = VRP_UNDEFINED; - enum range_ops new_range_op = VRP_NONE; int something_changed = 0; - - node->vrp.valid = 1; - // TODO: Check if all predecessors have valid VRP information - + vrp_attr *vrp; if (!mode_is_int(get_irn_mode(node))) { - return 0; // we don't optimize for non-int-nodes + return 0; /* we don't optimize for non-int-nodes*/ } - if (is_Const(node)) { - tarval *tv = get_Const_tarval(node); + vrp = get_vrp_attr(node); + + /* TODO: Check if all predecessors have valid VRP information*/ + switch (get_irn_opcode(node)) { + case iro_Const: { + ir_tarval *tv = get_Const_tarval(node); new_bits_set = tv; - new_bits_not_set = tarval_not(tv); + new_bits_not_set = tv; new_range_bottom = tv; new_range_top = tv; new_range_type = VRP_RANGE; - } else if (is_And(node)) { - ir_node *pred0 = get_And_left(node); - ir_node *pred1 = get_And_right(node); - tarval *tmp; - - new_bits_set = tarval_and(pred0->vrp.bits_set, pred1->vrp.bits_set); - new_bits_not_set = tarval_or(pred0->vrp.bits_not_set, pred1->vrp.bits_not_set); - - tmp = tarval_not(pred0->vrp.bits_set); - tmp = tarval_eor(pred0->vrp.bits_not_set, tmp); - //check if one of the predecessors is completely determined - if (tarval_is_null(tmp)) { - new_bits_node = pred1; - } + break; + } + case iro_And: { + const vrp_attr *vrp_left, *vrp_right; + const ir_node *left, *right; + + left = get_And_left(node); + right = get_And_right(node); + vrp_left = get_vrp_attr(left); + vrp_right = get_vrp_attr(right); + new_bits_set = tarval_and(vrp_left->bits_set, vrp_right->bits_set); + new_bits_not_set = tarval_and(vrp_left->bits_not_set, vrp_right->bits_not_set); + + break; + } - tmp = tarval_not(pred1->vrp.bits_set); - tmp = tarval_eor(pred1->vrp.bits_not_set, tmp); - if (tarval_is_null(tmp)) { - new_bits_node = pred0; - } - } else if (is_Add(node)) { - ir_node *pred0 = get_Add_left(node); - ir_node *pred1 = get_Add_right(node); + case iro_Add: { int overflow_top, overflow_bottom; - tarval *new_top, *new_bottom; - - if (pred0->vrp.range_type == VRP_UNDEFINED || pred1->vrp.range_type == - VRP_UNDEFINED || pred0->vrp.range_type == VRP_VARYING || - pred1->vrp.range_type == VRP_VARYING) { + ir_tarval *new_top, *new_bottom; + const vrp_attr *vrp_left, *vrp_right; + vrp_left = get_vrp_attr(get_Add_left(node)); + vrp_right = get_vrp_attr(get_Add_right(node)); + + if (vrp_left->range_type == VRP_UNDEFINED || vrp_right->range_type == + VRP_UNDEFINED || vrp_left->range_type == VRP_VARYING || + vrp_right->range_type == VRP_VARYING) { return 0; } - new_top = tarval_add(pred0->vrp.range_top, pred1->vrp.range_top); + new_top = tarval_add(vrp_left->range_top, vrp_right->range_top); overflow_top = tarval_carry(); - new_bottom = tarval_add(pred0->vrp.range_bottom, pred1->vrp.range_bottom); + new_bottom = tarval_add(vrp_left->range_bottom, vrp_right->range_bottom); overflow_bottom = tarval_carry(); - if (!overflow_top && !overflow_bottom && pred0->vrp.range_type == VRP_RANGE - &&pred1->vrp.range_type == VRP_RANGE) { + if (!overflow_top && !overflow_bottom && vrp_left->range_type == VRP_RANGE + &&vrp_right->range_type == VRP_RANGE) { new_range_bottom = new_bottom; new_range_top = new_top; new_range_type = VRP_RANGE; } if (overflow_top || overflow_bottom) { - // TODO Implement overflow handling + /* TODO Implement overflow handling*/ new_range_type = VRP_UNDEFINED; } - } else if (is_Sub(node)) { - ir_node *pred0 = get_Sub_left(node); - ir_node *pred1 = get_Sub_right(node); - int overflow_top, overflow_bottom; - tarval *new_top, *new_bottom; + break; + } - if (pred0->vrp.range_type == VRP_UNDEFINED || pred1->vrp.range_type == - VRP_UNDEFINED) { + case iro_Sub: { + int overflow_top, overflow_bottom; + ir_tarval *new_top, *new_bottom; + const vrp_attr *vrp_left, *vrp_right; + vrp_left = get_vrp_attr(get_Sub_left(node)); + vrp_right = get_vrp_attr(get_Sub_right(node)); + + if (vrp_left->range_type == VRP_UNDEFINED || vrp_right->range_type == + VRP_UNDEFINED || vrp_left->range_type == VRP_VARYING || + vrp_right->range_type == VRP_VARYING) { return 0; } - new_top = tarval_sub(pred0->vrp.range_top, pred1->vrp.range_top, NULL); + new_top = tarval_sub(vrp_left->range_top, vrp_right->range_top, NULL); overflow_top = tarval_carry(); - new_bottom = tarval_sub(pred0->vrp.range_bottom, pred1->vrp.range_bottom, NULL); + new_bottom = tarval_sub(vrp_left->range_bottom, vrp_right->range_bottom, NULL); overflow_bottom = tarval_carry(); - if (!overflow_top && !overflow_bottom && pred0->vrp.range_type == VRP_RANGE - &&pred1->vrp.range_type == VRP_RANGE) { + if (!overflow_top && !overflow_bottom && vrp_left->range_type == VRP_RANGE + &&vrp_right->range_type == VRP_RANGE) { new_range_bottom = new_bottom; new_range_top = new_top; new_range_type = VRP_RANGE; } if (overflow_top || overflow_bottom) { - // TODO Implement overflow handling - } - } else if (is_Or(node)) { - ir_node *a = get_Or_left(node); - ir_node *b = get_Or_right(node); - tarval *tmp; - - new_bits_set = tarval_or(a->vrp.bits_set, b->vrp.bits_set); - new_bits_not_set = tarval_and(a->vrp.bits_not_set, b->vrp.bits_not_set); - - tmp = tarval_not(a->vrp.bits_set); - tmp = tarval_eor(a->vrp.bits_not_set, tmp); - //check if one of the predecessors is completely determined - if (tarval_is_null(tmp)) { - new_bits_node = b; + /* TODO Implement overflow handling*/ } + break; + } - tmp = tarval_not(b->vrp.bits_set); - tmp = tarval_eor(b->vrp.bits_not_set, tmp); - if (tarval_is_null(tmp)) { - new_bits_node = a; - } + case iro_Or: { + const vrp_attr *vrp_left, *vrp_right; - } else if (is_Rotl(node)) { - ir_node *a = get_Rotl_left(node); - ir_node *b = get_Rotl_right(node); + vrp_left = get_vrp_attr(get_Or_left(node)); + vrp_right = get_vrp_attr(get_Or_right(node)); - // We can only compute this if the right value is a constant - if (is_Const(b)) { - tarval *bits_set, *bits_not_set; - bits_set = tarval_rotl(a->vrp.bits_set, get_Const_tarval(b)); - bits_not_set = tarval_rotl(a->vrp.bits_not_set, get_Const_tarval(b)); + new_bits_set = tarval_or(vrp_left->bits_set, vrp_right->bits_set); + new_bits_not_set = tarval_or(vrp_left->bits_not_set, vrp_right->bits_not_set); - new_bits_set = tarval_or(bits_set, node->vrp.bits_set); - new_bits_not_set = tarval_or(bits_not_set, node->vrp.bits_not_set); - } + break; + } - } else if (is_Shl(node)) { - ir_node *a = get_Shl_left(node); - ir_node *b = get_Shl_right(node); + case iro_Rotl: { + const vrp_attr *vrp_left, *vrp_right; + const ir_node *right = get_Rotl_right(node); - // We can only compute this if the right value is a constant - if (is_Const(b)) { - tarval *bits_set, *bits_not_set; - ir_mode *m = get_tarval_mode(node->vrp.bits_not_set); - bits_set = tarval_shl(a->vrp.bits_set, get_Const_tarval(b)); - bits_not_set = tarval_shl(a->vrp.bits_not_set, get_Const_tarval(b)); + vrp_left = get_vrp_attr(get_Rotl_left(node)); + vrp_right = get_vrp_attr(get_Rotl_right(node)); - new_bits_set = tarval_or(bits_set, node->vrp.bits_set); - new_bits_not_set = tarval_or(bits_not_set, node->vrp.bits_not_set); + /* We can only compute this if the right value is a constant*/ + if (is_Const(right)) { + ir_tarval *bits_set, *bits_not_set; + bits_set = tarval_rotl(vrp_left->bits_set, get_Const_tarval(right)); + bits_not_set = tarval_rotl(vrp_left->bits_not_set, get_Const_tarval(right)); + } + break; + } - bits_not_set = tarval_not( tarval_shl( - get_tarval_all_one(m), - get_Const_tarval(b))); - new_bits_not_set = tarval_or(bits_not_set, new_bits_not_set); + case iro_Shl: { + const vrp_attr *vrp_left, *vrp_right; + const ir_node *right = get_Shl_right(node); + vrp_left = get_vrp_attr(get_Shl_left(node)); + vrp_right = get_vrp_attr(get_Shl_right(node)); + /* We can only compute this if the right value is a constant*/ + if (is_Const(right)) { + new_bits_set = tarval_shl(vrp_left->bits_set, get_Const_tarval(right)); + new_bits_not_set = tarval_shl(vrp_left->bits_not_set, get_Const_tarval(right)); } + break; + } - } else if (is_Shr(node)) { - ir_node *a = get_Shr_left(node); - ir_node *b = get_Shr_right(node); + case iro_Shr: { + const vrp_attr *vrp_left, *vrp_right; + const ir_node *right = get_Shr_right(node); + + vrp_left = get_vrp_attr(get_Shr_left(node)); + vrp_right = get_vrp_attr(get_Shr_right(node)); + + /* We can only compute this if the right value is a constant*/ + if (is_Const(right)) { + new_bits_set = tarval_shr(vrp_left->bits_set, get_Const_tarval(right)); + new_bits_not_set = tarval_shr(vrp_left->bits_not_set, get_Const_tarval(right)); + } + break; + } - // We can only compute this if the right value is a constant - if (is_Const(b)) { - tarval *bits_set, *bits_not_set; - ir_mode *m = get_tarval_mode(node->vrp.bits_not_set); - bits_set = tarval_shr(a->vrp.bits_set, get_Const_tarval(b)); - bits_not_set = tarval_shr(a->vrp.bits_not_set, get_Const_tarval(b)); + case iro_Shrs: { + const vrp_attr *vrp_left, *vrp_right; + const ir_node *right = get_Shrs_right(node); - new_bits_set = tarval_or(bits_set, node->vrp.bits_set); - new_bits_not_set = tarval_or(bits_not_set, node->vrp.bits_not_set); + vrp_left = get_vrp_attr(get_Shrs_left(node)); + vrp_right = get_vrp_attr(get_Shrs_right(node)); - bits_not_set = tarval_not( tarval_shr( - get_tarval_all_one(m), - get_Const_tarval(b))); - new_bits_not_set = tarval_or(bits_not_set, new_bits_not_set); + /* We can only compute this if the right value is a constant*/ + if (is_Const(right)) { + new_bits_set = tarval_shrs(vrp_left->bits_set, get_Const_tarval(right)); + new_bits_not_set = tarval_shrs(vrp_left->bits_not_set, get_Const_tarval(right)); } + break; + } - } else if (is_Shrs(node)) { - ir_node *a = get_Shrs_left(node); - ir_node *b = get_Shrs_right(node); + case iro_Eor: { + const vrp_attr *vrp_left, *vrp_right; - // We can only compute this if the right value is a constant - if (is_Const(b)) { - tarval *bits_set, *bits_not_set; - ir_mode *m = get_tarval_mode(node->vrp.bits_not_set); - bits_set = tarval_shrs(a->vrp.bits_set, get_Const_tarval(b)); - bits_not_set = tarval_shrs(a->vrp.bits_not_set, get_Const_tarval(b)); + vrp_left = get_vrp_attr(get_Eor_left(node)); + vrp_right = get_vrp_attr(get_Eor_right(node)); - new_bits_set = tarval_or(bits_set, node->vrp.bits_set); - new_bits_not_set = tarval_or(bits_not_set, node->vrp.bits_not_set); + new_bits_set = tarval_or( + tarval_and(vrp_left->bits_set, tarval_not(vrp_right->bits_not_set)), + tarval_and(tarval_not(vrp_left->bits_not_set), vrp_right->bits_set)); - bits_not_set = tarval_not( tarval_shrs( - get_tarval_all_one(m), - get_Const_tarval(b))); - new_bits_not_set = tarval_or(bits_not_set, new_bits_not_set); - } + new_bits_not_set = tarval_not(tarval_or( + tarval_and(vrp_left->bits_set,vrp_right->bits_set), + tarval_and(tarval_not(vrp_left->bits_not_set), + tarval_not(vrp_right->bits_not_set)))); + + break; + } + + case iro_Id: { + const vrp_attr *vrp_pred = get_vrp_attr(get_Id_pred(node)); + new_bits_set = vrp_pred->bits_set; + new_bits_not_set = vrp_pred->bits_not_set; + new_range_top = vrp_pred->range_top; + new_range_bottom = vrp_pred->range_bottom; + new_range_type = vrp_pred->range_type; + break; + } - } else if (is_Eor(node)) { - ir_node *a = get_Eor_left(node); - ir_node *b = get_Eor_right(node); - - tarval *bits_set, *bits_not_set; - bits_not_set = tarval_or( - tarval_and(a->vrp.bits_set, b->vrp.bits_set), - tarval_and(a->vrp.bits_not_set, - b->vrp.bits_not_set)); - - bits_set = tarval_or( - tarval_and(a->vrp.bits_set, b->vrp.bits_not_set), - tarval_and(a->vrp.bits_not_set, b->vrp.bits_set)); - - new_bits_set = tarval_or(bits_set, node->vrp.bits_set); - new_bits_not_set = tarval_or(bits_not_set, node->vrp.bits_not_set); - - } else if (is_Id(node)) { - ir_node *pred = get_Id_pred(node); - new_bits_set = pred->vrp.bits_set; - new_bits_not_set = pred->vrp.bits_not_set; - new_range_top = pred->vrp.range_top; - new_range_bottom = pred->vrp.range_bottom; - new_range_type = pred->vrp.range_type; - - } else if (is_Not(node)) { - ir_node *pred = get_Not_op(node); - new_bits_set = tarval_or(pred->vrp.bits_not_set, node->vrp.bits_set); - new_bits_not_set = tarval_or(pred->vrp.bits_set, node->vrp.bits_not_set); - - } else if (is_Conv(node)) { - ir_node *pred = get_Conv_op(node); + case iro_Not: { + const vrp_attr *vrp_pred = get_vrp_attr(get_Not_op(node)); + new_bits_set = tarval_not(vrp_pred->bits_not_set); + new_bits_not_set = tarval_not(vrp_pred->bits_set); + break; + } + + case iro_Conv: { + const ir_node *pred = get_Conv_op(node); ir_mode *old_mode = get_irn_mode(pred); + const vrp_attr *vrp_pred = get_vrp_attr(pred); + ir_mode *new_mode; - tarval *bits_not_set; if (!mode_is_int(old_mode)) return 0; new_mode = get_irn_mode(node); - // The second and is needed if target type is smaller - bits_not_set = tarval_not( - tarval_convert_to(get_tarval_all_one(old_mode), - new_mode - )); - bits_not_set = tarval_or(bits_not_set, tarval_convert_to(pred->vrp.bits_not_set, new_mode)); - new_bits_not_set = tarval_or(bits_not_set, node->vrp.bits_not_set); + /* The second and is needed if target type is smaller*/ + new_bits_not_set = tarval_convert_to(get_mode_all_one(old_mode), new_mode); + new_bits_not_set = tarval_and(new_bits_not_set, tarval_convert_to(vrp_pred->bits_not_set, new_mode)); new_bits_set = tarval_and( - tarval_not(bits_not_set), tarval_convert_to(pred->vrp.bits_set, new_mode)); + new_bits_not_set, tarval_convert_to(vrp_pred->bits_set, new_mode)); - if (tarval_cmp(pred->vrp.range_top, get_tarval_max(new_mode)) == pn_Cmp_Le) { - node->vrp.range_top = pred->vrp.range_top; + /* Matze: TODO, BUGGY, tarval_cmp never returns ir_relation_less_equal */ + if (tarval_cmp(vrp_pred->range_top, get_mode_max(new_mode)) == ir_relation_less_equal) { + vrp->range_top = vrp_pred->range_top; } - if (tarval_cmp(pred->vrp.range_bottom, get_tarval_min(new_mode)) == pn_Cmp_Ge) { - node->vrp.range_bottom = pred->vrp.range_bottom; + /* Matze: TODO, BUGGY, tarval_cmp never returns ir_relation_greater_equal */ + if (tarval_cmp(vrp_pred->range_bottom, get_mode_min(new_mode)) == ir_relation_greater_equal) { + vrp->range_bottom = vrp_pred->range_bottom; } + break; + } - } else if (is_Confirm(node)) { - pn_Cmp cmp = get_Confirm_cmp(node); - ir_node *bound = get_Confirm_bound(node); + case iro_Confirm: { + const ir_relation relation = get_Confirm_relation(node); + const ir_node *bound = get_Confirm_bound(node); - /** @todo: Handle non-Const bounds */ - if (cmp == pn_Cmp_Lg) { - /** @todo: Is there some way to preserve the information? */ - new_range_type = VRP_ANTIRANGE; + if (relation == ir_relation_less_greater) { + /** @todo: Handle non-Const bounds */ if (is_Const(bound)) { + new_range_type = VRP_ANTIRANGE; new_range_top = get_Const_tarval(bound); new_range_bottom = get_Const_tarval(bound); } - } else if (cmp == pn_Cmp_Le) { - if (node->vrp.range_type == VRP_UNDEFINED) { + } else if (relation == ir_relation_less_equal) { + if (is_Const(bound)) { new_range_type = VRP_RANGE; - if (is_Const(bound)) { - new_range_top = get_Const_tarval(bound); - } + new_range_top = get_Const_tarval(bound); new_range_bottom = get_tarval_min(get_irn_mode(node)); - } else if (node->vrp.range_type == VRP_RANGE) { - if (is_Const(bound)) { - if (tarval_cmp(node->vrp.range_top, - get_Const_tarval(bound)) == pn_Cmp_Le) { - new_range_top = get_Const_tarval(bound); - } - new_range_bottom = get_tarval_min(get_irn_mode(node)); - - } else if (node->vrp.range_type == VRP_ANTIRANGE) { - /** @todo: How do we manage not to get a never ending loop? */ - } } } + break; + } + + case iro_Phi: { + /* combine all ranges*/ - } else if (is_Phi(node)) { - // combine all ranges - ir_node *pred; int num = get_Phi_n_preds(node); - pn_Cmp cmp; + ir_relation relation; int i; - tarval *range_top, *range_bottom, *bits_set, *bits_not_set; - enum range_types range_type; - assert(num > 0); + const ir_node *pred = get_Phi_pred(node,0); + const vrp_attr *vrp_pred = get_vrp_attr(pred); + new_range_top = vrp_pred->range_top; + new_range_bottom = vrp_pred->range_bottom; + new_range_type = vrp_pred->range_type; + new_bits_set = vrp_pred->bits_set; + new_bits_not_set = vrp_pred->bits_not_set; - pred = get_Phi_pred(node,0); - range_top = pred->vrp.range_top; - range_bottom = pred->vrp.range_bottom; - range_type = pred->vrp.range_type; - bits_set = pred->vrp.bits_set; - bits_not_set = pred->vrp.bits_not_set; + assert(num > 0); - for(i = 1; i < num; i++) { + for (i = 1; i < num; i++) { pred = get_Phi_pred(node, i); - if (range_type == VRP_RANGE && pred->vrp.range_type == + vrp_pred = get_vrp_attr(pred); + if (new_range_type == VRP_RANGE && vrp_pred->range_type == VRP_RANGE) { - cmp = tarval_cmp(range_top, pred->vrp.range_top); - if (cmp == pn_Cmp_Lt) { - range_top = pred->vrp.range_top; + relation = tarval_cmp(new_range_top, vrp_pred->range_top); + if (relation == ir_relation_less) { + new_range_top = vrp_pred->range_top; } - cmp = tarval_cmp(range_bottom, pred->vrp.range_bottom); - if (cmp == pn_Cmp_Gt) { - range_bottom = pred->vrp.range_bottom; + relation = tarval_cmp(new_range_bottom, vrp_pred->range_bottom); + if (relation == ir_relation_greater) { + new_range_bottom = vrp_pred->range_bottom; } } else { - range_type = VRP_VARYING; - break; + new_range_type = VRP_VARYING; } + new_bits_set = tarval_and(new_bits_set, vrp_pred->bits_set); + new_bits_not_set = tarval_or(new_bits_not_set, + vrp_pred->bits_not_set); } - new_range_type = range_type; - new_range_top = range_top; - new_range_bottom = range_bottom; - - } else { - // unhandled, therefore never updated - return 0; + break; + } + default: + /* unhandled, therefore never updated */ + break; } /* TODO: Check, if there can be information derived from any of these: is_Abs(node) is_Alloc(node) is_Anchor(node) is_Borrow(node) is_Bound(node) - is_Break(node) is_Builtin(node) is_Call(node) is_CallBegin(node) + is_Break(node) is_Builtin(node) is_Call(node) is_Carry(node) is_Cast(node) is_Cmp(node) is_Cond(node) - is_CopyB(node) is_Div(node) is_DivMod(node) is_Dummy(node) - is_End(node) is_EndExcept(node) is_EndReg(node) is_Filter(node) is_Free(node) + is_CopyB(node) is_Div(node) is_Dummy(node) + is_End(node) is_Free(node) is_IJmp(node) is_InstOf(node) is_Jmp(node) is_Load(node) is_Minus(node) is_Mod(node) is_Mul(node) is_Mulh(node) is_Mux(node) is_NoMem(node) - is_Pin(node) is_Proj(node) is_Quot(node) + is_Pin(node) is_Proj(node) is_Raise(node) is_Return(node) is_Sel(node) is_Start(node) is_Store(node) is_SymConst(node) is_Sync(node) is_Tuple(node) */ - // Merge the newly calculated values with those that might already exist + /* @todo: At this place, we check if the mode of the variable changed. A + * better place for this might be in the convopt.c file + */ + + if (new_bits_set != tarval_bad && get_tarval_mode(new_bits_set) != get_tarval_mode(vrp->bits_set)) { + vrp->bits_set = tarval_convert_to(vrp->bits_set, get_irn_mode(node)); + } + if (new_bits_not_set != tarval_bad && get_tarval_mode(new_bits_not_set) != get_tarval_mode(vrp->bits_not_set)) { + vrp->bits_not_set = tarval_convert_to(vrp->bits_not_set, get_irn_mode(node)); + } + if (vrp->range_type != VRP_UNDEFINED && new_range_type != VRP_UNDEFINED && get_tarval_mode(new_range_top) != get_tarval_mode(vrp->range_top)) { + /* @todo: We might be able to preserve this range information if it + * fits in */ + vrp->range_type = VRP_VARYING; + } + + /* Merge the newly calculated values with those that might already exist*/ if (new_bits_set != tarval_bad) { - new_bits_set = tarval_or(new_bits_set, node->vrp.bits_set); - if (tarval_cmp(new_bits_set, node->vrp.bits_set) != pn_Cmp_Eq) { + new_bits_set = tarval_or(new_bits_set, vrp->bits_set); + if (tarval_cmp(new_bits_set, vrp->bits_set) != ir_relation_equal) { something_changed = 1; - node->vrp.bits_set = new_bits_set; + vrp->bits_set = new_bits_set; } } - if (new_bits_not_set != tarval_bad) { - new_bits_not_set = tarval_or(new_bits_not_set, node->vrp.bits_not_set); + new_bits_not_set = tarval_and(new_bits_not_set, vrp->bits_not_set); - if (tarval_cmp(new_bits_not_set, node->vrp.bits_not_set) != pn_Cmp_Eq) { + if (tarval_cmp(new_bits_not_set, vrp->bits_not_set) != ir_relation_equal) { something_changed = 1; - node->vrp.bits_not_set = new_bits_not_set; + vrp->bits_not_set = new_bits_not_set; } } - if (node->vrp.bits_node == NULL && new_bits_node != NULL) { - something_changed = 1; - node->vrp.bits_node = new_bits_node; - } - - if (node->vrp.range_type == VRP_UNDEFINED && + if (vrp->range_type == VRP_UNDEFINED && new_range_type != VRP_UNDEFINED) { something_changed = 1; - node->vrp.range_type = new_range_type; - node->vrp.range_bottom = new_range_bottom; - node->vrp.range_top = new_range_top; - node->vrp.range_op = new_range_op; - node->vrp.range_node = new_range_node; + vrp->range_type = new_range_type; + vrp->range_bottom = new_range_bottom; + vrp->range_top = new_range_top; - } else if (node->vrp.range_type == VRP_RANGE) { + } else if (vrp->range_type == VRP_RANGE) { if (new_range_type == VRP_RANGE) { - if ((new_range_node == NULL && node->vrp.range_node == NULL) || - (new_range_node == node->vrp.range_node && - new_range_op == node->vrp.range_op)) { - if (tarval_cmp(node->vrp.range_bottom, new_range_bottom) == pn_Cmp_Lt) { - something_changed = 1; - node->vrp.range_bottom = new_range_bottom; - } - if (tarval_cmp(node->vrp.range_top, new_range_top) == pn_Cmp_Gt) { - something_changed = 1; - node->vrp.range_top = new_range_top; - } + if (tarval_cmp(vrp->range_bottom, new_range_bottom) == ir_relation_less) { + something_changed = 1; + vrp->range_bottom = new_range_bottom; } - - // prefer the absolute value - if (new_range_node == NULL && node->vrp.range_node != NULL) { + if (tarval_cmp(vrp->range_top, new_range_top) == ir_relation_greater) { something_changed = 1; - node->vrp.range_node = NULL; - node->vrp.range_top = new_range_top; - node->vrp.range_bottom = new_range_bottom; + vrp->range_top = new_range_top; } } if (new_range_type == VRP_ANTIRANGE) { - // if they are overlapping, cut the range. - // TODO: Maybe we can preserve more information here - if (new_range_node == NULL && node->vrp.range_node == NULL) { - if (tarval_cmp(node->vrp.range_bottom, new_range_top) == pn_Cmp_Gt && - tarval_cmp(node->vrp.range_bottom, new_range_bottom) == pn_Cmp_Gt) { - something_changed = 1; - node->vrp.range_bottom = new_range_top; - - } else if (tarval_cmp(node->vrp.range_top, new_range_bottom) == pn_Cmp_Gt && - tarval_cmp(node->vrp.range_top, new_range_top) == pn_Cmp_Lt) { - something_changed = 1; - node->vrp.range_top = new_range_bottom; - } - - // We can not handle the case where the anti range is in the - // range - } + /* if they are overlapping, cut the range.*/ + /* TODO: Maybe we can preserve more information here*/ + if (tarval_cmp(vrp->range_bottom, new_range_top) == ir_relation_greater && + tarval_cmp(vrp->range_bottom, new_range_bottom) == ir_relation_greater) { + something_changed = 1; + vrp->range_bottom = new_range_top; - // prefer the absolute value - if (new_range_node == NULL && node->vrp.range_node != NULL) { + } else if (tarval_cmp(vrp->range_top, new_range_bottom) == ir_relation_greater && + tarval_cmp(vrp->range_top, new_range_top) == ir_relation_less) { something_changed = 1; - node->vrp.range_node = NULL; - node->vrp.range_top = new_range_top; - node->vrp.range_bottom = new_range_bottom; + vrp->range_top = new_range_bottom; } + + /* We can not handle the case where the anti range is in the*/ + /* range*/ + } - } else if (node->vrp.range_type == VRP_ANTIRANGE) { + } else if (vrp->range_type == VRP_ANTIRANGE) { if (new_range_type == VRP_ANTIRANGE) { - if ((new_range_node == NULL && node->vrp.range_node == NULL) || - (new_range_node == node->vrp.range_node && - new_range_op == node->vrp.range_op)) { - if (tarval_cmp(node->vrp.range_bottom, new_range_bottom) == pn_Cmp_Gt) { - something_changed = 1; - node->vrp.range_bottom = new_range_bottom; - } - if (tarval_cmp(node->vrp.range_top, new_range_top) == pn_Cmp_Lt) { - something_changed = 1; - node->vrp.range_top = new_range_top; - } + if (tarval_cmp(vrp->range_bottom, new_range_bottom) == ir_relation_greater) { + something_changed = 1; + vrp->range_bottom = new_range_bottom; } - - // prefer the absolute value - if (new_range_node == NULL && node->vrp.range_node != NULL) { + if (tarval_cmp(vrp->range_top, new_range_top) == ir_relation_less) { something_changed = 1; - node->vrp.range_node = NULL; - node->vrp.range_top = new_range_top; - node->vrp.range_bottom = new_range_bottom; + vrp->range_top = new_range_top; } } if (new_range_type == VRP_RANGE) { - if ((new_range_node == NULL && node->vrp.range_node == NULL) || - (new_range_node == node->vrp.range_node && - new_range_op == node->vrp.range_op)) { - if (tarval_cmp(node->vrp.range_bottom, new_range_top) == pn_Cmp_Gt) { - something_changed = 1; - node->vrp.range_bottom = new_range_top; - } - if (tarval_cmp(node->vrp.range_top, new_range_bottom) == pn_Cmp_Lt) { - something_changed = 1; - node->vrp.range_top = new_range_bottom; - } + if (tarval_cmp(vrp->range_bottom, new_range_top) == ir_relation_greater) { + something_changed = 1; + vrp->range_bottom = new_range_top; } - - // prefer the absolute value - if (new_range_node == NULL && node->vrp.range_node != NULL) { + if (tarval_cmp(vrp->range_top, new_range_bottom) == ir_relation_less) { something_changed = 1; - node->vrp.range_node = NULL; - node->vrp.range_top = new_range_top; - node->vrp.range_bottom = new_range_bottom; + vrp->range_top = new_range_bottom; } } } assert(tarval_is_null( - tarval_and(node->vrp.bits_set, node->vrp.bits_not_set))); - + tarval_and(vrp->bits_set, tarval_not(vrp->bits_not_set)))); return something_changed; } -void vrp_first_pass(ir_node *n, void *e) { - ir_node *succ; - worklist_t *tmp_entry; +static void vrp_first_pass(ir_node *n, void *e) +{ int i; - struct vrp_env_t *env; + vrp_env_t *env = (vrp_env_t*) e; if (is_Block(n)) return; - env = (struct vrp_env_t *) e; - + bitset_set(env->visited, get_irn_idx(n)); - set_irn_link(n, VISITED); - - update_vrp_data(n); + vrp_update_node(n); + assure_irg_outs(get_current_ir_graph()); for (i = get_irn_n_outs(n) - 1; i >=0; --i) { - succ = get_irn_out(n, i); - if (get_irn_link(succ) == VISITED) { - // we found a loop - - tmp_entry = (struct worklist_t *)malloc(sizeof(struct worklist_t)); - tmp_entry->node = n; - list_add(&(tmp_entry->nodes), &(env->worklist->nodes)); - - + ir_node *succ = get_irn_out(n, i); + if (bitset_is_set(env->visited, get_irn_idx(succ))) { + /* we found a loop*/ + waitq_put(env->workqueue, succ); } } } +static void *vrp_init_node(ir_phase *phase, const ir_node *n) +{ + ir_mode *mode; + vrp_attr *vrp; -void set_vrp_data(ir_graph *irg) { + DBG((dbg, LEVEL_2, "initialized node nr: %d\n", get_irn_node_nr(n))); + vrp = (vrp_attr*) phase_alloc(phase, sizeof(vrp_attr)); - ir_node *succ; - int i; - worklist_t worklist; - worklist_t *tmp_entry, *tmp_entry2; - struct vrp_env_t *env; + memset(vrp, 0, sizeof(vrp_attr)); + /* Initialize the vrp information to default */ - env = malloc(sizeof(struct vrp_env_t)); - if (env == NULL) { - return; - } + mode = get_irn_mode(n); - if (!irg) { - /* no graph, skip */ - return; + vrp->range_type = VRP_UNDEFINED; + + /* TODO: We might be able to optimize space usage if we do not allocate + * vrp space for non-int nodes. (currently caught by vrp_update_node) + */ + if (mode_is_int(mode)) { + /* We are assuming that 0 is always represented as this modes null */ + vrp->valid = 1; + vrp->bits_set = get_mode_null(mode); + vrp->bits_not_set = get_mode_all_one(mode); + vrp->range_bottom = get_tarval_top(); + vrp->range_top = get_tarval_top(); + } else { + vrp->valid = 0; + vrp->bits_set = get_tarval_bad(); + vrp->bits_not_set = get_tarval_bad(); + vrp->range_bottom = get_tarval_bad(); + vrp->range_top = get_tarval_bad(); } - assure_irg_outs(irg); // ensure that out edges are consistent + /* TODO: We might be able to set better vrp info at this time, if this is + * a node which is newly created in an already initialized irg + * + * maybe just call vrp_update_node and if it returns one, iterate over + * successors + */ + return vrp; +} -// edges_activate(irg); +void set_vrp_data(ir_graph *irg) +{ + ir_node *succ, *node; + int i; + vrp_env_t *env; + ir_phase *phase; + + FIRM_DBG_REGISTER(dbg, "ir.ana.vrp"); + + assure_irg_outs(irg); /* ensure that out edges are consistent*/ + phase = irg_get_phase(irg, PHASE_VRP); + if (phase == NULL) { + /* this is our first run */ + phase = new_phase(irg, vrp_init_node); + irg_register_phase(irg, PHASE_VRP, phase); + env = (vrp_env_t*) phase_alloc(phase, sizeof(*env)); + phase->priv = env; + } else { + env = (vrp_env_t*) phase->priv; + } - INIT_LIST_HEAD(&worklist.nodes); + env->workqueue = new_waitq(); - env->worklist = &worklist; + env->visited = bitset_malloc(get_irg_last_idx(irg)); irg_walk_graph(irg, NULL, vrp_first_pass, env); + bitset_free(env->visited); + /* while there are entries in the worklist, continue*/ + while (!waitq_empty(env->workqueue)) { + node = (ir_node*) waitq_get(env->workqueue); + if (vrp_update_node(node)) { + /* if something changed, add successors to worklist*/ + for (i = get_irn_n_outs(node) - 1; i >= 0; --i) { + succ = get_irn_out(node, i); + waitq_put(env->workqueue, node); + } + } + } + del_waitq(env->workqueue); +} - // while there are entries in the worklist, continue - while( !list_empty(&worklist.nodes) ) { - - struct list_head *pos, *next; - list_for_each_safe(pos, next, &worklist.nodes) { +ir_graph_pass_t *set_vrp_pass(const char *name) +{ + return def_graph_pass(name ? name : "set_vrp", set_vrp_data); +} - tmp_entry = list_entry(pos, struct worklist_t, nodes); +ir_relation vrp_cmp(const ir_node *left, const ir_node *right) +{ + vrp_attr *vrp_left, *vrp_right; - if (update_vrp_data(tmp_entry->node)) { - // if something changed, add successors to worklist - for (i = get_irn_n_outs(tmp_entry->node) - 1; i >=0; --i) { - succ = get_irn_out(tmp_entry->node, i); + vrp_left = vrp_get_info(left); + vrp_right = vrp_get_info(right); - tmp_entry2 = (struct worklist_t *)malloc(sizeof(struct worklist_t)); - tmp_entry2->node = succ; - list_add(&(tmp_entry2->nodes), &worklist.nodes); - } - } + if (!vrp_left || !vrp_right) + return ir_relation_true; - list_del(pos); - free(tmp_entry); + if (vrp_left->range_type == VRP_RANGE && vrp_right->range_type == VRP_RANGE) { + if (tarval_cmp(vrp_left->range_top, vrp_right->range_bottom) == ir_relation_less) { + return ir_relation_less; + } + if (tarval_cmp(vrp_left->range_bottom, vrp_right->range_top) == ir_relation_greater) { + return ir_relation_greater; } } -} + if (!tarval_is_null(tarval_and(vrp_left->bits_set, tarval_not(vrp_right->bits_not_set))) || + !tarval_is_null(tarval_and(tarval_not(vrp_left->bits_not_set), vrp_right->bits_set))) { + return ir_relation_less_greater; + } -ir_graph_pass_t *set_vrp_pass(const char *name) { - return def_graph_pass(name ? name : "set_vrp", set_vrp_data); + /* TODO: We can get way more information here*/ + return ir_relation_true; } -pn_Cmp vrp_cmp(ir_node *left, ir_node *right) { - if (!left->vrp.valid || !right->vrp.valid) { - return pn_Cmp_False; - } - - if (!(left->vrp.range_type == VRP_UNDEFINED || - left->vrp.range_type == VRP_VARYING) && !( - right->vrp.range_type == VRP_UNDEFINED || - right->vrp.range_type == VRP_VARYING)) { - - tarval *lefttop = left->vrp.range_top; - tarval *leftbottom = left->vrp.range_bottom; - tarval *righttop = right->vrp.range_top; - tarval *rightbottom = right->vrp.range_bottom; - if (left->vrp.range_type == VRP_RANGE && right->vrp.range_type == - VRP_RANGE) { - if (tarval_cmp(lefttop, rightbottom) == pn_Cmp_Lt) { - return pn_Cmp_Lt; - } - if (tarval_cmp(leftbottom, righttop) == pn_Cmp_Gt) { - return pn_Cmp_Gt; - } +vrp_attr *vrp_get_info(const ir_node *node) +{ + const ir_graph *irg = get_irn_irg(node); + const ir_phase *phase = irg_get_phase(irg, PHASE_VRP); + vrp_attr *vrp; - } + if (phase == NULL) { + /* phase has not yet been initialized */ + return NULL; } - if (!tarval_is_null(tarval_and(left->vrp.bits_set, right->vrp.bits_not_set)) || - !tarval_is_null(tarval_and(left->vrp.bits_not_set, right->vrp.bits_set))) { - return pn_Cmp_Lg; + vrp = (vrp_attr*) phase_get_irn_data(phase, node); + if (vrp && vrp->valid) { + return vrp; } - // TODO: We can get way more information here - return pn_Cmp_False; + return NULL; }