Steinar H. Gunderson: Decompilation patterns, part 14: Strength increase
Let's look at the entire loop from yesterday:
u16 spE10;
u16 *var_v0_2;
...
var_t1_2 = 0x7F;
var_v0_2 = &spE10 + 0xFE;
do {
*var_v0_2 = 0;
var_t1_2 -= 1;
var_v0_2 -= 2;
} while (var_t1_2 >= 0);
What's going with the pointer arithmetic here? Why is it indexing out-of-bounds?
The first thing to notice is that m2c doesn't really take into account that arithmetic on pointers in C is multiplied by the size of the element. And obviously, spE10 is the root of some array. So corrected, this reads:
u16 spE10[0x80]; // Modified.
u16 *var_v0_2;
...
var_t1_2 = 0x7F;
var_v0_2 = spE10 + 0x7F; // Modified.
do {
*var_v0_2 = 0;
var_t1_2 -= 1;
var_v0_2 -= 1; // Modified.
} while (var_t1_2 >= 0);
We saw yesterday how we should rewrite the iteration back to a for loop, but also, most likely, the pointer arithmetic here came from strength reduction; the compiler took a multiplication operation and rewrote it to a βweakerβ operation (subtraction) since that's typically cheaper, at the cost of making the values dependent, an easy trade. So we can rewrite it back into multiplication:
var_t1_2 = 0x7F;
do {
var_v0_2 = spE10 + var_t1_2;
*var_v0_2 = 0;
var_t1_2 -= 1;
} while (var_t1_2 >= 0);
and now it's easy to see that the loop should read:
for (i = 0; i < 0x80; ++i) {
spE10[i] = 0;
}
and then, of course, the array should get a better name.
Sometimes the loop counter will go backwards while the pointer will go forwards, which is also completely normal, especially if there's side effects. The compiler will reverse one but not the other.