首页 > 解决方案 > 处理 68000 汇编语言中的错误的最佳方法是什么?

问题描述

我最近一直在写很多 68K 的汇编语言,我注意到一个模式,大致如下:

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

也就是说,我有很多分支到只设置返回码然后分支到一些清理指令的指令。

有没有一些聪明的方法可以更有效地做到这一点,或者我只是在做需要做的事情?

我能想到的唯一优化是在最常见(无错误)路径上保存一个分支:

    ...
    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

标签: assembly68000

解决方案


如果您必须(或选择)遵守您当前使用的 ABI(在 中返回错误代码d0,并保留寄存器d2-d7/a2-a6),那么您无能为力。

在某些特殊情况下,您可能会对某些操作进行微优化,例如,如果ERR_OPEN碰巧-1(并且您可以处理修改后的d0),您可以替换:

    tst.l   d0
    beq     open_error

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

经过:

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

如果你想优化速度而不是代码大小,你可以替换所有

    bra     exit

由相应的

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

如果你在接口上有更多的自由,你可以说“我的函数可能会破坏寄存器d0-d5/a0-a3并让调用者处理它(所有这些bra exit都会变成一个rts)。

此外,特别是如果您的函数仅从单个其他函数调用,该函数本身d0在调用它后直接检查,您可以简单地“内联”您的函数并直接分支到实际处理每个错误的代码(但对于更大的函数,这可能会以更差的可读性为代价做出微不足道的改进)。

如果您主要关心的是冗长,我真的建议将其移植到更高级别的语言(并且仅手动优化性能关键功能 - 如果您实际上可以比您的编译器更好地实现它们)。


推荐阅读