警告:新手回答。可能会让有经验的用户感到厌烦。
我不确定您是否误用了术语,或者您是否真的想使用predicated instructions1。
在后一种情况下,使用ARM v6 predication 作为研究案例(并继承您关于寄存器使用的前提),程序集很简单
;r1 = A r2 = B r3 = C r4 = D r5 = E
;
;A, B unsigned | ;A, B signed
|
cmp r1, r2 | cmp r1, r2
|
movhi r3, r1 | movgt r3, r1
movhi r4, r2 | movgt r4, r2
movhi r5, #0 | movgt r5, #0
|
movls r3, r2 | movle r3, r2
这里我根据所涉及变量的符号给出了两个版本。
movhi 表示如果更高则移动。 movls 表示如果小于或相同则移动。
movgt 表示如果大于则移动。 movle 表示如果小于或等于则移动。
它们意味着相同的算术比较,只是后者对有符号数使用了正确的标志。
我对指令进行了分组,因此很容易识别 if-then 和 else 块。
请注意同一块中的指令如何具有相同的后缀(例如 hi 和 ls)。
真正使这段代码成为 if-then-else 构造而不是其他东西的原因是条件 hi-ls 和 gt-le 是 互斥(两者中只有一个为真)。
所以只能执行一个指令块。
使用非互斥条件会产生多个 if-then-else 语句。
如果您误用了术语并且您实际上只想实现一个条件语句(或选择),即一个if-then-else,那么通常的方法是一个 条件分支2 如 Nutan 所示。
这里有一个更易读的版本:
cmp r1, r2
bls _A_less_same_B
mov r3, r1
mov r4, r2
eor r5, r5, r5
b _end_if
_A_less_same_B:
mov r3, r2
_end_if:
将此代码转换为使用有符号整数的负担由您决定。
以冒号 (:) 结尾的花哨的词称为标签,它们是在代码(和数据)中命名点的有用方法3。
将其视为灵活的行号。
b 表示分支,一旦执行,下一条指令将从指定为操作数的标签(地址)中获取(例如来自_end_if)。
bls 是只是一个谓词b(bls 表示分支如果小于或相同),通常称为条件分支。
条件分支就像普通分支一样,但如果指定的条件不满足,它们可以被“忽略”。
如果条件满足并且 CPU 执行跳转,则称条件跳转被执行,从而从指定为操作数的标签中获取下一条指令。
如果条件不满足并且CPU从分支之后指令继续执行(程序流程通过 em>)。
“条件”通常表示设置和清除标志。
一些指令,如cmp,设置和清除这些标志。
其他指令,如 bls 使用这些标志。
标志保存在专用寄存器中(ARM 中为ps),但有些架构,尤其是 MIPS,没有标志寄存器。
您可以用手指模拟程序流程。比如A > B的流程如下:
[Start Here]
¯¯¯¯+¯¯¯¯¯
cmp r1, r2 |
bls _A_less_same_B + [Branch not taken, fall through]
|
mov r3, r1 |
mov r4, r2 |
eor r5, r5, r5 |
|
b _end_if +--[Branch always taken]----+
|
_A_less_same_B: |
mov r3, r2 |
|
_end_if: +--[Land here]--------------+
|
V
弯曲的意思是“跳过”我们想要跳过的代码(在本例中为 else)。
我不认识你问题的汇编风格,所以我无法帮助编写具体示例。
无论如何我都不会这样做,因为我觉得这个一般性的解释就足够了,并希望我这样缺乏努力会促使你尝试自己解决这个练习。
这是学习道路上的必经步骤。
1 获取、解码(可能也发出)但仅在设置或清除特定标志时执行的指令。
2 请注意,如果可能,最好避免使用条件分支。根据目标微架构,可能会有更优化的方法来实现相同的结果。这只是值得注意,现在不要理会它。
3 实际上将成为地址的偏移量。