|
@@ -577,6 +577,19 @@ static int do_constant_folding_cond2(TCGArg *p1, TCGArg *p2, TCGCond c)
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * swap_commutative:
|
|
|
|
+ * @dest: TCGArg of the destination argument, or NO_DEST.
|
|
|
|
+ * @p1: first paired argument
|
|
|
|
+ * @p2: second paired argument
|
|
|
|
+ *
|
|
|
|
+ * If *@p1 is a constant and *@p2 is not, swap.
|
|
|
|
+ * If *@p2 matches @dest, swap.
|
|
|
|
+ * Return true if a swap was performed.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+#define NO_DEST temp_arg(NULL)
|
|
|
|
+
|
|
static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2)
|
|
static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2)
|
|
{
|
|
{
|
|
TCGArg a1 = *p1, a2 = *p2;
|
|
TCGArg a1 = *p1, a2 = *p2;
|
|
@@ -696,6 +709,12 @@ static bool fold_const2(OptContext *ctx, TCGOp *op)
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool fold_const2_commutative(OptContext *ctx, TCGOp *op)
|
|
|
|
+{
|
|
|
|
+ swap_commutative(op->args[0], &op->args[1], &op->args[2]);
|
|
|
|
+ return fold_const2(ctx, op);
|
|
|
|
+}
|
|
|
|
+
|
|
static bool fold_masks(OptContext *ctx, TCGOp *op)
|
|
static bool fold_masks(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
uint64_t a_mask = ctx->a_mask;
|
|
uint64_t a_mask = ctx->a_mask;
|
|
@@ -832,7 +851,7 @@ static bool fold_xx_to_x(OptContext *ctx, TCGOp *op)
|
|
|
|
|
|
static bool fold_add(OptContext *ctx, TCGOp *op)
|
|
static bool fold_add(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
- if (fold_const2(ctx, op) ||
|
|
|
|
|
|
+ if (fold_const2_commutative(ctx, op) ||
|
|
fold_xi_to_x(ctx, op, 0)) {
|
|
fold_xi_to_x(ctx, op, 0)) {
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
@@ -891,6 +910,10 @@ static bool fold_addsub2(OptContext *ctx, TCGOp *op, bool add)
|
|
|
|
|
|
static bool fold_add2(OptContext *ctx, TCGOp *op)
|
|
static bool fold_add2(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
|
|
+ /* Note that the high and low parts may be independently swapped. */
|
|
|
|
+ swap_commutative(op->args[0], &op->args[2], &op->args[4]);
|
|
|
|
+ swap_commutative(op->args[1], &op->args[3], &op->args[5]);
|
|
|
|
+
|
|
return fold_addsub2(ctx, op, true);
|
|
return fold_addsub2(ctx, op, true);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -898,7 +921,7 @@ static bool fold_and(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
uint64_t z1, z2;
|
|
uint64_t z1, z2;
|
|
|
|
|
|
- if (fold_const2(ctx, op) ||
|
|
|
|
|
|
+ if (fold_const2_commutative(ctx, op) ||
|
|
fold_xi_to_i(ctx, op, 0) ||
|
|
fold_xi_to_i(ctx, op, 0) ||
|
|
fold_xi_to_x(ctx, op, -1) ||
|
|
fold_xi_to_x(ctx, op, -1) ||
|
|
fold_xx_to_x(ctx, op)) {
|
|
fold_xx_to_x(ctx, op)) {
|
|
@@ -950,8 +973,13 @@ static bool fold_andc(OptContext *ctx, TCGOp *op)
|
|
static bool fold_brcond(OptContext *ctx, TCGOp *op)
|
|
static bool fold_brcond(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
TCGCond cond = op->args[2];
|
|
TCGCond cond = op->args[2];
|
|
- int i = do_constant_folding_cond(ctx->type, op->args[0], op->args[1], cond);
|
|
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ if (swap_commutative(NO_DEST, &op->args[0], &op->args[1])) {
|
|
|
|
+ op->args[2] = cond = tcg_swap_cond(cond);
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ i = do_constant_folding_cond(ctx->type, op->args[0], op->args[1], cond);
|
|
if (i == 0) {
|
|
if (i == 0) {
|
|
tcg_op_remove(ctx->tcg, op);
|
|
tcg_op_remove(ctx->tcg, op);
|
|
return true;
|
|
return true;
|
|
@@ -966,10 +994,14 @@ static bool fold_brcond(OptContext *ctx, TCGOp *op)
|
|
static bool fold_brcond2(OptContext *ctx, TCGOp *op)
|
|
static bool fold_brcond2(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
TCGCond cond = op->args[4];
|
|
TCGCond cond = op->args[4];
|
|
- int i = do_constant_folding_cond2(&op->args[0], &op->args[2], cond);
|
|
|
|
TCGArg label = op->args[5];
|
|
TCGArg label = op->args[5];
|
|
- int inv = 0;
|
|
|
|
|
|
+ int i, inv = 0;
|
|
|
|
|
|
|
|
+ if (swap_commutative2(&op->args[0], &op->args[2])) {
|
|
|
|
+ op->args[4] = cond = tcg_swap_cond(cond);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ i = do_constant_folding_cond2(&op->args[0], &op->args[2], cond);
|
|
if (i >= 0) {
|
|
if (i >= 0) {
|
|
goto do_brcond_const;
|
|
goto do_brcond_const;
|
|
}
|
|
}
|
|
@@ -1219,7 +1251,7 @@ static bool fold_dup2(OptContext *ctx, TCGOp *op)
|
|
|
|
|
|
static bool fold_eqv(OptContext *ctx, TCGOp *op)
|
|
static bool fold_eqv(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
- if (fold_const2(ctx, op) ||
|
|
|
|
|
|
+ if (fold_const2_commutative(ctx, op) ||
|
|
fold_xi_to_x(ctx, op, -1) ||
|
|
fold_xi_to_x(ctx, op, -1) ||
|
|
fold_xi_to_not(ctx, op, 0)) {
|
|
fold_xi_to_not(ctx, op, 0)) {
|
|
return true;
|
|
return true;
|
|
@@ -1381,8 +1413,20 @@ static bool fold_mov(OptContext *ctx, TCGOp *op)
|
|
static bool fold_movcond(OptContext *ctx, TCGOp *op)
|
|
static bool fold_movcond(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
TCGCond cond = op->args[5];
|
|
TCGCond cond = op->args[5];
|
|
- int i = do_constant_folding_cond(ctx->type, op->args[1], op->args[2], cond);
|
|
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ if (swap_commutative(NO_DEST, &op->args[1], &op->args[2])) {
|
|
|
|
+ op->args[5] = cond = tcg_swap_cond(cond);
|
|
|
|
+ }
|
|
|
|
+ /*
|
|
|
|
+ * Canonicalize the "false" input reg to match the destination reg so
|
|
|
|
+ * that the tcg backend can implement a "move if true" operation.
|
|
|
|
+ */
|
|
|
|
+ if (swap_commutative(op->args[0], &op->args[4], &op->args[3])) {
|
|
|
|
+ op->args[5] = cond = tcg_invert_cond(cond);
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ i = do_constant_folding_cond(ctx->type, op->args[1], op->args[2], cond);
|
|
if (i >= 0) {
|
|
if (i >= 0) {
|
|
return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[4 - i]);
|
|
return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[4 - i]);
|
|
}
|
|
}
|
|
@@ -1428,7 +1472,7 @@ static bool fold_mul(OptContext *ctx, TCGOp *op)
|
|
|
|
|
|
static bool fold_mul_highpart(OptContext *ctx, TCGOp *op)
|
|
static bool fold_mul_highpart(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
- if (fold_const2(ctx, op) ||
|
|
|
|
|
|
+ if (fold_const2_commutative(ctx, op) ||
|
|
fold_xi_to_i(ctx, op, 0)) {
|
|
fold_xi_to_i(ctx, op, 0)) {
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
@@ -1437,6 +1481,8 @@ static bool fold_mul_highpart(OptContext *ctx, TCGOp *op)
|
|
|
|
|
|
static bool fold_multiply2(OptContext *ctx, TCGOp *op)
|
|
static bool fold_multiply2(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
|
|
+ swap_commutative(op->args[0], &op->args[2], &op->args[3]);
|
|
|
|
+
|
|
if (arg_is_const(op->args[2]) && arg_is_const(op->args[3])) {
|
|
if (arg_is_const(op->args[2]) && arg_is_const(op->args[3])) {
|
|
uint64_t a = arg_info(op->args[2])->val;
|
|
uint64_t a = arg_info(op->args[2])->val;
|
|
uint64_t b = arg_info(op->args[3])->val;
|
|
uint64_t b = arg_info(op->args[3])->val;
|
|
@@ -1480,7 +1526,7 @@ static bool fold_multiply2(OptContext *ctx, TCGOp *op)
|
|
|
|
|
|
static bool fold_nand(OptContext *ctx, TCGOp *op)
|
|
static bool fold_nand(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
- if (fold_const2(ctx, op) ||
|
|
|
|
|
|
+ if (fold_const2_commutative(ctx, op) ||
|
|
fold_xi_to_not(ctx, op, -1)) {
|
|
fold_xi_to_not(ctx, op, -1)) {
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
@@ -1509,7 +1555,7 @@ static bool fold_neg(OptContext *ctx, TCGOp *op)
|
|
|
|
|
|
static bool fold_nor(OptContext *ctx, TCGOp *op)
|
|
static bool fold_nor(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
- if (fold_const2(ctx, op) ||
|
|
|
|
|
|
+ if (fold_const2_commutative(ctx, op) ||
|
|
fold_xi_to_not(ctx, op, 0)) {
|
|
fold_xi_to_not(ctx, op, 0)) {
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
@@ -1529,7 +1575,7 @@ static bool fold_not(OptContext *ctx, TCGOp *op)
|
|
|
|
|
|
static bool fold_or(OptContext *ctx, TCGOp *op)
|
|
static bool fold_or(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
- if (fold_const2(ctx, op) ||
|
|
|
|
|
|
+ if (fold_const2_commutative(ctx, op) ||
|
|
fold_xi_to_x(ctx, op, 0) ||
|
|
fold_xi_to_x(ctx, op, 0) ||
|
|
fold_xx_to_x(ctx, op)) {
|
|
fold_xx_to_x(ctx, op)) {
|
|
return true;
|
|
return true;
|
|
@@ -1581,8 +1627,13 @@ static bool fold_remainder(OptContext *ctx, TCGOp *op)
|
|
static bool fold_setcond(OptContext *ctx, TCGOp *op)
|
|
static bool fold_setcond(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
TCGCond cond = op->args[3];
|
|
TCGCond cond = op->args[3];
|
|
- int i = do_constant_folding_cond(ctx->type, op->args[1], op->args[2], cond);
|
|
|
|
|
|
+ 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) {
|
|
if (i >= 0) {
|
|
return tcg_opt_gen_movi(ctx, op, op->args[0], i);
|
|
return tcg_opt_gen_movi(ctx, op, op->args[0], i);
|
|
}
|
|
}
|
|
@@ -1594,9 +1645,13 @@ static bool fold_setcond(OptContext *ctx, TCGOp *op)
|
|
static bool fold_setcond2(OptContext *ctx, TCGOp *op)
|
|
static bool fold_setcond2(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
TCGCond cond = op->args[5];
|
|
TCGCond cond = op->args[5];
|
|
- int i = do_constant_folding_cond2(&op->args[1], &op->args[3], cond);
|
|
|
|
- int inv = 0;
|
|
|
|
|
|
+ int i, inv = 0;
|
|
|
|
+
|
|
|
|
+ if (swap_commutative2(&op->args[1], &op->args[3])) {
|
|
|
|
+ op->args[5] = cond = tcg_swap_cond(cond);
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ i = do_constant_folding_cond2(&op->args[1], &op->args[3], cond);
|
|
if (i >= 0) {
|
|
if (i >= 0) {
|
|
goto do_setcond_const;
|
|
goto do_setcond_const;
|
|
}
|
|
}
|
|
@@ -1774,7 +1829,7 @@ static bool fold_tcg_ld(OptContext *ctx, TCGOp *op)
|
|
|
|
|
|
static bool fold_xor(OptContext *ctx, TCGOp *op)
|
|
static bool fold_xor(OptContext *ctx, TCGOp *op)
|
|
{
|
|
{
|
|
- if (fold_const2(ctx, op) ||
|
|
|
|
|
|
+ if (fold_const2_commutative(ctx, op) ||
|
|
fold_xx_to_i(ctx, op, 0) ||
|
|
fold_xx_to_i(ctx, op, 0) ||
|
|
fold_xi_to_x(ctx, op, 0) ||
|
|
fold_xi_to_x(ctx, op, 0) ||
|
|
fold_xi_to_not(ctx, op, -1)) {
|
|
fold_xi_to_not(ctx, op, -1)) {
|
|
@@ -1827,63 +1882,6 @@ void tcg_optimize(TCGContext *s)
|
|
ctx.type = TCG_TYPE_I32;
|
|
ctx.type = TCG_TYPE_I32;
|
|
}
|
|
}
|
|
|
|
|
|
- /* For commutative operations make constant second argument */
|
|
|
|
- switch (opc) {
|
|
|
|
- CASE_OP_32_64_VEC(add):
|
|
|
|
- CASE_OP_32_64_VEC(mul):
|
|
|
|
- CASE_OP_32_64_VEC(and):
|
|
|
|
- CASE_OP_32_64_VEC(or):
|
|
|
|
- CASE_OP_32_64_VEC(xor):
|
|
|
|
- CASE_OP_32_64(eqv):
|
|
|
|
- CASE_OP_32_64(nand):
|
|
|
|
- CASE_OP_32_64(nor):
|
|
|
|
- CASE_OP_32_64(muluh):
|
|
|
|
- CASE_OP_32_64(mulsh):
|
|
|
|
- swap_commutative(op->args[0], &op->args[1], &op->args[2]);
|
|
|
|
- break;
|
|
|
|
- CASE_OP_32_64(brcond):
|
|
|
|
- if (swap_commutative(-1, &op->args[0], &op->args[1])) {
|
|
|
|
- op->args[2] = tcg_swap_cond(op->args[2]);
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- CASE_OP_32_64(setcond):
|
|
|
|
- if (swap_commutative(op->args[0], &op->args[1], &op->args[2])) {
|
|
|
|
- op->args[3] = tcg_swap_cond(op->args[3]);
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- CASE_OP_32_64(movcond):
|
|
|
|
- if (swap_commutative(-1, &op->args[1], &op->args[2])) {
|
|
|
|
- op->args[5] = tcg_swap_cond(op->args[5]);
|
|
|
|
- }
|
|
|
|
- /* For movcond, we canonicalize the "false" input reg to match
|
|
|
|
- the destination reg so that the tcg backend can implement
|
|
|
|
- a "move if true" operation. */
|
|
|
|
- if (swap_commutative(op->args[0], &op->args[4], &op->args[3])) {
|
|
|
|
- op->args[5] = tcg_invert_cond(op->args[5]);
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- CASE_OP_32_64(add2):
|
|
|
|
- swap_commutative(op->args[0], &op->args[2], &op->args[4]);
|
|
|
|
- swap_commutative(op->args[1], &op->args[3], &op->args[5]);
|
|
|
|
- break;
|
|
|
|
- CASE_OP_32_64(mulu2):
|
|
|
|
- CASE_OP_32_64(muls2):
|
|
|
|
- swap_commutative(op->args[0], &op->args[2], &op->args[3]);
|
|
|
|
- break;
|
|
|
|
- case INDEX_op_brcond2_i32:
|
|
|
|
- if (swap_commutative2(&op->args[0], &op->args[2])) {
|
|
|
|
- op->args[4] = tcg_swap_cond(op->args[4]);
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- case INDEX_op_setcond2_i32:
|
|
|
|
- if (swap_commutative2(&op->args[1], &op->args[3])) {
|
|
|
|
- op->args[5] = tcg_swap_cond(op->args[5]);
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/* Assume all bits affected, and no bits known zero. */
|
|
/* Assume all bits affected, and no bits known zero. */
|
|
ctx.a_mask = -1;
|
|
ctx.a_mask = -1;
|
|
ctx.z_mask = -1;
|
|
ctx.z_mask = -1;
|