-
Notifications
You must be signed in to change notification settings - Fork 26
Compiler Patterns and Gotchas
This pattern denotes a modulo operation: r3 % r4
:
divwu r0, r3, r4
mullw r0, r0, r4
subf r0, r0, r3
This pattern: clrlwi r3, r5, 0x18
is the result of the compiler converting a boolean value to an integer.
In this example, there is a function that returns an unsigned int in r3, and the r5 register either has 0 or 1.
In many places throughout the code, Heavy Iron uses 4 byte integers as return values for functions which return a boolean type, whereas in C++, the bool
keyword is equivalent to a single byte.
For example, the DWARF data defines the following info for this function:
void zEntPlayer_SNDSetVol(_tagePlayerSnd player_snd, float32 new_vol);
Consider the following line in this function:
if (sPlayerSnd[gCurrentPlayer][player_snd])
where sPlayerSnd
is an array of unsigned integers.
uint32 sPlayerSnd[47][3];
The type of the first argument player_snd
is an enum type: _tagePlayerSnd
.
When indexing the array with this enum, we can see the difference in instructions (red being matching):
-800811ac: 54 64 10 3a rlwinm r4,r3,2,0,29
+800811ac: 54 64 15 ba rlwinm r4,r3,2,22,29
After being stumped on this for quite some time, I realized that by changing the type of the first argument to int32
it matches:
void zEntPlayer_SNDSetVol(int32 player_snd, float32 new_vol)
Also note that attempting to cast the enum as an int to avoid changing the parameter type does not solve the problem:
if (sPlayerSnd[gCurrentPlayer][(int32) player_snd]) // doesn't work