diff options
Diffstat (limited to 'tcg/optimize.c')
| -rw-r--r-- | tcg/optimize.c | 78 |
1 files changed, 77 insertions, 1 deletions
diff --git a/tcg/optimize.c b/tcg/optimize.c index d2156367a3..3013eb04e6 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -1279,6 +1279,8 @@ static bool fold_ctpop(OptContext *ctx, TCGOp *op) static bool fold_deposit(OptContext *ctx, TCGOp *op) { + TCGOpcode and_opc; + if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) { uint64_t t1 = arg_info(op->args[1])->val; uint64_t t2 = arg_info(op->args[2])->val; @@ -1287,6 +1289,41 @@ static bool fold_deposit(OptContext *ctx, TCGOp *op) return tcg_opt_gen_movi(ctx, op, op->args[0], t1); } + switch (ctx->type) { + case TCG_TYPE_I32: + and_opc = INDEX_op_and_i32; + break; + case TCG_TYPE_I64: + and_opc = INDEX_op_and_i64; + break; + default: + g_assert_not_reached(); + } + + /* Inserting a value into zero at offset 0. */ + if (arg_is_const(op->args[1]) + && arg_info(op->args[1])->val == 0 + && op->args[3] == 0) { + uint64_t mask = MAKE_64BIT_MASK(0, op->args[4]); + + op->opc = and_opc; + op->args[1] = op->args[2]; + op->args[2] = temp_arg(tcg_constant_internal(ctx->type, mask)); + ctx->z_mask = mask & arg_info(op->args[1])->z_mask; + return false; + } + + /* Inserting zero into a value. */ + if (arg_is_const(op->args[2]) + && arg_info(op->args[2])->val == 0) { + uint64_t mask = deposit64(-1, op->args[3], op->args[4], 0); + + op->opc = and_opc; + op->args[2] = temp_arg(tcg_constant_internal(ctx->type, mask)); + ctx->z_mask = mask & arg_info(op->args[1])->z_mask; + return false; + } + ctx->z_mask = deposit64(arg_info(op->args[1])->z_mask, op->args[3], op->args[4], arg_info(op->args[2])->z_mask); @@ -1530,14 +1567,22 @@ static bool fold_movcond(OptContext *ctx, TCGOp *op) if (arg_is_const(op->args[3]) && arg_is_const(op->args[4])) { uint64_t tv = arg_info(op->args[3])->val; uint64_t fv = arg_info(op->args[4])->val; - TCGOpcode opc; + TCGOpcode opc, negopc = 0; switch (ctx->type) { case TCG_TYPE_I32: opc = INDEX_op_setcond_i32; + if (TCG_TARGET_HAS_negsetcond_i32) { + negopc = INDEX_op_negsetcond_i32; + } + tv = (int32_t)tv; + fv = (int32_t)fv; break; case TCG_TYPE_I64: opc = INDEX_op_setcond_i64; + if (TCG_TARGET_HAS_negsetcond_i64) { + negopc = INDEX_op_negsetcond_i64; + } break; default: g_assert_not_reached(); @@ -1549,6 +1594,14 @@ static bool fold_movcond(OptContext *ctx, TCGOp *op) } else if (fv == 1 && tv == 0) { op->opc = opc; op->args[3] = tcg_invert_cond(cond); + } else if (negopc) { + if (tv == -1 && fv == 0) { + op->opc = negopc; + op->args[3] = cond; + } else if (fv == -1 && tv == 0) { + op->opc = negopc; + op->args[3] = tcg_invert_cond(cond); + } } } return false; @@ -1759,6 +1812,26 @@ static bool fold_setcond(OptContext *ctx, TCGOp *op) return false; } +static bool fold_negsetcond(OptContext *ctx, TCGOp *op) +{ + TCGCond cond = op->args[3]; + int i; + + if (swap_commutative(op->args[0], &op->args[1], &op->args[2])) { + op->args[3] = cond = tcg_swap_cond(cond); + } + + i = do_constant_folding_cond(ctx->type, op->args[1], op->args[2], cond); + if (i >= 0) { + return tcg_opt_gen_movi(ctx, op, op->args[0], -i); + } + + /* Value is {0,-1} so all bits are repetitions of the sign. */ + ctx->s_mask = -1; + return false; +} + + static bool fold_setcond2(OptContext *ctx, TCGOp *op) { TCGCond cond = op->args[5]; @@ -2216,6 +2289,9 @@ void tcg_optimize(TCGContext *s) CASE_OP_32_64(setcond): done = fold_setcond(&ctx, op); break; + CASE_OP_32_64(negsetcond): + done = fold_negsetcond(&ctx, op); + break; case INDEX_op_setcond2_i32: done = fold_setcond2(&ctx, op); break; |