I'm decompiling a PS2 game that was originally coded in C. To do this, I'm reading MIPS assembler and writing the corresponding C statements.
There's one reoccurring pattern that I haven't been able to figure out. Consider the following assembly:
li v1,2
sra v1,s1,1
bgez s1,*+16
nop
addiu v1,s1,1
sra v1,v1,1
daddu s1,v1,$0
The immediate value 2 is loaded into register v1, and is immediately overwritten by the one-bit-right-shifted value of register s1. Next, it checks if s1 was a positive number, and if it wasn't it loads s1 plus one into v1, and shifts it one bit to the right like before. In both cases, the result is then copied back to s1.
The same pattern has also appeared when shifting more bits to the right. Here, it shifts 8 bits to the right, and the immediate values are changed to match:
li v1,256
sra v1,s1,8
bgez s1,*+16
nop
addiu v1,s1,255
sra v1,v1,8
daddu s1,v1,$0
After some thinking, this reminded me of two's complement, so I thought it was a result of using the C standard library function abs() to get the absolute value. It made sense, because I always encountered this snippet before the value would be used as an array index, which can't be negative.
Now, I'm not so sure, because since then I've seen it used in situations where negative numbers are allowed and accounted for.
Does anyone have any idea of what this code is for?
If the li
isn't in the branch delay slot of an earlier branch, it's useless. You're right that its result is overwritten and thus has no effect.
After the li
, the code looks like it's doing signed division by 2
or 256
, rounding toward 0 like C x /= 256
instead of rounding toward -Inf
like x >>= 8
.
I wonder if it was for debugging or something, to find blocks in disassembly or in the debugger? Since you say the game came with debug symbols, it could perhaps be intentional for that reason.
In both cases the value loaded into v1
is the divisor, and it's doing v1 = s1 / v1
, but not actually using the value from v1.
Or perhaps some hand-written asm, or a clunky compiler that got its peephole optimization wrong and left in a useless instruction?