case OP_SWL:
case OP_SW:
case OP_SWR:
+ case OP_META_LWU:
+ case OP_META_SWU:
return BIT(op.i.rs) | BIT(op.i.rt);
case OP_META:
return BIT(op.m.rs);
case OP_LBU:
case OP_LHU:
case OP_LWR:
+ case OP_META_LWU:
return BIT(op.i.rt);
case OP_JAL:
return BIT(31);
if (opcode_writes_register(list[i].c, reg))
return true;
+ if (is_syscall(list[i].c))
+ return false;
+
if (has_delay_slot(list[i].c)) {
if (op_flag_no_ds(list[i].flags) ||
opcode_reads_register(list[i + 1].c, reg))
case OP_LHU:
case OP_LWR:
case OP_LWC2:
+ case OP_META_LWU:
return true;
default:
return false;
case OP_SWL:
case OP_SWR:
case OP_SWC2:
+ case OP_META_SWU:
return true;
default:
return false;
case OP_LBU:
case OP_LHU:
case OP_LWR:
+ case OP_META_LWU:
return false;
default:
return true;
case OP_SWL:
case OP_SW:
case OP_SWR:
+ case OP_META_SWU:
if (is_known_zero(v, op->i.rt))
op->i.rt = 0;
fallthrough;
case OP_LWR:
case OP_LWC2:
case OP_SWC2:
+ case OP_META_LWU:
if (is_known(v, op->i.rs)
&& kunseg(v[op->i.rs].value) == 0)
op->i.rs = 0;
}
}
+static void maybe_remove_load_delay(struct opcode *op)
+{
+ if (op_flag_load_delay(op->flags) && opcode_is_load(op->c))
+ op->flags &= ~LIGHTREC_LOAD_DELAY;
+}
+
static int lightrec_transform_ops(struct lightrec_state *state, struct block *block)
{
struct opcode *op, *list = block->opcode_list;
struct constprop_data v[32] = LIGHTREC_CONSTPROP_INITIALIZER;
unsigned int i;
bool local;
+ int idx;
u8 tmp;
for (i = 0; i < block->nb_ops; i++) {
(v[op->i.rs].value ^ v[op->i.rt].value)) {
pr_debug("Found never-taken BEQ\n");
+ if (!op_flag_no_ds(op->flags))
+ maybe_remove_load_delay(&list[i + 1]);
+
local = op_flag_local_branch(op->flags);
op->opcode = 0;
op->flags = 0;
v[op->i.rs].value == v[op->i.rt].value) {
pr_debug("Found never-taken BNE\n");
+ if (!op_flag_no_ds(op->flags))
+ maybe_remove_load_delay(&list[i + 1]);
+
local = op_flag_local_branch(op->flags);
op->opcode = 0;
op->flags = 0;
v[op->i.rs].value & BIT(31)) {
pr_debug("Found never-taken BGTZ\n");
+ if (!op_flag_no_ds(op->flags))
+ maybe_remove_load_delay(&list[i + 1]);
+
local = op_flag_local_branch(op->flags);
op->opcode = 0;
op->flags = 0;
}
}
break;
+ case OP_LWL:
+ case OP_LWR:
+ if (i == 0 || !has_delay_slot(list[i - 1].c)) {
+ idx = find_next_reader(list, i + 1, op->i.rt);
+ if (idx > 0 && list[idx].i.op == (op->i.op ^ 0x4)
+ && list[idx].i.rs == op->i.rs
+ && list[idx].i.rt == op->i.rt
+ && abs((s16)op->i.imm - (s16)list[idx].i.imm) == 3) {
+ /* Replace a LWL/LWR combo with a META_LWU */
+ if (op->i.op == OP_LWL)
+ op->i.imm -= 3;
+ op->i.op = OP_META_LWU;
+ list[idx].opcode = 0;
+ pr_debug("Convert LWL/LWR to LWU\n");
+ }
+ }
+ break;
+ case OP_SWL:
+ case OP_SWR:
+ if (i == 0 || !has_delay_slot(list[i - 1].c)) {
+ idx = find_next_reader(list, i + 1, op->i.rt);
+ if (idx > 0 && list[idx].i.op == (op->i.op ^ 0x4)
+ && list[idx].i.rs == op->i.rs
+ && list[idx].i.rt == op->i.rt
+ && abs((s16)op->i.imm - (s16)list[idx].i.imm) == 3) {
+ /* Replace a SWL/SWR combo with a META_SWU */
+ if (op->i.op == OP_SWL)
+ op->i.imm -= 3;
+ op->i.op = OP_META_SWU;
+ list[idx].opcode = 0;
+ pr_debug("Convert SWL/SWR to SWU\n");
+ }
+ }
+ break;
case OP_REGIMM:
switch (op->r.rt) {
case OP_REGIMM_BLTZ:
} else {
pr_debug("Found never-taken BLTZ/BGEZ\n");
+ if (!op_flag_no_ds(op->flags))
+ maybe_remove_load_delay(&list[i + 1]);
+
local = op_flag_local_branch(op->flags);
op->opcode = 0;
op->flags = 0;