- switch (op.i.op) {
- case OP_CP0:
- switch (op.r.rs) {
- case OP_CP0_MFC0:
- case OP_CP0_CFC0:
- return true;
- default:
- break;
- }
-
- break;
- case OP_CP2:
- if (op.r.op == OP_CP2_BASIC) {
- switch (op.r.rs) {
- case OP_CP2_BASIC_MFC2:
- case OP_CP2_BASIC_CFC2:
- return true;
- default:
- break;
- }
- }
-
- break;
- case OP_LB:
- case OP_LH:
- case OP_LW:
- case OP_LWL:
- case OP_LWR:
- case OP_LBU:
- case OP_LHU:
- return true;
- default:
- break;
- }
-
- return false;
-}
-
-static u32 lightrec_propagate_consts(const struct opcode *op,
- const struct opcode *prev,
- u32 known, u32 *v)
-{
- union code c = prev->c;
-
- /* Register $zero is always, well, zero */
- known |= BIT(0);
- v[0] = 0;
-
- if (op_flag_sync(op->flags))
- return BIT(0);
-
- switch (c.i.op) {
- case OP_SPECIAL:
- switch (c.r.op) {
- case OP_SPECIAL_SLL:
- if (known & BIT(c.r.rt)) {
- known |= BIT(c.r.rd);
- v[c.r.rd] = v[c.r.rt] << c.r.imm;
- } else {
- known &= ~BIT(c.r.rd);
- }
- break;
- case OP_SPECIAL_SRL:
- if (known & BIT(c.r.rt)) {
- known |= BIT(c.r.rd);
- v[c.r.rd] = v[c.r.rt] >> c.r.imm;
- } else {
- known &= ~BIT(c.r.rd);
- }
- break;
- case OP_SPECIAL_SRA:
- if (known & BIT(c.r.rt)) {
- known |= BIT(c.r.rd);
- v[c.r.rd] = (s32)v[c.r.rt] >> c.r.imm;
- } else {
- known &= ~BIT(c.r.rd);
- }
- break;
- case OP_SPECIAL_SLLV:
- if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
- known |= BIT(c.r.rd);
- v[c.r.rd] = v[c.r.rt] << (v[c.r.rs] & 0x1f);
- } else {
- known &= ~BIT(c.r.rd);
- }
- break;
- case OP_SPECIAL_SRLV:
- if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
- known |= BIT(c.r.rd);
- v[c.r.rd] = v[c.r.rt] >> (v[c.r.rs] & 0x1f);
- } else {
- known &= ~BIT(c.r.rd);
- }
- break;
- case OP_SPECIAL_SRAV:
- if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
- known |= BIT(c.r.rd);
- v[c.r.rd] = (s32)v[c.r.rt]
- >> (v[c.r.rs] & 0x1f);
- } else {
- known &= ~BIT(c.r.rd);
- }
- break;
- case OP_SPECIAL_ADD:
- case OP_SPECIAL_ADDU:
- if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
- known |= BIT(c.r.rd);
- v[c.r.rd] = (s32)v[c.r.rt] + (s32)v[c.r.rs];
- } else {
- known &= ~BIT(c.r.rd);
- }
- break;
- case OP_SPECIAL_SUB:
- case OP_SPECIAL_SUBU:
- if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
- known |= BIT(c.r.rd);
- v[c.r.rd] = v[c.r.rt] - v[c.r.rs];
- } else {
- known &= ~BIT(c.r.rd);
- }
- break;
- case OP_SPECIAL_AND:
- if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
- known |= BIT(c.r.rd);
- v[c.r.rd] = v[c.r.rt] & v[c.r.rs];
- } else {
- known &= ~BIT(c.r.rd);
- }
- break;
- case OP_SPECIAL_OR:
- if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
- known |= BIT(c.r.rd);
- v[c.r.rd] = v[c.r.rt] | v[c.r.rs];
- } else {
- known &= ~BIT(c.r.rd);
- }
- break;
- case OP_SPECIAL_XOR:
- if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
- known |= BIT(c.r.rd);
- v[c.r.rd] = v[c.r.rt] ^ v[c.r.rs];
- } else {
- known &= ~BIT(c.r.rd);
- }
- break;
- case OP_SPECIAL_NOR:
- if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
- known |= BIT(c.r.rd);
- v[c.r.rd] = ~(v[c.r.rt] | v[c.r.rs]);
- } else {
- known &= ~BIT(c.r.rd);
- }
- break;
- case OP_SPECIAL_SLT:
- if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
- known |= BIT(c.r.rd);
- v[c.r.rd] = (s32)v[c.r.rs] < (s32)v[c.r.rt];
- } else {
- known &= ~BIT(c.r.rd);
- }
- break;
- case OP_SPECIAL_SLTU:
- if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
- known |= BIT(c.r.rd);
- v[c.r.rd] = v[c.r.rs] < v[c.r.rt];
- } else {
- known &= ~BIT(c.r.rd);
- }
- break;
- case OP_SPECIAL_MULT:
- case OP_SPECIAL_MULTU:
- case OP_SPECIAL_DIV:
- case OP_SPECIAL_DIVU:
- if (OPT_FLAG_MULT_DIV && c.r.rd)
- known &= ~BIT(c.r.rd);
- if (OPT_FLAG_MULT_DIV && c.r.imm)
- known &= ~BIT(c.r.imm);
- break;
- case OP_SPECIAL_MFLO:
- case OP_SPECIAL_MFHI:
- known &= ~BIT(c.r.rd);
- break;
- default:
- break;
- }
- break;
- case OP_META_MULT2:
- case OP_META_MULTU2:
- if (OPT_FLAG_MULT_DIV && (known & BIT(c.r.rs))) {
- if (c.r.rd) {
- known |= BIT(c.r.rd);
-
- if (c.r.op < 32)
- v[c.r.rd] = v[c.r.rs] << c.r.op;
- else
- v[c.r.rd] = 0;
- }
-
- if (c.r.imm) {
- known |= BIT(c.r.imm);
-
- if (c.r.op >= 32)
- v[c.r.imm] = v[c.r.rs] << (c.r.op - 32);
- else if (c.i.op == OP_META_MULT2)
- v[c.r.imm] = (s32) v[c.r.rs] >> (32 - c.r.op);
- else
- v[c.r.imm] = v[c.r.rs] >> (32 - c.r.op);
- }
- } else {
- if (OPT_FLAG_MULT_DIV && c.r.rd)
- known &= ~BIT(c.r.rd);
- if (OPT_FLAG_MULT_DIV && c.r.imm)
- known &= ~BIT(c.r.imm);
- }
- break;
- case OP_REGIMM:
- break;
- case OP_ADDI:
- case OP_ADDIU:
- if (known & BIT(c.i.rs)) {
- known |= BIT(c.i.rt);
- v[c.i.rt] = v[c.i.rs] + (s32)(s16)c.i.imm;
- } else {
- known &= ~BIT(c.i.rt);
- }
- break;
- case OP_SLTI:
- if (known & BIT(c.i.rs)) {
- known |= BIT(c.i.rt);
- v[c.i.rt] = (s32)v[c.i.rs] < (s32)(s16)c.i.imm;
- } else {
- known &= ~BIT(c.i.rt);
- }
- break;
- case OP_SLTIU:
- if (known & BIT(c.i.rs)) {
- known |= BIT(c.i.rt);
- v[c.i.rt] = v[c.i.rs] < (u32)(s32)(s16)c.i.imm;
- } else {
- known &= ~BIT(c.i.rt);
- }
- break;
- case OP_ANDI:
- if (known & BIT(c.i.rs)) {
- known |= BIT(c.i.rt);
- v[c.i.rt] = v[c.i.rs] & c.i.imm;
- } else {
- known &= ~BIT(c.i.rt);
- }
- break;
- case OP_ORI:
- if (known & BIT(c.i.rs)) {
- known |= BIT(c.i.rt);
- v[c.i.rt] = v[c.i.rs] | c.i.imm;
- } else {
- known &= ~BIT(c.i.rt);
- }
- break;
- case OP_XORI:
- if (known & BIT(c.i.rs)) {
- known |= BIT(c.i.rt);
- v[c.i.rt] = v[c.i.rs] ^ c.i.imm;
- } else {
- known &= ~BIT(c.i.rt);
- }
- break;
- case OP_LUI:
- known |= BIT(c.i.rt);
- v[c.i.rt] = c.i.imm << 16;
- break;
- case OP_CP0:
- switch (c.r.rs) {
- case OP_CP0_MFC0:
- case OP_CP0_CFC0:
- known &= ~BIT(c.r.rt);
- break;
- }
- break;
- case OP_CP2:
- if (c.r.op == OP_CP2_BASIC) {
- switch (c.r.rs) {
- case OP_CP2_BASIC_MFC2:
- case OP_CP2_BASIC_CFC2:
- known &= ~BIT(c.r.rt);
- break;
- }
- }
- break;
- case OP_LB:
- case OP_LH:
- case OP_LWL:
- case OP_LW:
- case OP_LBU:
- case OP_LHU:
- case OP_LWR:
- case OP_LWC2:
- known &= ~BIT(c.i.rt);
- break;
- case OP_META_MOV:
- if (known & BIT(c.r.rs)) {
- known |= BIT(c.r.rd);
- v[c.r.rd] = v[c.r.rs];
- } else {
- known &= ~BIT(c.r.rd);
- }
- break;
- case OP_META_EXTC:
- if (known & BIT(c.i.rs)) {
- known |= BIT(c.i.rt);
- v[c.i.rt] = (s32)(s8)v[c.i.rs];
- } else {
- known &= ~BIT(c.i.rt);
- }
- break;
- case OP_META_EXTS:
- if (known & BIT(c.i.rs)) {
- known |= BIT(c.i.rt);
- v[c.i.rt] = (s32)(s16)v[c.i.rs];
- } else {
- known &= ~BIT(c.i.rt);
- }
- break;
- default:
- break;
- }
-
- return known;
-}
-
-static void lightrec_optimize_sll_sra(struct opcode *list, unsigned int offset)
-{
- struct opcode *prev, *prev2 = NULL, *curr = &list[offset];