Commit cb61aa38 authored by Matthias Braun's avatar Matthias Braun
Browse files

iropt: recognize multiplication with power-of-2 as Shl behaviour

parent 6a7ef642
......@@ -91,6 +91,31 @@ static bool is_Eor_Add(const ir_node *node)
return get_tarval_lowest_bit(tv) == (int)get_mode_size_bits(mode)-1;
}
/**
* If node produces a left shift with a constant value return that value.
* This matches for x << c and x * C2 with C2 being a power of 2.
*/
static ir_tarval *is_shl_const_like(const ir_node *node)
{
if (is_Shl(node)) {
ir_node *right = get_Shl_right(node);
if (is_Const(right))
return get_Const_tarval(right);
} else if (is_Mul(node)) {
ir_node *right = get_Mul_right(node);
if (is_Const(right)) {
ir_tarval *tv = get_Const_tarval(right);
int low_bit = get_tarval_lowest_bit(tv);
int high_bit = get_tarval_highest_bit(tv);
/* is value a power of 2? */
if (low_bit == high_bit && low_bit != -1) {
return new_tarval_from_long(low_bit, get_tarval_mode(tv));
}
}
}
return NULL;
}
/**
* Returns the tarval of a Const node or tarval_unknown for all other nodes.
*/
......@@ -522,18 +547,13 @@ bool ir_zero_when_converted(const ir_node *node, ir_mode *dest_mode)
|| get_mode_arithmetic(dest_mode) != irma_twos_complement)
return false;
if (is_Shl(node)) {
const ir_node *count = get_Shl_right(node);
if (is_Const(count)) {
const ir_tarval *tv = get_Const_tarval(count);
if (tarval_is_long(tv)) {
long shiftval = get_tarval_long(tv);
long destbits = get_mode_size_bits(dest_mode);
if (shiftval >= destbits
&& shiftval < (long)get_mode_modulo_shift(mode))
return true;
}
}
ir_tarval *tv = is_shl_const_like(node);
if (tv != NULL && tarval_is_long(tv)) {
long shiftval = get_tarval_long(tv);
long destbits = get_mode_size_bits(dest_mode);
if (shiftval >= destbits
&& shiftval < (long)get_mode_modulo_shift(mode))
return true;
}
if (is_And(node)) {
ir_node *right = get_And_right(node);
......@@ -2969,6 +2989,8 @@ static ir_node *can_negate_cheaply(ir_node *node)
return NULL;
}
static ir_node *transform_node_shl_shr(ir_node *n);
static ir_node *transform_node_Mul(ir_node *n)
{
ir_node *oldn = n;
......@@ -2992,6 +3014,11 @@ static ir_node *transform_node_Mul(ir_node *n)
dbg_info *dbgi = get_irn_dbg_info(n);
ir_node *block = get_nodes_block(n);
return new_rd_Minus(dbgi, block, a, mode);
} else if (get_tarval_popcount(tv) == 1) {
/* multiplication behaves Shl-like */
n = transform_node_shl_shr(n);
if (n != oldn)
return n;
}
}
/* distribute minus:
......@@ -3383,7 +3410,9 @@ static ir_node *transform_node_shift_bitop(ir_node *n)
ir_node *new_shift;
ir_tarval *tv_shift;
if (is_Shl(n)) {
ir_tarval *shl_like = is_shl_const_like(n);
if (shl_like != NULL) {
tv2 = shl_like;
new_shift = new_rd_Shl(dbgi, block, bitop_left, right, mode);
tv_shift = tarval_shl(tv1, tv2);
} else if (is_Shr(n)) {
......@@ -4859,8 +4888,6 @@ static ir_node *transform_node_shift(ir_node *n)
*/
static ir_node *transform_node_shl_shr(ir_node *n)
{
assert(is_Shl(n) || is_Shr(n));
ir_node *right = get_binop_right(n);
if (!is_Const(right))
return n;
......@@ -4868,20 +4895,17 @@ static ir_node *transform_node_shl_shr(ir_node *n)
ir_node *left = get_binop_left(n);
ir_node *x;
ir_mode *mode = get_irn_mode(n);
ir_tarval *tv_shl;
ir_tarval *tv_shr;
ir_tarval *tv_mask;
int need_shrs = 0;
if (is_Shl(n) && (is_Shr(left) || is_Shrs(left))) {
bool need_shrs = false;
ir_tarval *tv_shl = is_shl_const_like(n);
if (tv_shl != NULL && (is_Shr(left) || is_Shrs(left))) {
ir_node *shr_right = get_binop_right(left);
if (!is_Const(shr_right))
return n;
x = get_binop_left(left);
tv_shr = get_Const_tarval(shr_right);
tv_shl = get_Const_tarval(right);
if (is_Shrs(left)) {
/* shrs variant only allowed if c1 >= c2 */
......@@ -4889,20 +4913,17 @@ static ir_node *transform_node_shl_shr(ir_node *n)
return n;
tv_mask = tarval_shrs(get_mode_all_one(mode), tv_shr);
need_shrs = 1;
need_shrs = true;
} else {
tv_mask = tarval_shr(get_mode_all_one(mode), tv_shr);
}
tv_mask = tarval_shl(tv_mask, tv_shl);
} else if (is_Shr(n) && is_Shl(left)) {
ir_node *shl_right = get_Shl_right(left);
if (!is_Const(shl_right))
} else if (is_Shr(n)) {
tv_shl = is_shl_const_like(left);
if (tv_shl == NULL)
return n;
x = get_Shl_left(left);
x = get_binop_left(left);
tv_shr = get_Const_tarval(right);
tv_shl = get_Const_tarval(shl_right);
tv_mask = tarval_shl(get_mode_all_one(mode), tv_shl);
tv_mask = tarval_shr(tv_mask, tv_shr);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment