+DZ-Jay Posted August 20, 2022 Share Posted August 20, 2022 (edited) In an IntyBASIC program, I have a moving object with two velocity vectors represented by signed 16-bit variables, "#VelocityX" and "#VelocityY". I want to change the object state to "idle" when both values are zero, indicating that the object stopped moving. Of course, the simplest way is to do something like: If ((#VelocityX = 0) + (#VelocityY = 0)) Then State = ST_IDLE End If However, that generates some horrendously expensive code for such a simple operation -- and it is rather a common case that needs to be perform on each frame, for each object. Short-circuiting with two branches is slightly better, but still not so great: If (#VelocityX = 0) Then If (#VelocityY = 0) Then State = ST_IDLE End If End If In assembly, I would optimize this by adding the values together, treating them as unsigned, and testing the Zero and Carry bits. That is, when you add the two values together, they will result in zero in only two circumstances: Both values are zero (0 + 0) Both have the same absolute value, with opposite signs (+n + -n) We only care about the first case, so to disambiguate we can test the "Carry" flag, which is set when the values subtract each other to zero. It would look something like this: MVI var_&VELOCITYX, R0 ; \_ Add values together ADD var_&VELOCITYY, R0 ; / BNZE NOT_ZERO ; Zero = Both values are zero (0 + 0), or the same with opposite sign (+n + -n) BC NOT_ZERO ; Carry = Disambiguates when zero is the result of adding same value with opposite signs. ZERO: MVII #ST_IDLE, R0 ; \_ Update state MVO R0, var_STATE ; / NOT_ZERO: ; Continue ... This could work in IntyBASIC, but it seems that the compiler sometimes decides to compare the results of the addition against zero -- which changes my flags yet again. For example, the following IntyBASIC code: Unsigned #VelocityX, #VelocityY If ((#VelocityX + #VelocityY) <= 0) Then State = ST_IDLE End If Signed #VelocityX, #VelocityY Compiles into the following assembly code (I've annotated it, for clarity): MVI var_&VELOCITYX,R0 ; \_ Added values together ADD var_&VELOCITYY,R0 ; / CMPI #0, R0 ; Discard the flags and compare against zero! BEQ $+4 ; \_ Operate on the results of the CMPI, not the ADD BC T121 ; / MVII #ST_IDLE, R0 ; \_ MVO R0, var_STATE ; / T121: I am not sure why IntyBASIC adds the "CMPI" comparison to zero instead of just testing the output of the "ADD" operation itself. I've noticed this occasionally, but I am not sure what induces the compiler to use "CMPI #0" instead of the most immediate result of an arithmetic operation (like in this case), or even "TSTR" (which is cheaper). Does anybody know why this is? Also, does anybody have a better pattern to do this sort of thing than the above approach? -dZ. Edited August 20, 2022 by DZ-Jay Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.