Steinar H. Gunderson: Decompilation patterns, part 16: Tail reduplication
We're nearing the end soon, I promise. Here's one that I see all the time:
...
} else {
var_t0_5 = temp_a0_3 - 0x140;
var_a2_5 = 0xA0 - temp_a3_5;
goto block_45;
}
} else {
var_t0_5 = 0xA0 - temp_a0_3;
var_a2_5 = temp_a3_5 - 0x118;
block_45:
var_v0_3 = var_t0_5 + 0xA0;
var_v1_4 = var_a2_5 + 0x78;
}
So, eh, what's that goto doing there? What happened was that the compiler helpfully figured it could help with some tail deduplication; someone wrote the same code twice, and the compiler figured taking the cost of a branch was better than keeping it duplicated. (In a sense, it's the opposite of inlining. Ish.) In most cases, it's as simple as copying the block and then you can remove the label:
...
} else {
var_t0_5 = temp_a0_3 - 0x140;
var_a2_5 = 0xA0 - temp_a3_5;
var_v0_3 = var_t0_5 + 0xA0;
var_v1_4 = var_a2_5 + 0x78;
}
} else {
var_t0_5 = 0xA0 - temp_a0_3;
var_a2_5 = temp_a3_5 - 0x118;
var_v0_3 = var_t0_5 + 0xA0;
var_v1_4 = var_a2_5 + 0x78;
}
Sometimes, these are nested, with multiple tails goto-ing into each other, so in that case, you'll need to reduplicate multiple times. Make sure you actually come out on the correct side afterwards, though.
As an extra complication, the code is deduplicated not on the C statement level, but on
RTL instructions, so if you're calling functions with five parameters
of more (which requires pushing parameters onto the stack), m2c can
get really confused and start throwing M2C_ERROR() at you on the
receiving side because it's not clear at all where the parameters
would be coming from.