Commit 5766c304 authored by yb9976's avatar yb9976
Browse files

Merged fp-vrp into localopt.

Along the way:
- Simplified code to sharpen Cmp relations
- Do not remove unreachable code by using bit information anymore
parent 1d1df910
......@@ -541,13 +541,6 @@ FIRM_API void dead_node_elimination(ir_graph *irg);
*/
FIRM_API void place_code(ir_graph *irg);
/**
* Determines information about the values of nodes and perform simplifications
* using this information. This optimization performs a data-flow analysis to
* find the minimal fixpoint.
*/
FIRM_API void fixpoint_vrp(ir_graph*);
/**
* This optimization finds values where the bits are either constant or irrelevant
* and exchanges them for a corresponding constant.
......
......@@ -14,6 +14,7 @@
#include "irnode_t.h"
#include "irgraph_t.h"
#include "constbits.h"
#include "iroptimize.h"
#include "iropt_t.h"
#include "irgopt.h"
......@@ -164,9 +165,8 @@ static void opt_walker(ir_node *n, void *env)
int optimize_graph_df(ir_graph *irg)
{
pdeq *waitq = new_pdeq();
ir_graph *rem = current_ir_graph;
ir_node *end;
pdeq *waitq = new_pdeq();
ir_graph *rem = current_ir_graph;
current_ir_graph = irg;
......@@ -186,7 +186,12 @@ int optimize_graph_df(ir_graph *irg)
assure_irg_properties(irg, IR_GRAPH_PROPERTY_CONSISTENT_OUT_EDGES
| IR_GRAPH_PROPERTY_CONSISTENT_DOMINANCE);
ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_PHI_LIST);
struct obstack obst;
obstack_init(&obst);
constbits_analyze(irg, &obst);
irg_walk_graph(irg, NULL, opt_walker, waitq);
/* any optimized nodes are stored in the wait queue,
......@@ -204,7 +209,10 @@ int optimize_graph_df(ir_graph *irg)
irg_block_walk_graph(irg, NULL, find_unreachable_blocks, waitq);
}
del_pdeq(waitq);
ir_free_resources(irg, IR_RESOURCE_IRN_LINK);
ir_free_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_PHI_LIST);
constbits_clear(irg);
obstack_free(&obst, NULL);
/* disable unreachable code elimination */
if (get_opt_algebraic_simplification()) {
......@@ -219,7 +227,7 @@ int optimize_graph_df(ir_graph *irg)
/* Finally kill BAD and doublets from the keep alives.
* Doing this AFTER edges where deactivated saves cycles */
end = get_irg_end(irg);
ir_node *end = get_irg_end(irg);
remove_End_Bads_and_doublets(end);
current_ir_graph = rem;
......
......@@ -11,6 +11,7 @@
#include <string.h>
#include <stdbool.h>
#include "constbits.h"
#include "irnode_t.h"
#include "irgraph_t.h"
#include "iredges_t.h"
......@@ -57,14 +58,15 @@ int ir_imprecise_float_transforms_allowed(void)
static bool is_Or_Eor_Add(const ir_node *node)
{
if (is_Or(node) || is_Eor(node) || is_Add(node)) {
const ir_node *left = get_binop_left(node);
const ir_node *right = get_binop_right(node);
const vrp_attr *vrp_left = vrp_get_info(left);
const vrp_attr *vrp_right = vrp_get_info(right);
if (vrp_left != NULL && vrp_right != NULL) {
ir_tarval *vrp_val
= tarval_and(vrp_left->bits_not_set, vrp_right->bits_not_set);
return tarval_is_null(vrp_val);
const ir_node *const left = get_binop_left(node);
const ir_node *const right = get_binop_right(node);
const bitinfo *const bl = get_bitinfo(left);
const bitinfo *const br = get_bitinfo(right);
/* if each bit is guaranteed to be zero on either the left or right
* then an Add will have the same effect as the Eor/Or.
*/
if (bl && br && tarval_is_null(tarval_and(bl->z, br->z))) {
return true;
}
}
return false;
......@@ -633,9 +635,6 @@ ir_relation ir_get_possible_cmp_relations(const ir_node *left,
ir_relation possible = ir_relation_true;
const ir_tarval *tv_l = value_of(left);
const ir_tarval *tv_r = value_of(right);
const ir_mode *mode = get_irn_mode(left);
const ir_tarval *min = get_mode_min(mode);
const ir_tarval *max = get_mode_max(mode);
/* both values known - evaluate them */
if ((tv_l != tarval_unknown) && (tv_r != tarval_unknown)) {
......@@ -643,14 +642,18 @@ ir_relation ir_get_possible_cmp_relations(const ir_node *left,
/* we can return now, won't get any better */
return possible;
}
/* a == a is never less or greater (but might be equal or unordered) */
if (left == right)
possible &= ~ir_relation_less_greater;
/* unordered results only happen for float compares */
const ir_mode *mode = get_irn_mode(left);
if (!mode_is_float(mode))
possible &= ~ir_relation_unordered;
/* values can never be less than the least representable number or
* greater than the greatest representable number */
ir_tarval *min = get_mode_min(mode);
const ir_tarval *max = get_mode_max(mode);
if (tv_l == min)
possible &= ~ir_relation_greater;
if (tv_l == max)
......@@ -659,6 +662,36 @@ ir_relation ir_get_possible_cmp_relations(const ir_node *left,
possible &= ~ir_relation_greater;
if (tv_r == min)
possible &= ~ir_relation_less;
/* Try to use bit information. */
const bitinfo *const bl = get_bitinfo(left);
const bitinfo *const br = get_bitinfo(right);
if (bl != NULL && br != NULL) {
ir_tarval *const l_o = bl->o;
ir_tarval *const l_z = bl->z;
ir_tarval *const r_o = br->o;
ir_tarval *const r_z = br->z;
if (get_mode_arithmetic(mode) == irma_twos_complement) {
/* Compute min/max values of operands. */
ir_tarval *l_max = tarval_andnot(l_z, tarval_andnot(min, l_o));
ir_tarval *l_min = tarval_or(l_o, tarval_and(l_z, min));
ir_tarval *r_max = tarval_andnot(r_z, tarval_andnot(min, r_o));
ir_tarval *r_min = tarval_or(r_o, tarval_and(r_z, min));
if (!(tarval_cmp(l_max, r_min) & ir_relation_greater)) {
possible &= ~ir_relation_greater;
}
if (!(tarval_cmp(l_min, r_max) & ir_relation_less)) {
possible &= ~ir_relation_less;
}
}
if (!tarval_is_null(tarval_andnot(l_o, r_z))
|| !tarval_is_null(tarval_andnot(r_o, l_z))) {
possible &= ~ir_relation_equal;
}
}
/* maybe vrp can tell us more */
possible &= vrp_cmp(left, right);
/* Alloc nodes never return null (but throw an exception) */
......@@ -1032,7 +1065,29 @@ static ir_node *equivalent_node_involution(ir_node *n, int input)
static ir_node *equivalent_node_Minus(ir_node *n)
{
return equivalent_node_involution(n, n_Minus_op);
ir_node *oldn = n;
n = equivalent_node_involution(n, n_Minus_op);
if (n != oldn)
return n;
/* If all bits except the highest bit are zero the Minus is superfluous. */
ir_mode *const mode = get_irn_mode(n);
if (get_mode_arithmetic(mode) == irma_twos_complement) {
ir_node *const op = get_Minus_op(n);
const bitinfo *const b = get_bitinfo(op);
if (b) {
ir_tarval *const min = get_mode_min(mode);
ir_tarval *const z = b->z;
if (z == min) {
n = op;
set_bitinfo(n, z, b->o);
}
}
}
return n;
}
static ir_node *equivalent_node_Not(ir_node *n)
......@@ -1084,6 +1139,22 @@ static ir_node *equivalent_node_Or(ir_node *n)
DBG_OPT_ALGSIM0(oldn, n, FS_OPT_OR);
return n;
}
const bitinfo *const ba = get_bitinfo(a);
const bitinfo *const bb = get_bitinfo(b);
if (ba != NULL && bb != NULL) {
if (tarval_is_null(tarval_andnot(ba->z, bb->o))) {
n = b;
DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_OR);
return n;
}
if (tarval_is_null(tarval_andnot(bb->z, ba->o))) {
n = a;
DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_OR);
return n;
}
}
/* constants are normalized to right, check this side first */
const ir_tarval *tb = value_of(b);
if (tarval_is_null(tb)) {
......@@ -1107,8 +1178,22 @@ static ir_node *equivalent_node_Or(ir_node *n)
static ir_node *equivalent_node_And(ir_node *n)
{
ir_node *oldn = n;
ir_node *a = get_And_left(n);
ir_node *b = get_And_right(n);
ir_node* const a = get_And_left(n);
ir_node* const b = get_And_right(n);
bitinfo const* const ba = get_bitinfo(a);
bitinfo const* const bb = get_bitinfo(b);
if (ba != NULL && bb != NULL) {
if (tarval_is_null(tarval_andnot(bb->z, ba->o))) {
n = b;
DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_AND);
return n;
}
if (tarval_is_null(tarval_andnot(ba->z, bb->o))) {
n = a;
DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_AND);
return n;
}
}
if (a == b) {
n = a; /* idempotence */
......@@ -5099,14 +5184,17 @@ static ir_node *transform_node_Shrs(ir_node *n)
return n;
/* Normalization: use Shr when sign bit is guaranteed to be cleared */
vrp_attr *attr = vrp_get_info(a);
if (attr != NULL) {
unsigned bits = get_mode_size_bits(mode);
ir_tarval *sign = tarval_shl_unsigned(get_mode_one(mode), bits-1);
if (tarval_is_null(tarval_and(attr->bits_not_set, sign))) {
dbg_info *dbgi = get_irn_dbg_info(n);
ir_node *block = get_nodes_block(n);
return new_rd_Shr(dbgi, block, a, b, mode);
const bitinfo *const bn = get_bitinfo(n);
if (bn != NULL && get_mode_arithmetic(mode) == irma_twos_complement) {
ir_tarval *z = bn->z;
unsigned mode_bits = get_mode_size_bits(mode);
unsigned highest_bit = get_tarval_highest_bit(z);
if (highest_bit + 1U != mode_bits) {
dbg_info *const dbgi = get_irn_dbg_info(n);
ir_node *const block = get_nodes_block(n);
n = new_rd_Shr(dbgi, block, a, b, mode);
set_bitinfo(n, z, bn->o);
return n;
}
}
......@@ -6394,16 +6482,33 @@ restart:;
if (get_opt_constant_folding()) {
/* neither constants nor Tuple values can be evaluated */
if (iro != iro_Const && get_irn_mode(n) != mode_T) {
/* try to evaluate */
ir_tarval *tv = computed_value(n);
if (tv != tarval_unknown) {
/* evaluation was successful -- replace the node. */
ir_graph *irg = get_irn_irg(n);
bitinfo *const b = get_bitinfo(n);
if (b) {
ir_tarval *z = b->z;
ir_tarval *o = b->o;
/* Replace node with constant value by Const. */
if (z == o) {
ir_mode *const m = get_irn_mode(n);
if (mode_is_int(m) || m == mode_b) {
ir_graph *const irg = get_irn_irg(n);
n = new_r_Const(irg, z);
set_bitinfo(n, z, o);
return n;
}
}
} else {
/* try to evaluate */
ir_tarval *tv = computed_value(n);
if (tv != tarval_unknown) {
/* evaluation was successful -- replace the node. */
ir_graph *const irg = get_irn_irg(n);
n = new_r_Const(irg, tv);
n = new_r_Const(irg, tv);
DBG_OPT_CSTEVAL(old_n, n);
return n;
DBG_OPT_CSTEVAL(old_n, n);
return n;
}
}
}
}
......
/*
* This file is part of libFirm.
* Copyright (C) 2012 University of Karlsruhe.
*/
/**
* @file
* @brief Data-flow driven minimal fixpoint value range propagation
* @author Christoph Mallon
*/
#include "adt/obst.h"
#include "constbits.h"
#include "debug.h"
#include "ircons.h"
#include "irgmod.h"
#include "irgraph_t.h"
#include "irgwalk.h"
#include "iroptimize.h"
#include "tv.h"
DEBUG_ONLY(static firm_dbg_module_t *dbg;)
typedef struct environment_t {
unsigned modified:1; /**< Set, if the graph was modified. */
} environment_t;
static int mode_is_intb(ir_mode const* const m)
{
return mode_is_int(m) || m == mode_b;
}
static void apply_result(ir_node* const irn, void* ctx)
{
environment_t* env = (environment_t*)ctx;
if (is_Block(irn)) {
bitinfo *block_b = get_bitinfo(irn);
/* Trivially unreachable blocks have no info. */
if (block_b == NULL || block_b->z == get_tarval_b_false()) {
ir_graph *irg = get_irn_irg(irn);
ir_node *bad = new_r_Bad(irg, mode_BB);
exchange(irn, bad);
env->modified = 1;
}
return;
}
ir_node *block = get_nodes_block(irn);
bitinfo *block_b = get_bitinfo(block);
/* Trivially unreachable blocks have no info. */
if (block_b == NULL || block_b->z == get_tarval_b_false()) {
/* Unreachable blocks might be replaced before the nodes in them. */
ir_mode *mode = get_irn_mode(irn);
ir_graph *irg = get_irn_irg(irn);
ir_node *bad = new_r_Bad(irg, mode);
exchange(irn, bad);
env->modified = 1;
return;
}
bitinfo *b = get_bitinfo(irn);
if (!b) return;
if (is_Const(irn)) return; // It cannot get any better than a Const.
ir_tarval *z = b->z;
ir_tarval *o = b->o;
// Only display information if we could find out anything about the value.
DEBUG_ONLY(if (!tarval_is_all_one(z) || !tarval_is_null(o)))
DB((dbg, LEVEL_2, "%+F: 0:%T 1:%T%s\n", irn, z, o, z == o ? " --- constant" : ""));
// Replace node with constant value by Const.
if (z == o) {
ir_mode* const m = get_irn_mode(irn);
ir_node* n;
if (mode_is_intb(m)) {
ir_graph *irg = get_irn_irg(irn);
n = new_r_Const(irg, z);
} else if (m == mode_X) {
ir_graph* const irg = get_Block_irg(block);
if (z == get_tarval_b_true()) {
n = new_r_Jmp(block);
} else {
n = new_r_Bad(irg, mode_X);
/* Transferring analysis information to the bad node makes it a
* candidate for replacement. */
goto exchange_only;
}
} else {
return;
}
set_bitinfo(n, z, o);
exchange_only:
exchange(irn, n);
env->modified = 1;
}
switch (get_irn_opcode(irn)) {
case iro_And: {
ir_node* const l = get_And_left(irn);
ir_node* const r = get_And_right(irn);
bitinfo const* const bl = get_bitinfo(l);
bitinfo const* const br = get_bitinfo(r);
if (tarval_is_null(tarval_andnot(br->z, bl->o))) {
DB((dbg, LEVEL_2, "%+F(%+F, %+F) is superfluous\n", irn, l, r));
exchange(irn, r);
env->modified = 1;
} else if (tarval_is_null(tarval_andnot(bl->z, br->o))) {
DB((dbg, LEVEL_2, "%+F(%+F, %+F) is superfluous\n", irn, l, r));
exchange(irn, l);
env->modified = 1;
}
break;
}
case iro_Cmp: {
ir_node *const l = get_Cmp_left(irn);
ir_node *const r = get_Cmp_right(irn);
const bitinfo *const bl = get_bitinfo(l);
const bitinfo *const br = get_bitinfo(r);
if (bl == NULL || br == NULL)
break;
ir_mode *const mode = get_irn_mode(l);
ir_tarval *const l_o = bl->o;
ir_tarval *const l_z = bl->z;
ir_tarval *const r_o = br->o;
ir_tarval *const r_z = br->z;
ir_tarval * l_max;
ir_tarval * l_min;
ir_tarval * r_max;
ir_tarval * r_min;
if (mode_is_signed(mode)) {
if (!get_mode_arithmetic(mode) == irma_twos_complement)
break;
ir_tarval *min = get_mode_min(mode);
ir_tarval *not_min = tarval_not(min);
l_max = l_z;
l_min = l_o;
if (tarval_is_negative(l_z)) {
/* Value may be negative. */
l_min = tarval_or(l_o, min);
}
if (!tarval_is_negative(l_o)) {
/* Value may be positive. */
l_max = tarval_and(l_z, not_min);
}
r_max = r_z;
r_min = r_o;
if (tarval_is_negative(r_z)) {
/* Value may be negative. */
r_min = tarval_or(r_o, min);
}
if (!tarval_is_negative(r_o)) {
/* Value may be positive. */
r_max = tarval_and(r_z, not_min);
}
} else {
l_max = l_z;
l_min = l_o;
r_max = r_z;
r_min = r_o;
}
const ir_relation relation = get_Cmp_relation(irn);
ir_relation new_relation = relation;
if (!(tarval_cmp(l_max, r_min) & ir_relation_greater)) {
new_relation &= ~ir_relation_greater;
}
if (!(tarval_cmp(l_min, r_max) & ir_relation_less)) {
new_relation &= ~ir_relation_less;
}
if (!tarval_is_null(tarval_andnot(l_o, r_z))
|| !tarval_is_null(tarval_andnot(r_o, l_z))) {
new_relation &= ~ir_relation_equal;
}
if (relation != new_relation) {
dbg_info *dbgi = get_irn_dbg_info(irn);
ir_node *cmp = new_rd_Cmp(dbgi, block, l, r, new_relation);
mark_irn_visited(cmp);
DB((dbg, LEVEL_2, "Simplified relation of %+F(%+F, %+F)\n", irn, l, r));
if (is_Const(cmp)) {
z = o = get_Const_tarval(cmp);
}
set_bitinfo(cmp, z, o);
exchange(irn, cmp);
env->modified = 1;
}
break;
}
case iro_Eor: {
ir_node* const l = get_Eor_left(irn);
ir_node* const r = get_Eor_right(irn);
bitinfo const* const bl = get_bitinfo(l);
bitinfo const* const br = get_bitinfo(r);
/* if each bit is guaranteed to be zero on either the left or right
* then an Add will have the same effect as the Eor. Change it for
* normalization */
if (tarval_is_null(tarval_and(bl->z, br->z))) {
dbg_info *dbgi = get_irn_dbg_info(irn);
ir_node *block = get_nodes_block(irn);
ir_mode *mode = get_irn_mode(irn);
ir_node *new_node = new_rd_Add(dbgi, block, l, r, mode);
mark_irn_visited(new_node);
DB((dbg, LEVEL_2, "%+F(%+F, %+F) normalized to Add\n", irn, l, r));
set_bitinfo(new_node, z, o);
exchange(irn, new_node);
env->modified = 1;
}
break;
}
case iro_Minus: {
ir_mode *mode = get_irn_mode(irn);
/* If all bits except the highest bit are zero the Minus is superfluous. */
if (get_mode_arithmetic(mode) == irma_twos_complement) {
ir_node *const op = get_Minus_op(irn);
bitinfo const *const b = get_bitinfo(op);
ir_tarval *const min = get_mode_min(mode);
if (b->z == min) {
DB((dbg, LEVEL_2, "%+F(%+F) is superfluous\n", irn, op));
exchange(irn, op);
env->modified = 1;
}
}
break;
}
case iro_Or: {
ir_node* const l = get_Or_left(irn);
ir_node* const r = get_Or_right(irn);
bitinfo const* const bl = get_bitinfo(l);
bitinfo const* const br = get_bitinfo(r);
if (tarval_is_null(tarval_andnot(bl->z, br->o))) {
DB((dbg, LEVEL_2, "%+F(%+F, %+F) is superfluous\n", irn, l, r));
exchange(irn, r);
env->modified = 1;
} else if (tarval_is_null(tarval_andnot(br->z, bl->o))) {
DB((dbg, LEVEL_2, "%+F(%+F, %+F) is superfluous\n", irn, l, r));
exchange(irn, l);
env->modified = 1;
}
/* if each bit is guaranteed to be zero on either the left or right
* then an Add will have the same effect as the Or. Change it for
* normalization */
if (tarval_is_null(tarval_and(bl->z, br->z))) {
ir_mode *mode = get_irn_mode(irn);
if (get_mode_arithmetic(mode) == irma_twos_complement) {
dbg_info *dbgi = get_irn_dbg_info(irn);
ir_node *block = get_nodes_block(irn);
ir_node *new_node = new_rd_Add(dbgi, block, l, r, mode);
mark_irn_visited(new_node);
DB((dbg, LEVEL_2, "%+F(%+F, %+F) normalized to Add\n", irn, l, r));
set_bitinfo(new_node, z, o);
exchange(irn, new_node);
env->modified = 1;
}
}
break;
}
case iro_Shrs: {
ir_mode *mode = get_irn_mode(irn);
if (get_mode_arithmetic(mode) == irma_twos_complement) {
unsigned mode_bits = get_mode_size_bits(mode);
unsigned highest_bit = get_tarval_highest_bit(z);
if (highest_bit + 1U != mode_bits) {
dbg_info *const dbgi = get_irn_dbg_info(irn);
ir_node *const block = get_nodes_block(irn);
ir_node *const l = get_Shrs_left(irn);
ir_node *const r = get_Shrs_right(irn);
ir_node *const new_node = new_rd_Shr(dbgi, block, l, r, mode);
mark_irn_visited(new_node);
DB((dbg, LEVEL_2, "%+F(%+F, %+F) normalized to Shr\n", irn, l, r));
set_bitinfo(new_node, z, o);
exchange(irn, new_node);
env->modified = 1;
}
}
break;
}
}
}
void fixpoint_vrp(ir_graph* const irg)
{
assure_irg_properties(irg,
IR_GRAPH_PROPERTY_NO_BADS
| IR_GRAPH_PROPERTY_NO_UNREACHABLE_CODE
| IR_GRAPH_PROPERTY_CONSISTENT_DOMINANCE
| IR_GRAPH_PROPERTY_CONSISTENT_OUT_EDGES);
struct obstack private_obst;
obstack_init(&private_obst);
ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_PHI_LIST);
constbits_analyze(irg, &private_obst);
FIRM_DBG_REGISTER(dbg, "firm.opt.fp-vrp");
DB((dbg, LEVEL_1, "===> Performing constant propagation on %+F (optimization)\n", irg));