我面前有一个C代码,我必须翻译成MIPS汇编语言。
我不是在寻找直接的答案,但我希望有人纠正我对这个问题的思考方式。
我面前的C代码是:
x = ((++z)<=y);
我认为x,y和z分别存储在寄存器 $ 6,$ 7,$ 8
中问题是我无法使用运算符直接比较小于或等于。我只能使用以下比较操作数:bne,beq,ori,slt。
我解决问题的方式是这样的:
addi $8,$8,1 #this will increment z by 1 to have ++z
slt $1,$8,$7 #compares ++z to y if ++z is < than y, it will store 1 in $1
beq $8,$7,Label #compares if $8 = $7, if so the code jumps to Label
Label addi $t0,$0,1 #if ++z = y, stores 1 in $t0
ori $6,$t0,$1 #Or's the t0 and t1 and accordingly stores 0 or 1 in x
这是解决这个问题的正确方法吗?
答案 0 :(得分:0)
正如迈克尔所指出的那样,你应该在下面标记一行:
addi $8,$8,1
slt $1,$8,$7
beq $8,$7,Label
addi $t0,$0,1
Label ori $6,$t0,$1
有趣的是,您使用slt
但不使用seq
,为什么不呢?你可能会这样做:
addi $8,$8,1
slt $1,$8,$7
seq $t0,$8,$7
ori $6,$t0,$1
通过避免分支,程序可以稍快一些(假设案例多次发生。)
现在,如果我没记错的话,slt
和seq
将生成0或255.如果您正在编写C / C ++兼容语句,那么您需要使用0或1。一种方法是在ori
:
srl $6,$6,7
答案 1 :(得分:0)
像往常一样,询问编译器(例如 on the Godbolt compiler explorer)。另见How to remove "noise" from GCC/clang assembly output?
<=
单独(没有增量) 最好用 反向 slt
实现(做 b<a
与 a<=b
) 相反,然后 xori
翻转结果。
int booleanize_le(int y, int z){
return (z<=y);
}
# GCC5.4 -O3 -fno-delayed-branch
booleanize_le(int, int):
slt $2,$4,$5 # slt retval, y, z
xori $2,$2,0x1 # !retval, i.e. flip 0 <-> 1 since it was already boolean
j $31 # return
# (omitting the NOP in the branch-delay slot)
有趣的事实:用于 RISC-V 的 clang 做同样的事情,slt/xori,因为 RISC-V 就像 MIPS 一样,只提供 slt
用于比较到布尔值。 (因为您可以将任何关系(如 ==、<=、> 或其他任何关系)布尔化为最多 2 条指令的整数寄存器。)
但是在您想要递增并且使用 addi
的情况下,很明显 z 必须是有符号整数(否则您的代码会在从 0x7fffffffU 递增到 0x80000000U 时出错;使用 addiu
如果你想要定义明确的环绕)。
未定义行为的签名溢出的 C 规则基本上匹配 MIPS addi
的使用,这意味着编译器还将假定 ++z
不包装,并进行优化我们想要。他们和我们可以只使用原始的 z 值。 (z+1)<=y
与 z<y
相同,如果 z+1
不/不能换行。
int booleanize_inc_le_signed(int y, int z){
return ((++z)<=y);
}
booleanize_inc_le_signed(int, int):
slt $2,$5,$4 # z<y before incrementing
j $31
# increment optimized away in this function, but you'd do it with
addiu $5, $5, 1
如果 z
未签名,则无法进行优化,编译器只会递增,然后使用 2 指令 <=
slt/xori 序列的未签名版本:
int booleanize_inc_le_unsigned(unsigned int y, unsigned int z){
return ((++z)<=y);
}
booleanize_inc_le_unsigned(unsigned int, unsigned int):
addiu $5,$5,1 # z++
sltu $2,$4,$5 # y<z (unsigned)
xori $2,$2,0x1 # return !(y<z)
j $31
完全相等,a == b
xor $2,$4,$5 # find bit-differences
sltu $2,$2,1 # (a^b) < 1U
不等于,a != b
xor $2,$4,$5
sltu $2,$0,$2 # 0U < (a^b)
一个非零整数:a!=0
,即!!a
sltu $2,$0,$4 # 0U < a
显然可以派生任何其他人,或者只是询问编译器(使用 Godbolt 链接)。