{
union code c = op->c;
+ /* Register $zero is always, well, zero */
+ known |= BIT(0);
+ v[0] = 0;
+
if (op->flags & LIGHTREC_SYNC)
return 0;
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) {
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:
}
}
+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];
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) {
} else {
list->r.imm = 0;
}
+
+ known = lightrec_propagate_consts(list, known, values);
}
return 0;