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 * ...@@ -97,8 +97,6 @@ typedef ir_node *(create_trampoline_fkt)(ir_node *block, ir_node *mem, ir_node *
* propagated to the libFirm parameter set. * propagated to the libFirm parameter set.
*/ */
typedef struct backend_params { 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 */ /** the backend uses big-endian byte ordering if set, else little endian */
unsigned byte_order_big_endian:1; unsigned byte_order_big_endian:1;
/** whether the architecure can natively handle modulo shift modes. /** 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); ...@@ -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); 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. * The output mode for tarval values.
* *
......
...@@ -28,9 +28,9 @@ ...@@ -28,9 +28,9 @@
#include "constbits.h" #include "constbits.h"
/* TODO: /* TODO:
* - Implement cleared/set bit calculation for Add, Sub, Minus, Mul, Div, Mod, Shl, Shr, Shrs, Rotl * - 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, Rotl, Mux * - 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, Rotl, Mux * - Implement min/max calculation for Add, Sub, Minus, Mul, Div, Mod, Conv, Shl, Shr, Shrs, Mux
*/ */
/* Tables of the cleared/set bit lattice /* Tables of the cleared/set bit lattice
...@@ -329,19 +329,6 @@ undefined: ...@@ -329,19 +329,6 @@ undefined:
break; 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: { case iro_Add: {
bitinfo* const l = get_bitinfo(get_Add_left(irn)); bitinfo* const l = get_bitinfo(get_Add_left(irn));
bitinfo* const r = get_bitinfo(get_Add_right(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) ...@@ -181,20 +181,6 @@ static int vrp_update_node(ir_vrp_info *info, ir_node *node)
break; 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: { case iro_Shl: {
const vrp_attr *vrp_left; const vrp_attr *vrp_left;
const ir_node *right = get_Shl_right(node); 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, ...@@ -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 const backend_params *TEMPLATE_get_backend_params(void)
{ {
static backend_params p = { static backend_params p = {
0, /* no support for Rotl nodes */
0, /* 0: little-endian, 1: big-endian */ 0, /* 0: little-endian, 1: big-endian */
1, /* modulo shift efficient */ 1, /* modulo shift efficient */
0, /* non-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, ...@@ -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 const backend_params *amd64_get_backend_params(void) {
static backend_params p = { static backend_params p = {
1, /* support Rotl nodes */
0, /* little endian */ 0, /* little endian */
1, /* modulo shift is efficient */ 1, /* modulo shift is efficient */
0, /* non-modulo shift is not 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, ...@@ -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); 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. * Creates an ARM Add.
* *
...@@ -503,6 +528,14 @@ static ir_node *gen_int_binop(ir_node *node, match_flags_t flags, ...@@ -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) 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 = { static const arm_binop_factory_t add_factory = {
new_bd_arm_Add_reg, new_bd_arm_Add_reg,
new_bd_arm_Add_imm, new_bd_arm_Add_imm,
...@@ -611,13 +644,20 @@ static ir_node *gen_And(ir_node *node) ...@@ -611,13 +644,20 @@ static ir_node *gen_And(ir_node *node)
static ir_node *gen_Or(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 = { static const arm_binop_factory_t or_factory = {
new_bd_arm_Or_reg, new_bd_arm_Or_reg,
new_bd_arm_Or_imm, new_bd_arm_Or_imm,
new_bd_arm_Or_reg_shift_reg, new_bd_arm_Or_reg_shift_reg,
new_bd_arm_Or_reg_shift_imm new_bd_arm_Or_reg_shift_imm
}; };
return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, &or_factory); return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, &or_factory);
} }
...@@ -749,89 +789,6 @@ static ir_node *gen_Shrs(ir_node *node) ...@@ -749,89 +789,6 @@ static ir_node *gen_Shrs(ir_node *node)
return make_shift(node, MATCH_NONE, ARM_SHF_ASR_REG); 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) static ir_node *gen_Not(ir_node *node)
{ {
ir_node *block = be_transform_node(get_nodes_block(node)); ir_node *block = be_transform_node(get_nodes_block(node));
...@@ -1905,7 +1862,6 @@ static void arm_register_transformers(void) ...@@ -1905,7 +1862,6 @@ static void arm_register_transformers(void)
be_set_transform_function(op_Or, gen_Or); be_set_transform_function(op_Or, gen_Or);
be_set_transform_function(op_Phi, gen_Phi); be_set_transform_function(op_Phi, gen_Phi);
be_set_transform_function(op_Return, gen_Return); 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_Sel, gen_Sel);
be_set_transform_function(op_Shl, gen_Shl); be_set_transform_function(op_Shl, gen_Shl);
be_set_transform_function(op_Shr, gen_Shr); be_set_transform_function(op_Shr, gen_Shr);
......
...@@ -466,7 +466,6 @@ static const backend_params *arm_get_libfirm_params(void) ...@@ -466,7 +466,6 @@ static const backend_params *arm_get_libfirm_params(void)
32, /* SMUL & UMUL available for 32 bit */ 32, /* SMUL & UMUL available for 32 bit */
}; };
static backend_params p = { static backend_params p = {
1, /* support Rotl nodes */
1, /* big endian */ 1, /* big endian */
1, /* modulo shift efficient */ 1, /* modulo shift efficient */
0, /* non-modulo shift not efficient */ 0, /* non-modulo shift not efficient */
......
...@@ -544,3 +544,61 @@ void be_start_transform_setup(void) ...@@ -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_Shr, shr_upper_bits_clean);
be_set_upper_bits_clean_function(op_Shrs, shrs_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); ...@@ -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); 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 #endif
...@@ -1462,7 +1462,6 @@ static const ir_settings_arch_dep_t ia32_arch_dep = { ...@@ -1462,7 +1462,6 @@ static const ir_settings_arch_dep_t ia32_arch_dep = {
32, /* Mulh allowed up to 32 bit */ 32, /* Mulh allowed up to 32 bit */
}; };
static backend_params ia32_backend_params = { static backend_params ia32_backend_params = {
1, /* support Rotl nodes */
0, /* little endian */ 0, /* little endian */
1, /* modulo shift efficient */ 1, /* modulo shift efficient */
0, /* non-modulo shift not efficient */ 0, /* non-modulo shift not efficient */
......
...@@ -1313,6 +1313,16 @@ static ir_node *match_64bit_shift(ir_node *node) ...@@ -1313,6 +1313,16 @@ static ir_node *match_64bit_shift(ir_node *node)
return NULL; 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. * Creates an ia32 Add.
* *
...@@ -1324,6 +1334,14 @@ static ir_node *gen_Add(ir_node *node) ...@@ -1324,6 +1334,14 @@ static ir_node *gen_Add(ir_node *node)
ir_node *op1 = get_Add_left(node); ir_node *op1 = get_Add_left(node);
ir_node *op2 = get_Add_right(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); ir_node *new_node = match_64bit_shift(node);
if (new_node != NULL) if (new_node != NULL)
return new_node; return new_node;
...@@ -1499,13 +1517,16 @@ static ir_node *gen_And(ir_node *node) ...@@ -1499,13 +1517,16 @@ static ir_node *gen_And(ir_node *node)
| match_immediate); | match_immediate);
} }
/**
* Creates an ia32 Or.
*
* @return The created ia32 Or node
*/
static ir_node *gen_Or(ir_node *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); ir_node *res = match_64bit_shift(node);
if (res != NULL) if (res != NULL)
return res; return res;
...@@ -1810,49 +1831,6 @@ static ir_node *gen_Shrs(ir_node *node) ...@@ -1810,49 +1831,6 @@ static ir_node *gen_Shrs(ir_node *node)
match_immediate | match_upconv); 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. * Transforms a Minus node.
* *
...@@ -2377,6 +2355,22 @@ static ir_node *try_create_dest_am(ir_node *node) ...@@ -2377,6 +2355,22 @@ static ir_node *try_create_dest_am(ir_node *node)
ir_node *new_node; ir_node *new_node;
switch (get_irn_opcode(val)) { switch (get_irn_opcode(val)) {
case iro_Add: { 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 *op1 = get_Add_left(val);
ir_node *op2 = get_Add_right(val); ir_node *op2 = get_Add_right(val);
if (ia32_cg_config.use_incdec) { if (ia32_cg_config.use_incdec) {
...@@ -2415,6 +2409,22 @@ static ir_node *try_create_dest_am(ir_node *node) ...@@ -2415,6 +2409,22 @@ static ir_node *try_create_dest_am(ir_node *node)
break; break;
} }
case iro_Or: { 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 *op1 = get_Or_left(val);
ir_node *op2 = get_Or_right(val); ir_node *op2 = get_Or_right(val);
new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, 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) ...@@ -2454,15 +2464,6 @@ static ir_node *try_create_dest_am(ir_node *node)