It wouldn't surprise me if they used asm stubs for arithmetic just out of habit. Most of them in the late 90s would've learned in environments where that sort of thing mattered and would've trusted the compiler to manage it for them a lot less. The compiler might've handled it for them fine but they still did it out of habit, like how a lot of C developers use macros when inline functions would be just as or more suitable (guilty) for no particular reason. Sometimes developers just do things out of habit and being used to seeing it, but they might also have done it out of a desire to avoid any weird compiler behavior. ***was wild in the late 90s.
Bit shifts are still used by allocators or anything doing aligned arithmetic on pointers. I'd define that as pretty rare but mostly because most modern C code is hot garbage 99% of the time unless it came from Microsoft, Google, or Apple where all the old crusty nerds work who complain about how some functions are slower than others because they have one added instruction.
Haha yeah back then lots of stuff like this was common. The PSX ran on a 33Mhz CPU with 5KB of cache, 2MB of "system" RAM and 1MB of "video" RAM. To get a game like FFVII to run on that with those kinds of graphics required squeezing every ounce of performance via tight code optimizations. The PS2, which FFXI was coded on, and didn't have any Microsoft Visual Studio compiler for, had a 299Mhz 64-bit MIPS CPU, 16KB of instruction cache, 8KB of data cache, 32MB of "system" memory, 4MB of "video" memory and 2MB of "sound" memory.
Every time we dig into any of this games math we always stumble into where percentage numbers are really integers over 1024. Haste isn't 15% (0.15) but rather 150/1024. WS waist / belts are not +10% WS damage but really +100/1024 fTP each. That wouldn't make sense unless the WS's fTP values were themselves coded as X/1024, making it a simple addition that costs 1 cycle to do. These sorts of low level optimizations would be the bread and butter of console game developers.
Like I'd bet that Fimbulvetr's fTP at 3K isn't 9.9 but rather 10138, which would actually account for some of the discrepancies that pop up occasionally. 9.9 doesn't convert cleanly into an integer over 1024, instead turning into 10137
.6. 10137 turns into 9.8994, while 10138 becomes 9.9003, and even 10140 becomes 9.9023. The 60% STR is probably 614, which is 0.5996 or 615 at 0.6005.
For percentages this is
really important as divides are crazy expensive, like orders of magnitude more. While a multiply can take 2~4 cycles, a division takes 32 to 89 cycles. All multiplication by a percentage becomes a division but you can avoid that by turning it into a pure multiplication.
A: 450 STR
B: 60% STR WSC (0.60)
450 * 0.60 = 270 (this requires a DIV instruction)
Or with shifting
A 450 STR
B: 60 (shift two places)
450 * 60 = 27000, shift two places to 270.