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

get rid of an explicit Rotl node

The backends which support rotl now match for or(shl,shr) patterns.
parent d4c5eceb
......@@ -97,8 +97,6 @@ typedef ir_node *(create_trampoline_fkt)(ir_node *block, ir_node *mem, ir_node *
* propagated to the libFirm parameter set.
*/
typedef struct backend_params {
/** If set, the backend supports Rotl nodes */
unsigned support_rotl:1;
/** the backend uses big-endian byte ordering if set, else little endian */
unsigned byte_order_big_endian:1;
/** whether the architecure can natively handle modulo shift modes.
......
......@@ -590,16 +590,6 @@ FIRM_API ir_tarval *tarval_shrs(ir_tarval *a, ir_tarval *b);
*/
FIRM_API ir_tarval *tarval_shrs_unsigned(ir_tarval *a, unsigned b);
/**
* Rotation to left.
*
* @param a the first tarval
* @param b the second tarval
*
* @return a \<\<L\>\> b or tarval_bad
*/
FIRM_API ir_tarval *tarval_rotl(ir_tarval *a, ir_tarval *b);
/**
* The output mode for tarval values.
*
......
......@@ -28,9 +28,9 @@
#include "constbits.h"
/* TODO:
* - Implement cleared/set bit calculation for Add, Sub, Minus, Mul, Div, Mod, Shl, Shr, Shrs, Rotl
* - Implement min/max calculation for And, Eor, Or, Not, Conv, Shl, Shr, Shrs, Rotl, Mux
* - Implement min/max calculation for Add, Sub, Minus, Mul, Div, Mod, Conv, Shl, Shr, Shrs, Rotl, Mux
* - Implement cleared/set bit calculation for Add, Sub, Minus, Mul, Div, Mod, Shl, Shr, Shrs
* - Implement min/max calculation for And, Eor, Or, Not, Conv, Shl, Shr, Shrs, Mux
* - Implement min/max calculation for Add, Sub, Minus, Mul, Div, Mod, Conv, Shl, Shr, Shrs, Mux
*/
/* Tables of the cleared/set bit lattice
......@@ -329,19 +329,6 @@ undefined:
break;
}
case iro_Rotl: {
bitinfo* const l = get_bitinfo(get_Rotl_left(irn));
bitinfo* const r = get_bitinfo(get_Rotl_right(irn));
ir_tarval* const rz = r->z;
if (rz == r->o) {
z = tarval_rotl(l->z, rz);
o = tarval_rotl(l->o, rz);
} else {
goto cannot_analyse;
}
break;
}
case iro_Add: {
bitinfo* const l = get_bitinfo(get_Add_left(irn));
bitinfo* const r = get_bitinfo(get_Add_right(irn));
......
......@@ -181,20 +181,6 @@ static int vrp_update_node(ir_vrp_info *info, ir_node *node)
break;
}
case iro_Rotl: {
const vrp_attr *vrp_left;
const ir_node *right = get_Rotl_right(node);
vrp_left = vrp_get_or_set_info(info, get_Rotl_left(node));
/* We can only compute this if the right value is a constant*/
if (is_Const(right)) {
new_bits_set = tarval_rotl(vrp_left->bits_set, get_Const_tarval(right));
new_bits_not_set = tarval_rotl(vrp_left->bits_not_set, get_Const_tarval(right));
}
break;
}
case iro_Shl: {
const vrp_attr *vrp_left;
const ir_node *right = get_Shl_right(node);
......
......@@ -246,7 +246,6 @@ static int TEMPLATE_is_mux_allowed(ir_node *sel, ir_node *mux_false,
static const backend_params *TEMPLATE_get_backend_params(void)
{
static backend_params p = {
0, /* no support for Rotl nodes */
0, /* 0: little-endian, 1: big-endian */
1, /* modulo shift efficient */
0, /* non-modulo shift efficient */
......
......@@ -384,7 +384,6 @@ static int amd64_is_mux_allowed(ir_node *sel, ir_node *mux_false,
*/
static const backend_params *amd64_get_backend_params(void) {
static backend_params p = {
1, /* support Rotl nodes */
0, /* little endian */
1, /* modulo shift is efficient */
0, /* non-modulo shift is not efficient */
......
......@@ -496,6 +496,31 @@ static ir_node *gen_int_binop(ir_node *node, match_flags_t flags,
return factory->new_binop_reg(dbgi, block, new_op1, new_op2);
}
static ir_node *gen_Ror(ir_node *node, ir_node *op1, ir_node *op2,
bool negate_op)
{
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *block = be_transform_node(get_nodes_block(node));
ir_node *new_op1 = be_transform_node(op1);
if (is_Const(op2)) {
ir_tarval *tv = get_Const_tarval(op2);
ir_mode *mode = get_irn_mode(node);
long bits = get_mode_size_bits(mode);
if (tarval_is_long(tv) && bits == 32) {
long val = get_tarval_long(tv);
val = (negate_op ? bits - val : val) & 31;
return new_bd_arm_Mov_reg_shift_imm(dbgi, block, new_op1, ARM_SHF_ROR_IMM, val);
}
}
ir_node *new_op2 = be_transform_node(op2);
if (negate_op) {
new_op2 = new_bd_arm_Rsb_imm(dbgi, block, new_op2, 32, 0);
}
return new_bd_arm_Mov_reg_shift_reg(dbgi, block, new_op1, new_op2,
ARM_SHF_ROR_REG);
}
/**
* Creates an ARM Add.
*
......@@ -503,6 +528,14 @@ static ir_node *gen_int_binop(ir_node *node, match_flags_t flags,
*/
static ir_node *gen_Add(ir_node *node)
{
ir_node *rotl_left;
ir_node *rotl_right;
if (be_pattern_is_rotl(node, &rotl_left, &rotl_right)) {
if (is_Minus(rotl_right))
return gen_Ror(node, rotl_left, get_Minus_op(rotl_right), false);
return gen_Ror(node, rotl_left, rotl_right, true);
}
static const arm_binop_factory_t add_factory = {
new_bd_arm_Add_reg,
new_bd_arm_Add_imm,
......@@ -611,13 +644,20 @@ static ir_node *gen_And(ir_node *node)
static ir_node *gen_Or(ir_node *node)
{
ir_node *rotl_left;
ir_node *rotl_right;
if (be_pattern_is_rotl(node, &rotl_left, &rotl_right)) {
if (is_Minus(rotl_right))
return gen_Ror(node, rotl_left, get_Minus_op(rotl_right), false);
return gen_Ror(node, rotl_left, rotl_right, true);
}
static const arm_binop_factory_t or_factory = {
new_bd_arm_Or_reg,
new_bd_arm_Or_imm,
new_bd_arm_Or_reg_shift_reg,
new_bd_arm_Or_reg_shift_imm
};
return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, &or_factory);
}
......@@ -749,89 +789,6 @@ static ir_node *gen_Shrs(ir_node *node)
return make_shift(node, MATCH_NONE, ARM_SHF_ASR_REG);
}
static ir_node *gen_Ror(ir_node *node, ir_node *op1, ir_node *op2)
{
ir_node *block = be_transform_node(get_nodes_block(node));
ir_node *new_op1 = be_transform_node(op1);
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *new_op2 = be_transform_node(op2);
return new_bd_arm_Mov_reg_shift_reg(dbgi, block, new_op1, new_op2,
ARM_SHF_ROR_REG);
}
static ir_node *gen_Rol(ir_node *node, ir_node *op1, ir_node *op2)
{
ir_node *block = be_transform_node(get_nodes_block(node));
ir_node *new_op1 = be_transform_node(op1);
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *new_op2 = be_transform_node(op2);
/* Note: there is no Rol on arm, we have to use Ror */
new_op2 = new_bd_arm_Rsb_imm(dbgi, block, new_op2, 32, 0);
return new_bd_arm_Mov_reg_shift_reg(dbgi, block, new_op1, new_op2,
ARM_SHF_ROR_REG);
}
static ir_node *gen_Rotl(ir_node *node)
{
ir_node *rotate = NULL;
ir_node *op1 = get_Rotl_left(node);
ir_node *op2 = get_Rotl_right(node);
/* Firm has only RotL, so we are looking for a right (op2)
operand "-e+mode_size_bits" (it's an already modified "mode_size_bits-e",
that means we can create a RotR. */
if (is_Add(op2)) {
ir_node *right = get_Add_right(op2);
if (is_Const(right)) {
ir_tarval *tv = get_Const_tarval(right);
ir_mode *mode = get_irn_mode(node);
long bits = get_mode_size_bits(mode);
ir_node *left = get_Add_left(op2);
if (is_Minus(left) &&
tarval_is_long(tv) &&
get_tarval_long(tv) == bits &&
bits == 32)
rotate = gen_Ror(node, op1, get_Minus_op(left));
}
} else if (is_Sub(op2)) {
ir_node *left = get_Sub_left(op2);
if (is_Const(left)) {
ir_tarval *tv = get_Const_tarval(left);
ir_mode *mode = get_irn_mode(node);
long bits = get_mode_size_bits(mode);
ir_node *right = get_Sub_right(op2);
if (tarval_is_long(tv) &&
get_tarval_long(tv) == bits &&
bits == 32)
rotate = gen_Ror(node, op1, right);
}
} else if (is_Const(op2)) {
ir_tarval *tv = get_Const_tarval(op2);
ir_mode *mode = get_irn_mode(node);
long bits = get_mode_size_bits(mode);
if (tarval_is_long(tv) && bits == 32) {
ir_node *block = be_transform_node(get_nodes_block(node));
ir_node *new_op1 = be_transform_node(op1);
dbg_info *dbgi = get_irn_dbg_info(node);
bits = (bits - get_tarval_long(tv)) & 31;
rotate = new_bd_arm_Mov_reg_shift_imm(dbgi, block, new_op1, ARM_SHF_ROR_IMM, bits);
}
}
if (rotate == NULL) {
rotate = gen_Rol(node, op1, op2);
}
return rotate;
}
static ir_node *gen_Not(ir_node *node)
{
ir_node *block = be_transform_node(get_nodes_block(node));
......@@ -1905,7 +1862,6 @@ static void arm_register_transformers(void)
be_set_transform_function(op_Or, gen_Or);
be_set_transform_function(op_Phi, gen_Phi);
be_set_transform_function(op_Return, gen_Return);
be_set_transform_function(op_Rotl, gen_Rotl);
be_set_transform_function(op_Sel, gen_Sel);
be_set_transform_function(op_Shl, gen_Shl);
be_set_transform_function(op_Shr, gen_Shr);
......
......@@ -466,7 +466,6 @@ static const backend_params *arm_get_libfirm_params(void)
32, /* SMUL & UMUL available for 32 bit */
};
static backend_params p = {
1, /* support Rotl nodes */
1, /* big endian */
1, /* modulo shift efficient */
0, /* non-modulo shift not efficient */
......
......@@ -544,3 +544,61 @@ void be_start_transform_setup(void)
be_set_upper_bits_clean_function(op_Shr, shr_upper_bits_clean);
be_set_upper_bits_clean_function(op_Shrs, shrs_upper_bits_clean);
}
bool be_pattern_is_rotl(ir_node const *const irn_or, ir_node **const left,
ir_node **const right)
{
assert(is_Add(irn_or) || is_Or(irn_or));
ir_mode *mode = get_irn_mode(irn_or);
if (!mode_is_int(mode))
return false;
ir_node *shl = get_binop_left(irn_or);
ir_node *shr = get_binop_right(irn_or);
if (is_Shr(shl)) {
if (!is_Shl(shr))
return false;
ir_node *tmp = shl;
shl = shr;
shr = tmp;
} else if (!is_Shl(shl)) {
return false;
} else if (!is_Shr(shr)) {
return false;
}
ir_node *x = get_Shl_left(shl);
if (x != get_Shr_left(shr))
return false;
ir_node *c1 = get_Shl_right(shl);
ir_node *c2 = get_Shr_right(shr);
if (is_Const(c1) && is_Const(c2)) {
ir_tarval *tv1 = get_Const_tarval(c1);
if (!tarval_is_long(tv1))
return false;
ir_tarval *tv2 = get_Const_tarval(c2);
if (!tarval_is_long(tv2))
return false;
if (get_tarval_long(tv1) + get_tarval_long(tv2)
!= (long) get_mode_size_bits(mode))
return false;
*left = x;
*right = c1;
return true;
}
/* Note: the obvious rot formulation (a << x) | (a >> (32-x)) gets
* transformed to (a << x) | (a >> -x) by transform_node_shift_modulo() */
if (!ir_is_negated_value(c1, c2))
return false;
*left = x;
*right = c1;
return true;
}
......@@ -95,4 +95,10 @@ void be_set_upper_bits_clean_function(ir_op *op, upper_bits_clean_func func);
*/
bool be_upper_bits_clean(const ir_node *node, ir_mode *mode);
/**
* returns true if node is the root pattern of a (left) rotation.
* The root @p node must be an Add or Or node.
*/
bool be_pattern_is_rotl(const ir_node *node, ir_node **left, ir_node **right);
#endif
......@@ -1462,7 +1462,6 @@ static const ir_settings_arch_dep_t ia32_arch_dep = {
32, /* Mulh allowed up to 32 bit */
};
static backend_params ia32_backend_params = {
1, /* support Rotl nodes */
0, /* little endian */
1, /* modulo shift efficient */
0, /* non-modulo shift not efficient */
......
......@@ -1313,6 +1313,16 @@ static ir_node *match_64bit_shift(ir_node *node)
return NULL;
}
static ir_node *gen_Rol(ir_node *node, ir_node *op1, ir_node *op2)
{
return gen_shift_binop(node, op1, op2, new_bd_ia32_Rol, match_immediate);
}
static ir_node *gen_Ror(ir_node *node, ir_node *op1, ir_node *op2)
{
return gen_shift_binop(node, op1, op2, new_bd_ia32_Ror, match_immediate);
}
/**
* Creates an ia32 Add.
*
......@@ -1324,6 +1334,14 @@ static ir_node *gen_Add(ir_node *node)
ir_node *op1 = get_Add_left(node);
ir_node *op2 = get_Add_right(node);
ir_node *rot_left;
ir_node *rot_right;
if (be_pattern_is_rotl(node, &rot_left, &rot_right)) {
if (is_Minus(rot_right))
return gen_Ror(node, rot_left, get_Minus_op(rot_right));
return gen_Rol(node, rot_left, rot_right);
}
ir_node *new_node = match_64bit_shift(node);
if (new_node != NULL)
return new_node;
......@@ -1499,13 +1517,16 @@ static ir_node *gen_And(ir_node *node)
| match_immediate);
}
/**
* Creates an ia32 Or.
*
* @return The created ia32 Or node
*/
static ir_node *gen_Or(ir_node *node)
{
ir_node *rot_left;
ir_node *rot_right;
if (be_pattern_is_rotl(node, &rot_left, &rot_right)) {
if (is_Minus(rot_right))
return gen_Ror(node, rot_left, get_Minus_op(rot_right));
return gen_Rol(node, rot_left, rot_right);
}
ir_node *res = match_64bit_shift(node);
if (res != NULL)
return res;
......@@ -1810,49 +1831,6 @@ static ir_node *gen_Shrs(ir_node *node)
match_immediate | match_upconv);
}
/**
* Creates an ia32 Rol.
*
* @param op1 The first operator
* @param op2 The second operator
* @return The created ia32 RotL node
*/
static ir_node *gen_Rol(ir_node *node, ir_node *op1, ir_node *op2)
{
return gen_shift_binop(node, op1, op2, new_bd_ia32_Rol, match_immediate);
}
/**
* Creates an ia32 Ror.
* NOTE: There is no RotR with immediate because this would always be a RotL
* "imm-mode_size_bits" which can be pre-calculated.
*
* @param op1 The first operator
* @param op2 The second operator
* @return The created ia32 RotR node
*/
static ir_node *gen_Ror(ir_node *node, ir_node *op1, ir_node *op2)
{
return gen_shift_binop(node, op1, op2, new_bd_ia32_Ror, match_immediate);
}
/**
* Creates an ia32 RotR or RotL (depending on the found pattern).
*
* @return The created ia32 RotL or RotR node
*/
static ir_node *gen_Rotl(ir_node *node)
{
ir_node *op1 = get_Rotl_left(node);
ir_node *op2 = get_Rotl_right(node);
if (is_Minus(op2)) {
return gen_Ror(node, op1, get_Minus_op(op2));
}
return gen_Rol(node, op1, op2);
}
/**
* Transforms a Minus node.
*
......@@ -2377,6 +2355,22 @@ static ir_node *try_create_dest_am(ir_node *node)
ir_node *new_node;
switch (get_irn_opcode(val)) {
case iro_Add: {
ir_node *rot_left;
ir_node *rot_right;
if (be_pattern_is_rotl(val, &rot_left, &rot_right)) {
if (is_Minus(rot_right)) {
rot_right = get_Minus_op(rot_right);
new_node = dest_am_binop(val, rot_left, rot_right, mem, ptr,
mode, new_bd_ia32_RorMem,
new_bd_ia32_RorMem, match_immediate);
} else {
new_node = dest_am_binop(val, rot_left, rot_right, mem, ptr,
mode, new_bd_ia32_RolMem,
new_bd_ia32_RolMem, match_immediate);
}
break;
}
ir_node *op1 = get_Add_left(val);
ir_node *op2 = get_Add_right(val);
if (ia32_cg_config.use_incdec) {
......@@ -2415,6 +2409,22 @@ static ir_node *try_create_dest_am(ir_node *node)
break;
}
case iro_Or: {
ir_node *rot_left;
ir_node *rot_right;
if (be_pattern_is_rotl(val, &rot_left, &rot_right)) {
if (is_Minus(rot_right)) {
rot_right = get_Minus_op(rot_right);
new_node = dest_am_binop(val, rot_left, rot_right, mem, ptr,
mode, new_bd_ia32_RorMem,
new_bd_ia32_RorMem, match_immediate);
} else {
new_node = dest_am_binop(val, rot_left, rot_right, mem, ptr,
mode, new_bd_ia32_RolMem,
new_bd_ia32_RolMem, match_immediate);
}
break;
}
ir_node *op1 = get_Or_left(val);
ir_node *op2 = get_Or_right(val);
new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
......@@ -2454,15 +2464,6 @@ static ir_node *try_create_dest_am(ir_node *node)
match_immediate);
break;
}
case iro_Rotl: {
ir_node *op1 = get_Rotl_left(val);
ir_node *op2 = get_Rotl_right(val);
/* TODO: match ROR patterns... */
new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
new_bd_ia32_RolMem, new_bd_ia32_RolMem,
match_immediate);
break;
}
case iro_Mux:
new_node = try_create_SetMem(val, ptr, mem);
break;
......@@ -5340,7 +5341,6 @@ static void register_transformers(void)
be_set_transform_function(op_Not, gen_Not);
be_set_transform_function(op_Or, gen_Or);
be_set_transform_function(op_Phi, gen_Phi);
be_set_transform_function(op_Rotl, gen_Rotl);
be_set_transform_function(op_Shl, gen_Shl);
be_set_transform_function(op_Shr, gen_Shr);
be_set_transform_function(op_Shrs, gen_Shrs);
......
......@@ -549,7 +549,6 @@ static const backend_params *sparc_get_backend_params(void)
32, /* max_bits_for_mulh */
};
static backend_params p = {
0, /* no support for RotL nodes */
1, /* big endian */
1, /* modulo shift efficient */
0, /* non-modulo shift not efficient */
......
......@@ -400,23 +400,6 @@ static ir_tarval *computed_value_Shrs(const ir_node *n)
return tarval_bad;
}
/**
* Return the value of a Rotl.
*/
static ir_tarval *computed_value_Rotl(const ir_node *n)
{
ir_node *a = get_Rotl_left(n);
ir_node *b = get_Rotl_right(n);
ir_tarval *ta = value_of(a);
ir_tarval *tb = value_of(b);
if ((ta != tarval_bad) && (tb != tarval_bad)) {
return tarval_rotl(ta, tb);
}
return tarval_bad;
}
bool ir_zero_when_converted(const ir_node *node, ir_mode *dest_mode)
{
ir_mode *mode = get_irn_mode(node);
......@@ -1687,7 +1670,7 @@ static ir_node *create_zero_const(ir_graph *irg, ir_mode *mode)
static bool is_shiftop(const ir_node *n)
{
return is_Shl(n) || is_Shr(n) || is_Shrs(n) || is_Rotl(n);
return is_Shl(n) || is_Shr(n) || is_Shrs(n);
}
/* the order of the values is important! */
......@@ -1852,79 +1835,6 @@ static ir_node *transform_node_Or_bf_store(ir_node *irn_or)
}
}
/**
* Optimize an Or(shl(x, c), shr(x, bits - c)) into a Rotl
*/
static ir_node *transform_node_Or_Rotl(ir_node *irn_or)
{
ir_mode *mode = get_irn_mode(irn_or);
ir_node *shl, *shr, *block;
ir_node *irn, *x, *c1, *c2, *n;
ir_tarval *tv1, *tv2;
/* some backends can't handle rotl */
if (!be_get_backend_param()->support_rotl)
return irn_or;
if (! mode_is_int(mode))
return irn_or;
shl = get_binop_left(irn_or);
shr = get_binop_right(irn_or);
if (is_Shr(shl)) {
if (!is_Shl(shr))
return irn_or;
irn = shl;
shl = shr;
shr = irn;
} else if (!is_Shl(shl)) {
return irn_or;
} else if (!is_Shr(shr)) {
return irn_or;
}
x = get_Shl_left(shl);
if (x != get_Shr_left(shr))
return irn_or;
c1 = get_Shl_right(shl);
c2 = get_Shr_right(shr);
if (is_Const(c1) && is_Const(c2)) {
tv1 = get_Const_tarval(c1);
if (! tarval_is_long(tv1))
return irn_or;