git subrepo pull --force deps/lightrec
[pcsx_rearmed.git] / deps / lightrec / optimizer.c
index 98a26f6..f719192 100644 (file)
@@ -463,6 +463,10 @@ static u32 lightrec_propagate_consts(const struct opcode *op, u32 known, u32 *v)
 {
        union code c = op->c;
 
+       /* Register $zero is always, well, zero */
+       known |= BIT(0);
+       v[0] = 0;
+
        if (op->flags & LIGHTREC_SYNC)
                return 0;
 
@@ -833,10 +837,6 @@ static int lightrec_transform_ops(struct lightrec_state *state, struct block *bl
                if (!op->opcode)
                        continue;
 
-               /* Register $zero is always, well, zero */
-               known |= BIT(0);
-               values[0] = 0;
-
                switch (op->i.op) {
                case OP_BEQ:
                        if (op->i.rs == op->i.rt) {
@@ -1238,10 +1238,6 @@ static int lightrec_flag_io(struct lightrec_state *state, struct block *block)
        for (i = 0; i < block->nb_ops; i++) {
                list = &block->opcode_list[i];
 
-               /* Register $zero is always, well, zero */
-               known |= BIT(0);
-               values[0] = 0;
-
                switch (list->i.op) {
                case OP_SB:
                case OP_SH:
@@ -1476,11 +1472,22 @@ static void lightrec_replace_lo_hi(struct block *block, u16 offset,
        }
 }
 
+static bool lightrec_always_skip_div_check(void)
+{
+#ifdef __mips__
+       return true;
+#else
+       return false;
+#endif
+}
+
 static int lightrec_flag_mults_divs(struct lightrec_state *state, struct block *block)
 {
        struct opcode *list;
        u8 reg_hi, reg_lo;
        unsigned int i;
+       u32 known = BIT(0);
+       u32 values[32] = { 0 };
 
        for (i = 0; i < block->nb_ops - 1; i++) {
                list = &block->opcode_list[i];
@@ -1489,19 +1496,27 @@ static int lightrec_flag_mults_divs(struct lightrec_state *state, struct block *
                        continue;
 
                switch (list->r.op) {
-               case OP_SPECIAL_MULT:
-               case OP_SPECIAL_MULTU:
                case OP_SPECIAL_DIV:
                case OP_SPECIAL_DIVU:
+                       /* If we are dividing by a non-zero constant, don't
+                        * emit the div-by-zero check. */
+                       if (lightrec_always_skip_div_check() ||
+                           (known & BIT(list->c.r.rt) && values[list->c.r.rt]))
+                               list->flags |= LIGHTREC_NO_DIV_CHECK;
+               case OP_SPECIAL_MULT: /* fall-through */
+               case OP_SPECIAL_MULTU:
                        break;
                default:
+                       known = lightrec_propagate_consts(list, known, values);
                        continue;
                }
 
                /* Don't support opcodes in delay slots */
                if ((i && has_delay_slot(block->opcode_list[i - 1].c)) ||
-                   (list->flags & LIGHTREC_NO_DS))
+                   (list->flags & LIGHTREC_NO_DS)) {
+                       known = lightrec_propagate_consts(list, known, values);
                        continue;
+               }
 
                reg_lo = get_mfhi_mflo_reg(block, i + 1, NULL, 0, false, true, false);
                if (reg_lo == 0) {
@@ -1543,6 +1558,8 @@ static int lightrec_flag_mults_divs(struct lightrec_state *state, struct block *
                } else {
                        list->r.imm = 0;
                }
+
+               known = lightrec_propagate_consts(list, known, values);
        }
 
        return 0;