x87: Only use fucompp if one operand happens to be at st(1).
authorChristoph Mallon <christoph.mallon@gmx.de>
Wed, 14 Nov 2012 11:59:50 +0000 (12:59 +0100)
committerChristoph Mallon <christoph.mallon@gmx.de>
Thu, 15 Nov 2012 09:08:31 +0000 (10:08 +0100)
Otherwise the extra effort to get the operands to the right position is not worth it.
Further, this avoids the unnecessary effort when we not going to use fucompp in favor of fucomi anyway.

ir/be/ia32/ia32_x87.c

index 58a3391..82bc54d 100644 (file)
@@ -1223,60 +1223,19 @@ static int sim_Fucom(x87_state *state, ir_node *n)
                                        }
                                        /* res = tos X op, pop */
                                        pops    = 1;
-                               }
-                               /* different, move them to st and st(1) and pop both.
-                                  The tricky part is to get one into st(1).*/
-                               else if (op2_idx == 1) {
-                                       /* good, second operand is already in the right place, move the first */
-                                       if (op1_idx != 0) {
-                                               /* bring the first on top */
-                                               x87_create_fxch(state, n, op1_idx);
-                                               assert(op2_idx != 0);
-                                               op1_idx = 0;
-                                       }
-                                       /* res = tos X op, pop, pop */
-                                       pops = 2;
-                               } else if (op1_idx == 1) {
-                                       /* good, first operand is already in the right place, move the second */
-                                       if (op2_idx != 0) {
-                                               /* bring the first on top */
-                                               x87_create_fxch(state, n, op2_idx);
-                                               assert(op1_idx != 0);
-                                               op2_idx = 0;
-                                       }
-                                       /* res = op X tos, pop, pop */
-                                       pops = 2;
                                } else {
-                                       /* if one is already the TOS, we need two fxch */
-                                       if (op1_idx == 0) {
-                                               /* first one is TOS, move to st(1) */
-                                               x87_create_fxch(state, n, 1);
-                                               assert(op2_idx != 1);
-                                               op1_idx = 1;
-                                               x87_create_fxch(state, n, op2_idx);
-                                               op2_idx = 0;
-                                               /* res = op X tos, pop, pop */
-                                               pops    = 2;
-                                       } else if (op2_idx == 0) {
-                                               /* second one is TOS, move to st(1) */
-                                               x87_create_fxch(state, n, 1);
-                                               assert(op1_idx != 1);
-                                               op2_idx = 1;
-                                               x87_create_fxch(state, n, op1_idx);
-                                               op1_idx = 0;
-                                               /* res = tos X op, pop, pop */
-                                               pops    = 2;
-                                       } else {
-                                               /* none of them is either TOS or st(1), 3 fxch needed */
-                                               x87_create_fxch(state, n, op2_idx);
-                                               assert(op1_idx != 0);
-                                               x87_create_fxch(state, n, 1);
-                                               op2_idx = 1;
-                                               x87_create_fxch(state, n, op1_idx);
-                                               op1_idx = 0;
-                                               /* res = tos X op, pop, pop */
-                                               pops    = 2;
+                                       if (op1_idx != 0 && op2_idx != 0) {
+                                               /* Both not at tos: Move one operand to tos. Move the one not at
+                                                * pos 1, so we get a chance to use fucompp. */
+                                               if (op1_idx != 1) {
+                                                       x87_create_fxch(state, n, op1_idx);
+                                                       op1_idx = 0;
+                                               } else {
+                                                       x87_create_fxch(state, n, op2_idx);
+                                                       op2_idx = 0;
+                                               }
                                        }
+                                       pops = 2;
                                }
                        }
                }
@@ -1295,15 +1254,23 @@ static int sim_Fucom(x87_state *state, ir_node *n)
 
        /* patch the operation */
        if (is_ia32_vFucomFnstsw(n)) {
-               dst = pops == 2 ? op_ia32_FucomppFnstsw : op_ia32_FucomFnstsw;
-               for (int i = 0; i < pops; ++i)
+               if (pops == 2 && (op1_idx == 1 || op2_idx == 1)) {
+                       dst = op_ia32_FucomppFnstsw;
                        x87_pop(state);
+                       x87_pop(state);
+               } else {
+                       dst = op_ia32_FucomFnstsw;
+                       goto pop;
+               }
        } else if (is_ia32_vFucomi(n)) {
                dst = op_ia32_Fucomi;
+pop:
                if (pops != 0)
                        x87_pop(state);
-               if (pops == 2)
-                       x87_create_fpop(state, sched_next(n), 0);
+               if (pops == 2) {
+                       int const idx = (op1_idx != 0 ? op1_idx : op2_idx) - 1 /* Due to prior pop. */;
+                       x87_create_fpop(state, sched_next(n), idx);
+               }
        } else {
                panic("invalid operation %+F", n);
        }