mips 中求一個數的絕對值的指令:
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即可實作同樣的功能。
可見,上述機器指令設計的精巧。(了解各個指令的功能,寫出通用的功能的簡潔的代碼,真的要下一番功夫!)