tcg/optimize: Handle vector opcodes during optimize
Trivial move and constant propagation. Some identity and constant function folding, but nothing that requires knowledge of the size of the vector element. Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
22fc352703
commit
170ba88f45
150
tcg/optimize.c
150
tcg/optimize.c
|
@ -32,6 +32,11 @@
|
||||||
glue(glue(case INDEX_op_, x), _i32): \
|
glue(glue(case INDEX_op_, x), _i32): \
|
||||||
glue(glue(case INDEX_op_, x), _i64)
|
glue(glue(case INDEX_op_, x), _i64)
|
||||||
|
|
||||||
|
#define CASE_OP_32_64_VEC(x) \
|
||||||
|
glue(glue(case INDEX_op_, x), _i32): \
|
||||||
|
glue(glue(case INDEX_op_, x), _i64): \
|
||||||
|
glue(glue(case INDEX_op_, x), _vec)
|
||||||
|
|
||||||
struct tcg_temp_info {
|
struct tcg_temp_info {
|
||||||
bool is_const;
|
bool is_const;
|
||||||
TCGTemp *prev_copy;
|
TCGTemp *prev_copy;
|
||||||
|
@ -108,40 +113,6 @@ static void init_arg_info(struct tcg_temp_info *infos,
|
||||||
init_ts_info(infos, temps_used, arg_temp(arg));
|
init_ts_info(infos, temps_used, arg_temp(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int op_bits(TCGOpcode op)
|
|
||||||
{
|
|
||||||
const TCGOpDef *def = &tcg_op_defs[op];
|
|
||||||
return def->flags & TCG_OPF_64BIT ? 64 : 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
static TCGOpcode op_to_mov(TCGOpcode op)
|
|
||||||
{
|
|
||||||
switch (op_bits(op)) {
|
|
||||||
case 32:
|
|
||||||
return INDEX_op_mov_i32;
|
|
||||||
case 64:
|
|
||||||
return INDEX_op_mov_i64;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "op_to_mov: unexpected return value of "
|
|
||||||
"function op_bits.\n");
|
|
||||||
tcg_abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static TCGOpcode op_to_movi(TCGOpcode op)
|
|
||||||
{
|
|
||||||
switch (op_bits(op)) {
|
|
||||||
case 32:
|
|
||||||
return INDEX_op_movi_i32;
|
|
||||||
case 64:
|
|
||||||
return INDEX_op_movi_i64;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "op_to_movi: unexpected return value of "
|
|
||||||
"function op_bits.\n");
|
|
||||||
tcg_abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static TCGTemp *find_better_copy(TCGContext *s, TCGTemp *ts)
|
static TCGTemp *find_better_copy(TCGContext *s, TCGTemp *ts)
|
||||||
{
|
{
|
||||||
TCGTemp *i;
|
TCGTemp *i;
|
||||||
|
@ -199,11 +170,23 @@ static bool args_are_copies(TCGArg arg1, TCGArg arg2)
|
||||||
|
|
||||||
static void tcg_opt_gen_movi(TCGContext *s, TCGOp *op, TCGArg dst, TCGArg val)
|
static void tcg_opt_gen_movi(TCGContext *s, TCGOp *op, TCGArg dst, TCGArg val)
|
||||||
{
|
{
|
||||||
TCGOpcode new_op = op_to_movi(op->opc);
|
const TCGOpDef *def;
|
||||||
|
TCGOpcode new_op;
|
||||||
tcg_target_ulong mask;
|
tcg_target_ulong mask;
|
||||||
struct tcg_temp_info *di = arg_info(dst);
|
struct tcg_temp_info *di = arg_info(dst);
|
||||||
|
|
||||||
|
def = &tcg_op_defs[op->opc];
|
||||||
|
if (def->flags & TCG_OPF_VECTOR) {
|
||||||
|
new_op = INDEX_op_dupi_vec;
|
||||||
|
} else if (def->flags & TCG_OPF_64BIT) {
|
||||||
|
new_op = INDEX_op_movi_i64;
|
||||||
|
} else {
|
||||||
|
new_op = INDEX_op_movi_i32;
|
||||||
|
}
|
||||||
op->opc = new_op;
|
op->opc = new_op;
|
||||||
|
/* TCGOP_VECL and TCGOP_VECE remain unchanged. */
|
||||||
|
op->args[0] = dst;
|
||||||
|
op->args[1] = val;
|
||||||
|
|
||||||
reset_temp(dst);
|
reset_temp(dst);
|
||||||
di->is_const = true;
|
di->is_const = true;
|
||||||
|
@ -214,15 +197,13 @@ static void tcg_opt_gen_movi(TCGContext *s, TCGOp *op, TCGArg dst, TCGArg val)
|
||||||
mask |= ~0xffffffffull;
|
mask |= ~0xffffffffull;
|
||||||
}
|
}
|
||||||
di->mask = mask;
|
di->mask = mask;
|
||||||
|
|
||||||
op->args[0] = dst;
|
|
||||||
op->args[1] = val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tcg_opt_gen_mov(TCGContext *s, TCGOp *op, TCGArg dst, TCGArg src)
|
static void tcg_opt_gen_mov(TCGContext *s, TCGOp *op, TCGArg dst, TCGArg src)
|
||||||
{
|
{
|
||||||
TCGTemp *dst_ts = arg_temp(dst);
|
TCGTemp *dst_ts = arg_temp(dst);
|
||||||
TCGTemp *src_ts = arg_temp(src);
|
TCGTemp *src_ts = arg_temp(src);
|
||||||
|
const TCGOpDef *def;
|
||||||
struct tcg_temp_info *di;
|
struct tcg_temp_info *di;
|
||||||
struct tcg_temp_info *si;
|
struct tcg_temp_info *si;
|
||||||
tcg_target_ulong mask;
|
tcg_target_ulong mask;
|
||||||
|
@ -236,9 +217,16 @@ static void tcg_opt_gen_mov(TCGContext *s, TCGOp *op, TCGArg dst, TCGArg src)
|
||||||
reset_ts(dst_ts);
|
reset_ts(dst_ts);
|
||||||
di = ts_info(dst_ts);
|
di = ts_info(dst_ts);
|
||||||
si = ts_info(src_ts);
|
si = ts_info(src_ts);
|
||||||
new_op = op_to_mov(op->opc);
|
def = &tcg_op_defs[op->opc];
|
||||||
|
if (def->flags & TCG_OPF_VECTOR) {
|
||||||
|
new_op = INDEX_op_mov_vec;
|
||||||
|
} else if (def->flags & TCG_OPF_64BIT) {
|
||||||
|
new_op = INDEX_op_mov_i64;
|
||||||
|
} else {
|
||||||
|
new_op = INDEX_op_mov_i32;
|
||||||
|
}
|
||||||
op->opc = new_op;
|
op->opc = new_op;
|
||||||
|
/* TCGOP_VECL and TCGOP_VECE remain unchanged. */
|
||||||
op->args[0] = dst;
|
op->args[0] = dst;
|
||||||
op->args[1] = src;
|
op->args[1] = src;
|
||||||
|
|
||||||
|
@ -417,8 +405,9 @@ static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y)
|
||||||
|
|
||||||
static TCGArg do_constant_folding(TCGOpcode op, TCGArg x, TCGArg y)
|
static TCGArg do_constant_folding(TCGOpcode op, TCGArg x, TCGArg y)
|
||||||
{
|
{
|
||||||
|
const TCGOpDef *def = &tcg_op_defs[op];
|
||||||
TCGArg res = do_constant_folding_2(op, x, y);
|
TCGArg res = do_constant_folding_2(op, x, y);
|
||||||
if (op_bits(op) == 32) {
|
if (!(def->flags & TCG_OPF_64BIT)) {
|
||||||
res = (int32_t)res;
|
res = (int32_t)res;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@ -508,13 +497,12 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x,
|
||||||
tcg_target_ulong xv = arg_info(x)->val;
|
tcg_target_ulong xv = arg_info(x)->val;
|
||||||
tcg_target_ulong yv = arg_info(y)->val;
|
tcg_target_ulong yv = arg_info(y)->val;
|
||||||
if (arg_is_const(x) && arg_is_const(y)) {
|
if (arg_is_const(x) && arg_is_const(y)) {
|
||||||
switch (op_bits(op)) {
|
const TCGOpDef *def = &tcg_op_defs[op];
|
||||||
case 32:
|
tcg_debug_assert(!(def->flags & TCG_OPF_VECTOR));
|
||||||
return do_constant_folding_cond_32(xv, yv, c);
|
if (def->flags & TCG_OPF_64BIT) {
|
||||||
case 64:
|
|
||||||
return do_constant_folding_cond_64(xv, yv, c);
|
return do_constant_folding_cond_64(xv, yv, c);
|
||||||
default:
|
} else {
|
||||||
tcg_abort();
|
return do_constant_folding_cond_32(xv, yv, c);
|
||||||
}
|
}
|
||||||
} else if (args_are_copies(x, y)) {
|
} else if (args_are_copies(x, y)) {
|
||||||
return do_constant_folding_cond_eq(c);
|
return do_constant_folding_cond_eq(c);
|
||||||
|
@ -653,11 +641,11 @@ void tcg_optimize(TCGContext *s)
|
||||||
|
|
||||||
/* For commutative operations make constant second argument */
|
/* For commutative operations make constant second argument */
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
CASE_OP_32_64(add):
|
CASE_OP_32_64_VEC(add):
|
||||||
CASE_OP_32_64(mul):
|
CASE_OP_32_64_VEC(mul):
|
||||||
CASE_OP_32_64(and):
|
CASE_OP_32_64_VEC(and):
|
||||||
CASE_OP_32_64(or):
|
CASE_OP_32_64_VEC(or):
|
||||||
CASE_OP_32_64(xor):
|
CASE_OP_32_64_VEC(xor):
|
||||||
CASE_OP_32_64(eqv):
|
CASE_OP_32_64(eqv):
|
||||||
CASE_OP_32_64(nand):
|
CASE_OP_32_64(nand):
|
||||||
CASE_OP_32_64(nor):
|
CASE_OP_32_64(nor):
|
||||||
|
@ -722,7 +710,7 @@ void tcg_optimize(TCGContext *s)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
CASE_OP_32_64(sub):
|
CASE_OP_32_64_VEC(sub):
|
||||||
{
|
{
|
||||||
TCGOpcode neg_op;
|
TCGOpcode neg_op;
|
||||||
bool have_neg;
|
bool have_neg;
|
||||||
|
@ -734,9 +722,12 @@ void tcg_optimize(TCGContext *s)
|
||||||
if (opc == INDEX_op_sub_i32) {
|
if (opc == INDEX_op_sub_i32) {
|
||||||
neg_op = INDEX_op_neg_i32;
|
neg_op = INDEX_op_neg_i32;
|
||||||
have_neg = TCG_TARGET_HAS_neg_i32;
|
have_neg = TCG_TARGET_HAS_neg_i32;
|
||||||
} else {
|
} else if (opc == INDEX_op_sub_i64) {
|
||||||
neg_op = INDEX_op_neg_i64;
|
neg_op = INDEX_op_neg_i64;
|
||||||
have_neg = TCG_TARGET_HAS_neg_i64;
|
have_neg = TCG_TARGET_HAS_neg_i64;
|
||||||
|
} else {
|
||||||
|
neg_op = INDEX_op_neg_vec;
|
||||||
|
have_neg = TCG_TARGET_HAS_neg_vec;
|
||||||
}
|
}
|
||||||
if (!have_neg) {
|
if (!have_neg) {
|
||||||
break;
|
break;
|
||||||
|
@ -750,7 +741,7 @@ void tcg_optimize(TCGContext *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
CASE_OP_32_64(xor):
|
CASE_OP_32_64_VEC(xor):
|
||||||
CASE_OP_32_64(nand):
|
CASE_OP_32_64(nand):
|
||||||
if (!arg_is_const(op->args[1])
|
if (!arg_is_const(op->args[1])
|
||||||
&& arg_is_const(op->args[2])
|
&& arg_is_const(op->args[2])
|
||||||
|
@ -767,7 +758,7 @@ void tcg_optimize(TCGContext *s)
|
||||||
goto try_not;
|
goto try_not;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
CASE_OP_32_64(andc):
|
CASE_OP_32_64_VEC(andc):
|
||||||
if (!arg_is_const(op->args[2])
|
if (!arg_is_const(op->args[2])
|
||||||
&& arg_is_const(op->args[1])
|
&& arg_is_const(op->args[1])
|
||||||
&& arg_info(op->args[1])->val == -1) {
|
&& arg_info(op->args[1])->val == -1) {
|
||||||
|
@ -775,7 +766,7 @@ void tcg_optimize(TCGContext *s)
|
||||||
goto try_not;
|
goto try_not;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
CASE_OP_32_64(orc):
|
CASE_OP_32_64_VEC(orc):
|
||||||
CASE_OP_32_64(eqv):
|
CASE_OP_32_64(eqv):
|
||||||
if (!arg_is_const(op->args[2])
|
if (!arg_is_const(op->args[2])
|
||||||
&& arg_is_const(op->args[1])
|
&& arg_is_const(op->args[1])
|
||||||
|
@ -789,7 +780,10 @@ void tcg_optimize(TCGContext *s)
|
||||||
TCGOpcode not_op;
|
TCGOpcode not_op;
|
||||||
bool have_not;
|
bool have_not;
|
||||||
|
|
||||||
if (def->flags & TCG_OPF_64BIT) {
|
if (def->flags & TCG_OPF_VECTOR) {
|
||||||
|
not_op = INDEX_op_not_vec;
|
||||||
|
have_not = TCG_TARGET_HAS_not_vec;
|
||||||
|
} else if (def->flags & TCG_OPF_64BIT) {
|
||||||
not_op = INDEX_op_not_i64;
|
not_op = INDEX_op_not_i64;
|
||||||
have_not = TCG_TARGET_HAS_not_i64;
|
have_not = TCG_TARGET_HAS_not_i64;
|
||||||
} else {
|
} else {
|
||||||
|
@ -810,16 +804,16 @@ void tcg_optimize(TCGContext *s)
|
||||||
|
|
||||||
/* Simplify expression for "op r, a, const => mov r, a" cases */
|
/* Simplify expression for "op r, a, const => mov r, a" cases */
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
CASE_OP_32_64(add):
|
CASE_OP_32_64_VEC(add):
|
||||||
CASE_OP_32_64(sub):
|
CASE_OP_32_64_VEC(sub):
|
||||||
|
CASE_OP_32_64_VEC(or):
|
||||||
|
CASE_OP_32_64_VEC(xor):
|
||||||
|
CASE_OP_32_64_VEC(andc):
|
||||||
CASE_OP_32_64(shl):
|
CASE_OP_32_64(shl):
|
||||||
CASE_OP_32_64(shr):
|
CASE_OP_32_64(shr):
|
||||||
CASE_OP_32_64(sar):
|
CASE_OP_32_64(sar):
|
||||||
CASE_OP_32_64(rotl):
|
CASE_OP_32_64(rotl):
|
||||||
CASE_OP_32_64(rotr):
|
CASE_OP_32_64(rotr):
|
||||||
CASE_OP_32_64(or):
|
|
||||||
CASE_OP_32_64(xor):
|
|
||||||
CASE_OP_32_64(andc):
|
|
||||||
if (!arg_is_const(op->args[1])
|
if (!arg_is_const(op->args[1])
|
||||||
&& arg_is_const(op->args[2])
|
&& arg_is_const(op->args[2])
|
||||||
&& arg_info(op->args[2])->val == 0) {
|
&& arg_info(op->args[2])->val == 0) {
|
||||||
|
@ -827,8 +821,8 @@ void tcg_optimize(TCGContext *s)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
CASE_OP_32_64(and):
|
CASE_OP_32_64_VEC(and):
|
||||||
CASE_OP_32_64(orc):
|
CASE_OP_32_64_VEC(orc):
|
||||||
CASE_OP_32_64(eqv):
|
CASE_OP_32_64(eqv):
|
||||||
if (!arg_is_const(op->args[1])
|
if (!arg_is_const(op->args[1])
|
||||||
&& arg_is_const(op->args[2])
|
&& arg_is_const(op->args[2])
|
||||||
|
@ -1042,8 +1036,8 @@ void tcg_optimize(TCGContext *s)
|
||||||
|
|
||||||
/* Simplify expression for "op r, a, 0 => movi r, 0" cases */
|
/* Simplify expression for "op r, a, 0 => movi r, 0" cases */
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
CASE_OP_32_64(and):
|
CASE_OP_32_64_VEC(and):
|
||||||
CASE_OP_32_64(mul):
|
CASE_OP_32_64_VEC(mul):
|
||||||
CASE_OP_32_64(muluh):
|
CASE_OP_32_64(muluh):
|
||||||
CASE_OP_32_64(mulsh):
|
CASE_OP_32_64(mulsh):
|
||||||
if (arg_is_const(op->args[2])
|
if (arg_is_const(op->args[2])
|
||||||
|
@ -1058,8 +1052,8 @@ void tcg_optimize(TCGContext *s)
|
||||||
|
|
||||||
/* Simplify expression for "op r, a, a => mov r, a" cases */
|
/* Simplify expression for "op r, a, a => mov r, a" cases */
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
CASE_OP_32_64(or):
|
CASE_OP_32_64_VEC(or):
|
||||||
CASE_OP_32_64(and):
|
CASE_OP_32_64_VEC(and):
|
||||||
if (args_are_copies(op->args[1], op->args[2])) {
|
if (args_are_copies(op->args[1], op->args[2])) {
|
||||||
tcg_opt_gen_mov(s, op, op->args[0], op->args[1]);
|
tcg_opt_gen_mov(s, op, op->args[0], op->args[1]);
|
||||||
continue;
|
continue;
|
||||||
|
@ -1071,9 +1065,9 @@ void tcg_optimize(TCGContext *s)
|
||||||
|
|
||||||
/* Simplify expression for "op r, a, a => movi r, 0" cases */
|
/* Simplify expression for "op r, a, a => movi r, 0" cases */
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
CASE_OP_32_64(andc):
|
CASE_OP_32_64_VEC(andc):
|
||||||
CASE_OP_32_64(sub):
|
CASE_OP_32_64_VEC(sub):
|
||||||
CASE_OP_32_64(xor):
|
CASE_OP_32_64_VEC(xor):
|
||||||
if (args_are_copies(op->args[1], op->args[2])) {
|
if (args_are_copies(op->args[1], op->args[2])) {
|
||||||
tcg_opt_gen_movi(s, op, op->args[0], 0);
|
tcg_opt_gen_movi(s, op, op->args[0], 0);
|
||||||
continue;
|
continue;
|
||||||
|
@ -1087,13 +1081,23 @@ void tcg_optimize(TCGContext *s)
|
||||||
folding. Constants will be substituted to arguments by register
|
folding. Constants will be substituted to arguments by register
|
||||||
allocator where needed and possible. Also detect copies. */
|
allocator where needed and possible. Also detect copies. */
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
CASE_OP_32_64(mov):
|
CASE_OP_32_64_VEC(mov):
|
||||||
tcg_opt_gen_mov(s, op, op->args[0], op->args[1]);
|
tcg_opt_gen_mov(s, op, op->args[0], op->args[1]);
|
||||||
break;
|
break;
|
||||||
CASE_OP_32_64(movi):
|
CASE_OP_32_64(movi):
|
||||||
|
case INDEX_op_dupi_vec:
|
||||||
tcg_opt_gen_movi(s, op, op->args[0], op->args[1]);
|
tcg_opt_gen_movi(s, op, op->args[0], op->args[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INDEX_op_dup_vec:
|
||||||
|
if (arg_is_const(op->args[1])) {
|
||||||
|
tmp = arg_info(op->args[1])->val;
|
||||||
|
tmp = dup_const(TCGOP_VECE(op), tmp);
|
||||||
|
tcg_opt_gen_movi(s, op, op->args[0], tmp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
CASE_OP_32_64(not):
|
CASE_OP_32_64(not):
|
||||||
CASE_OP_32_64(neg):
|
CASE_OP_32_64(neg):
|
||||||
CASE_OP_32_64(ext8s):
|
CASE_OP_32_64(ext8s):
|
||||||
|
|
Loading…
Reference in a new issue