从内存加载一侧的 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, y
是 or x, y, $zero
或 ori x, y, 0
的伪指令。或者 addu x, y, $zero
。随心所欲地实施它,或者让您的汇编程序为您完成。
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, y
是 or x, y, $zero
或 ori x, y, 0
的伪指令。或者 addu x, y, $zero
。随心所欲地实施它,或者让您的汇编程序为您完成。