根据数字是正数还是负数修改寄存器
Modifying a register based on whether a number is positive or negative
我是汇编和 MIPS 的新手,想练习一下我的技能。我在网上找到了一些练习,并决定试一试。以下是我不太确定的一个:
Set the value stored in $t0 to -1, if $t0 is negative, and 0 if $t0 is positive.
我的方法是否正确?这可以使用算术移位更有效地完成吗?
这是我的代码:
main:
li $t0, -5
bgt $t0, [=10=], pos
# must be negative
li $t1, -1
# negative so make t0 = -1
srav $t0, $t0, $t1
# end of program
li $v0, 10
syscall
pos:
# positive so make t0 = 0
sra $t0, $t0, 31
# end of program
li $v0, 10
syscall
sra
by 31 广播符号位,创建 0(所有位清除)或 -1(所有位设置,在二进制补码系统如 MIPS 上为 -1)。
没有必要围绕它进行分支,并且您已经在分支的两侧进行了相同的转换。算术右移 reg_width - 1
(或在可能的 ISA 上更多 1)会将整个寄存器变成原始符号位的副本。原始 MSB 在 LSB 结束,其余位是该位的副本。
脚注 1: 它不在 MIPS 上。从寄存器中获取计数的 MIPS 移位仅使用低 5 位作为计数 (MIPS32 instruction-set reference manual),因此 -1 & 31 = 31
。当然,立即计数移位在 R 型指令编码中只有一个 5 位 shamt
字段。
所以非负数(正数和零)变成0
,负数变成-1
。
li
一个 -1
作为一个 srav
的计数而不是仅仅做 sra $t0, $t0, 31
是非常奇怪的。或者因为你显然只想将 $t0
、li $t0, 0
或 move $t0, $zer0
归零,如果你正在分支并且知道你想要那里的 0。或者没有伪指令,or $t0, $zero, $zero
)
这个技巧是众所周知的(在位黑客爱好者和编译器开发人员中),并用于许多位黑客,例如无分支abs
:Integer absolute value in MIPS?
- https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign 正是这个 0 / -1 的决定。 (但在 C 中,
>>
不能保证是 2 的补码算术右移,并且 int
可以有填充,因此称它为不可移植的)。
- https://catonmat.net/low-level-bit-hacks
(MIPS 有其他无分支条件指令,如 slt
/ sltu
,后来的 MIPS movn
和 movs
无分支条件移动指令。一些编译器使用它们对于绝对值:https://godbolt.org/z/eEzYKv3az)
我是汇编和 MIPS 的新手,想练习一下我的技能。我在网上找到了一些练习,并决定试一试。以下是我不太确定的一个:
Set the value stored in $t0 to -1, if $t0 is negative, and 0 if $t0 is positive.
我的方法是否正确?这可以使用算术移位更有效地完成吗?
这是我的代码:
main:
li $t0, -5
bgt $t0, [=10=], pos
# must be negative
li $t1, -1
# negative so make t0 = -1
srav $t0, $t0, $t1
# end of program
li $v0, 10
syscall
pos:
# positive so make t0 = 0
sra $t0, $t0, 31
# end of program
li $v0, 10
syscall
sra
by 31 广播符号位,创建 0(所有位清除)或 -1(所有位设置,在二进制补码系统如 MIPS 上为 -1)。
没有必要围绕它进行分支,并且您已经在分支的两侧进行了相同的转换。算术右移 reg_width - 1
(或在可能的 ISA 上更多 1)会将整个寄存器变成原始符号位的副本。原始 MSB 在 LSB 结束,其余位是该位的副本。
脚注 1: 它不在 MIPS 上。从寄存器中获取计数的 MIPS 移位仅使用低 5 位作为计数 (MIPS32 instruction-set reference manual),因此 -1 & 31 = 31
。当然,立即计数移位在 R 型指令编码中只有一个 5 位 shamt
字段。
所以非负数(正数和零)变成0
,负数变成-1
。
li
一个 -1
作为一个 srav
的计数而不是仅仅做 sra $t0, $t0, 31
是非常奇怪的。或者因为你显然只想将 $t0
、li $t0, 0
或 move $t0, $zer0
归零,如果你正在分支并且知道你想要那里的 0。或者没有伪指令,or $t0, $zero, $zero
)
这个技巧是众所周知的(在位黑客爱好者和编译器开发人员中),并用于许多位黑客,例如无分支abs
:Integer absolute value in MIPS?
- https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign 正是这个 0 / -1 的决定。 (但在 C 中,
>>
不能保证是 2 的补码算术右移,并且int
可以有填充,因此称它为不可移植的)。 - https://catonmat.net/low-level-bit-hacks
(MIPS 有其他无分支条件指令,如 slt
/ sltu
,后来的 MIPS movn
和 movs
无分支条件移动指令。一些编译器使用它们对于绝对值:https://godbolt.org/z/eEzYKv3az)