从内存加载一侧的 C 三元条件运算符到 MIPS 程序集

C ternary conditional operator to MIPS assembly with one side loaded from memory

C语句

A= A? C[0] : B;

汇编指令这样写对吗? 假设数组 C 的 $t1=A, $t2=B, $s1=base 地址:

         beq   $t1, [=11=],  ELSE
         lw    $t1, 0($s1)
ELSE:    add   $t1, $t2, [=11=]

不,这似乎不正确,因为即使 $t1 != [=12=].

也会执行 add $t1, $t2, [=11=]

我希望这有效(未测试):

         beq   $t1, [=10=],  ELSE
         sll [=10=], [=10=], 0 # NOP : avoid the instruction after branch being executed
         lw    $t1, 0($s1)
         j END
         sll [=10=], [=10=], 0 # NOP : avoid the instruction after branch being executed
ELSE:    add   $t1, $t2, [=10=]
END:

此代码假设 C 的元素每个都是 4 字节长。

为 C 语句写一个 MIPS 段

x=5;  y=7; 

Land(x,y,z)   //  z=x &y    as procedure call

if (z>x) y=x+1

您可以避免无条件 j。不要将其构造为 if/else,而是始终执行 A=B(因为复制寄存器比跳转更便宜)然后选择性地执行加载。

在带有分支延迟槽的MIPS上,延迟槽实际上帮助我们:

# $t1=A, $t2=B, $s1=base
    beq   $t1, $zero,  noload
    move  $t1, $t2                  # branch delay: runs always

    lw    $t1, 0($s1)
noload:
    # A= A? C[0] : B;

MIPS 上没有 分支延迟槽(如默认配置中的 MARS 或 SPIM):

# MIPS without branch-delay slots
# $t1=A, $t2=B, $s1=base
    move  $t3, $t1              # tmp=A
    move  $t1, $t2              # A=B
    beq   $t3, $zero,  noload   # test the original A

    lw    $t1, 0($s1)
noload:
    # $t1 =   A= A ? C[0] : B;

如果我们可以破坏 B 并重新排列寄存器,我们可以保存一个没有分支延迟的 insn:

# MIPS without branch-delay slots
# $t1=A, $t2=B, $s1=base
    beq   $t1, $zero,  noload

    lw    $t2, 0($s1)
noload:
    # $t2 = A.   B is "dead": we no longer have it in a register

A move $t3, $t2 before BEQ可以将B保存在这个序列之前的另一个寄存器中。将变量放在不同的寄存器中可以节省指令,但会使跟踪事情变得更加困难。在一个循环中,如果你正在展开循环,你可以摆脱这个,因为代码的第二个副本可以重新洗牌以使寄存器恢复到循环顶部所需的方式。

move x, yor x, y, $zeroori x, y, 0 的伪指令。或者 addu x, y, $zero。随心所欲地实施它,或者让您的汇编程序为您完成。