Jump to content
IGNORED

IntyBASIC comparing against zero


DZ-Jay

Recommended Posts

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 by DZ-Jay
Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...