1. 程式人生 > >比較兩個數大小彙編解析

比較兩個數大小彙編解析

比較兩個數的大小, 用C語言寫很容易

int compare1(int x, int y)
{
    if (x > y)
    {
        return 1;
    } 
    else if (x == y) 
    {
        return 0;
    }
    else
    {
        return -1;
    }
}

用gcc生成powerPC ppu彙編指令, 用預設的-O選項

生成的彙編程式碼:

.compare1:
.LFB39:
	stdu 1,-80(1)
.LCFI3:
	std 31,72(1)
.LCFI4:
	mr 31,1
.LCFI5:
	mr 0,3
	mr 9,4
	stw 0,128(31)
	stw 9,136(31)
	lwz 9,128(31)
	lwz 0,136(31)
	cmpw 7,9,0
	ble 7,.L4
	li 0,1
	stw 0,48(31)
	b .L6
.L4:
	lwz 0,128(31)
	lwz 9,136(31)
	cmpw 7,0,9
	bne 7,.L7
	li 9,0
	stw 9,48(31)
	b .L6
.L7:
	li 0,-1
	stw 0,48(31)
.L6:
	lwz 9,48(31)
	extsw 0,9
	mr 3,0
	ld 11,0(1)
	ld 31,-8(11)
	mr 1,11
	blr
當然這麼多指令, 很多都不太清楚, 但是有點寫操作當中是有些壓棧了的,下面就用gcc 的-O3 選項就行優化
.compare1:
.LFB39:
	cmpw 7,3,4
	li 3,1
	ble 7,.L11
.L6:
	extsw 3,3
	blr
.L11:
	li 3,0
	beq 7,.L6
	li 3,-1
	b .L6
這樣得到的程式碼還是明顯少了很多, 但是我用if語句, 跳轉比較多, 大家都知道跳轉是比較耗時的

所以我就寫了另外的一種寫法:

int compare2(int x, int y)
{
    return x < y ? -1 : x == y ? 0 : 1;
}
上面的程式碼非常簡潔, 我們看一下gcc -O3彙編出來的程式碼, 預設-O選項的程式碼我就不列出了, 讀者可以自己試試以下
.compare2:
.LFB40:
	xor 0,3,4     // r3 = x, r4 = y
	cmpw 7,3,4
	srawi 11,0,31 // r0算術右移31位
	li 9,-1
	xor 3,11,0
	subf 3,3,11   // 這個指令的意思是說r3 = r11 - r3
	blt 7,.L15
	srwi 9,3,31  // r9 = r3 邏輯右移31位
.L15:
	extsw 3,9
	blr
我大概知道了編譯是怎麼做, 所以我自己根據編譯的做法, 自己也寫了一個:
        li      r9, -1           // r9 = -1
        r6, r3, r4
        cmpwi   cr7, r6, 0      // cal the diff
        blt     cr7, .Out        // jump to store -1
        li      r7, 0
        subf    r6, r6, r7      // cal 0 - diff, if the diff = 0, then r6 = 0, diff > 0, r6 < 0
        srwi    r9, r6,31       // mov the sign bit to r9, 
        .Out:
        mr      r3, r9          // r3 是儲存返回值的暫存器
        blr

以上就是比較兩個數的大小的C和彙編的分析, 但是用if語句的話跳轉比較多。

另外比較有兩個比較常用的功能就是求兩個數的最大值或者是最小值
// 寫法1
inline int max(int x, int y)
{
  if (x >= y)
  {
    return x;
  }
  return y;
}

inline int min(int x, int y)
{
  if (x < y)
  {
    return x;
  }
  return y;
}

// 寫法2
inline int max(int x, int y)
{
  return x >= y ? x : y;
}

inline int min(int x, int y)
{
  return x < y ? x : y;
}

// 寫法3
inline int max(int x, int y)
{
  int buf[] = {x, y};
  int shif = sizeof(int) * 8 - 1;                             // get the number for shif bits
  unsigned int sign = 0 ^ (((unsigned int)(x - y)) >> shif);  // if x > y, then sign = 0, then return x

  return buf[sign];
}

inline int min(int x, int y)
{
  int buf[] = { x, y };
  int shif = sizeof(int) * 8 - 1;                             // get the number for shif bits
  unsigned int sign = 1 ^ (((unsigned int)(x - y)) >> shif);  // if x < y, then sign = 0, then return x

  return buf[sign];
}
對於上面的三種方法, 大家可以反彙編一下, 看看那個生成的指令比較少, 也可以比較一下效能, 看看那個比較快, 可以把結果新增評論告訴我。
有誤請指出, 分享請標明出處, 謝謝!