abs $d, $s # $d = $s>=0 ? $s : -($s);
这条指令是mips编译器中的宏指令,其展开后的机器指令如下:
宏指令:abs $d, $s # $d = $s>=0 ? $s : -($s);
机器指令:
=> sra $at, $s, 31 #assume it's mips32, $at = $s<0 ? -1 : 0;
xor $d, $s, $at # $d= $s xor $at ;
subu $d, $d, $at # $d = $d - $at;
分析:该指令为求一个整数的的绝对值,若该整数是负数,其绝对值为其相反数;否则,为其本身。
对一个整数的二进制补码求其相反数的补码的方法是:对其各位(包括符号位)取反,末位加1;
对于异或 xor有这样的特性:设 Y 为一位二进制位(bit), 则有
Y xor 0 = Y;
Y xor 1 = ~Y; //~Y 为 Y 的非,即对 Y 取反
Y xor Y = 0;
对一个32位整数 Z 的各位取反,即可通过使其异或(xor)一个32位全为 1的整数即 mips32中的-1的补码;
Z xor -1 = Z xor (11111111 11111111 11111111 11111111)= ~Z;
Z的相反数的补码: -Z = ~Z + 1 = (Z xor -1) + 1;
其实求一个整数的相反数的补码的另一种快捷的机器实现方法是:
对该整数的各位从右往左(从低位到高位)扫描, 除最右边的零和第一个出现的1保持不变,其余的各位依次取反。
下面分析关于宏指令 : abs $d, $s 机器指令的实现:
第一条机器指令: sra $at, $s, 31;
通过算术右移指令sra,将 $s 右移 31 位,算术右移时带符号扩展的,其结果是$at寄存器中32位的每一位都和$s的符号位相同,即$at的32位要么全为1(if $s<0), 要么全为0 (if $s >=0);
第二条机器指令: xor $d, $s, $at;
有异或的特性可知,当$s<0时, $at=-1; $d = ~$s; 否则, $at=0, $d=$s;
第三条指令: subu $d, $d, $at;
当$s < 0 时 $at=-1,相当于对于负数求其相反数的加1操作;
当$s >= 0时, $at=0 , $d 保持不变。
可见,以上三条指令既能实现求一个负整数的绝对值,也能实现求一个正整数的的绝对值,而且其机器指令是一致。
note:对于mips64中abs 只须将 31 变为63即可实现同样的功能。
可见,上述机器指令设计的精巧。(了解各个指令的功能,写出通用的功能的简洁的代码,真的要下一番功夫!)