What is the best way to handle errors in 68000 assembly language?

Viewed 150

I've been writing a lot of 68K assembly language, recently, and I've noticed a pattern, roughly the following:

do_something:
    movem.l d2-d5/a2-a3,-(sp)

    ...
    jsr     xxx
    tst.l   d0
    beq     open_error

    ...
    jsr     yyy
    tst.l   d0
    bmi     read_error

    ...
    move.l  #ERR_OKAY,d0
    bra     exit

open_error:
    move.l  #ERR_OPEN,d0
    bra     exit

read_error:
    move.l  #ERR_READ,d0

exit:
    movem.l (sp)+,d2-d5/a2-a3
    rts

That is, I have a lot of branches to instructions that just set a return code then branch to some clean-up instructions.

Is there some clever way to do this more efficiently, or am I just doing what needs to be done?

The only optimization I've been able to come up with is to save a branch on the most-common (no error) path:

    ...
    move.l  #ERR_OKAY,d0

exit:
    movem.l (sp)+,d2-d5/a2-a3
    rts

open_error:
    move.l  #ERR_OPEN,d0
    bra     exit

read_error:
    move.l  #ERR_READ,d0
    bra     exit
1 Answers

If you have to (or choose to) obey the ABI you are currently using (return error code in d0, and have registers d2-d7/a2-a6 preserved), there is not much you can do.

In some special cases you might micro-optimize certain operations, e.g., if ERR_OPEN happens to be -1 (and you can handle a modified d0), you could replace:

    tst.l   d0
    beq     open_error

...
open_error:
    move.l  #ERR_OPEN,d0
    bra     exit

By:

    subq.l  #1,d0
    bcs     exit    ; carry is only set if `d0` was 0 before

And if you want to optimize for speed instead of code-size, you could replace all

    bra     exit

by the corresponding

    movem.l (sp)+,d2-d5/a2-a3
    rts

If you do have more liberties on the interface, you could just say "my function may destroy registers d0-d5/a0-a3 and let the caller handle that (and all bra exit would become a single rts).

Also, especially if your function was called from just a single other function, which itself checks d0 directly after calling it, you could simply 'inline' your function and directly branch to the code which actually handles each error (but for bigger functions this will likely make just a negligible improvement at the cost of much poorer readability).

And if your main concern is the verbosity, I'd really suggest porting this to a higher level language (and only hand-optimize performance critical functions -- if you can actually implement them better than your compiler).

Related