Skip to content

Compiler Patterns and Gotchas

mattbruv edited this page Oct 27, 2020 · 4 revisions

Patterns

Modulo instruction generation

This pattern denotes a modulo operation: r3 % r4:

divwu r0, r3, r4
mullw r0, r0, r4
subf  r0, r0, r3

Narrowing to a u8

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.

Gotchas

Using DWARF argument types can break a matching function

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