超標量處理與X86

回答這個問題先看個wiki,Instruction-level parallelism,x86曾經因為ilp,指令級的並行大有被mips操死在山頂的趨勢,John Hennessy 和David Patterson 獲得了今年的圖靈獎,他們倆曾經寫了一本影響了業界很多年的書,m.douban.com/book/subje,也創建一間真正的公司實踐自己的理論,risc核心基礎並不在於指令集小,而在於所有指令定長,x86的指令集不是定長的,定長有什麼好處,好處太tmd大了,因為等長的指令集可以很方便塞到流水線上,而我們平時用的寄存器r0, r1其實只是一個名字而已,事實上運算器和寄存器都可以有很多備份,給程序員看到的cpu 只是programmer interface, 而具體的implementations,只要符合指令集的約定就行了,所以沒有因果關係的指令就可以並行執行,比如,我好久沒寫彙編了,彙編格式不一定對,而且各種彙編格式是那麼個意思就好了。

1. load [1234] r0 #從地址1234取一個字
2. load [4567] r1 #從地址4567取一個字
3. add r0 r1 #把r0中的內容加上r1的內容保存在r0中。
4. save [1234] r0 #把r0 中的字存回地址1234
5. move r2 r0 #把r2一個字移動到r0
6. move r3 r1 #把r3一個字移動到r1
7. multi r0 r1 #r0和r1相乘保存結果在r0
8. move r0 r2 #把r0的結果移動回r2
9. move r6 r0 #把r6的數據移動到r0
10. move r7 r1 #把r7 的數據移動到r0
11. add r0 r1 #把r0和r1相加存在r0
12 move r0 r6 #把r0的結果存回r6

我們假設這12條指令,在這些指令中,最耗時的指令是1,2和4,對於cpu來說,在內存存取數據就是io,io的意思就是慢的一逼。這時候cpu的控制器會對這些指令進行重排,我們假設cpu一個機器周期是能執行完一個指令的,事實上一般不能,我們就假設能把。

我們第一個機器周期要執行的指令是

round 1:

1. load [1234] r0 #從地址1234取一個字
5. move r2 r0 #把r2一個字移動到r0
6. move r3 r1 #把r3一個字移動到r1
9. move r6 r0 #把r6的數據移動到r0
10. move r7 r1 #把r7 的數據移動到r0

事實上load內存的指令要可能需要幾個到幾十個機器周期,這裡我們簡化一下,我們假設一個機器周期能夠執行完。也許你會納悶我的1,5, 9都寫了r0難道不會衝突嗎?不會的,這就是現代超標量處理器的特徵,不管運算器還是常規寄存器,都有很多備份,名字是一樣的,你寫的根本不是一個寄存器,或者叫register renaming。所以這些指令統統都是能夠並行的,在一個周期一次性執行完畢收穫結果,我之所以選擇這樣執行序列,只要是我分析了這些指令的因果關係,我把沒有因果關係的指令統統能夠並行,一個周期結束,我載入了1234地址的數據,然後分別把r0和r1都裝進來了。

round 2

2. load [4567] r1 #從地址4567取一個字
7. multi r0 r1 #r0和r1相乘保存結果在r0
11. add r0 r1 #把r0和r1相加存在r0

round 3

3. add r0 r1 #把r0中的內容加上r1的內容保存在r0中。
8. move r0 r2 #把r0的結果移動回r2
12 move r0 r6 #把r0的結果存回r6

round 4

save [1234] r0 #把r0 中的字存回地址1234

為啥定長指令很屌,因為我preload指令的控制器載入一堆指令後會分析你這些指令的因果關係,然後算出執行序,也就是哪些指令和哪些指令可以一起發射,如果是不定長的話,媽蛋我拿第8個指令還需要知道前面7個是什麼玩意,整個取指就是線性,非常噁心,而定長的可以一片一片載入進來分析因果關係,算下執行序,就開始幹了。評論區有說了intel解碼器其實是通過package往解碼器隊列里塞不定長指令的,而解碼器是多路的,所以這裡不會成為瓶頸.而且塞到流水線cisc處理的複雜度和不確定性指數級上升,因為指令數量,和一個指令的複雜程度和耦合程度,直接決定了你能不能在一個很小的空間做很多份運算單元,所以cisc指令天然難以超標量的。

事實上我上面的描述有點bug,我太簡化了,一個周期好多時候執行不完這些發射在一起的指令的,所以有些指令是要執行好多周期的,比如從內存load save,可能最差要幾十個周期。所以真正的流水線是好多層級並行的,而不是單條,每一個時鐘周期,可能每個指令只進展一點點。具體參考計算機體系結構的書。所以這種RISC指令集是如此的屌,當年John Hennessy 和David Patterson開了mips公司,整出來屌炸天的超標量處理器是把cisc的英特爾和AMD操的一愣一愣的,完全只有拚命嬌喘的份。但是,知恥而後勇,英特爾也不是甘心貢獻菊花的貨,他們憑藉pc已經在有很多軟體跑在他們的指令集上,然後巧妙的引進了一層抽象,使用risc的超標量ILP技術。

做法是我不改變x86變長指令集,我引入一個解碼器,所以cisc指令集發射之前先吃進解碼器,然後吐出來的就是定長的risc指令,好了吧,mips不屌了吧。所以憑藉出色的銷售能力和前期積累的客戶,反過來把John Hennessy 和David Patterson操的一愣一愣的,後來John Hennessy 和David Patterson都回了大學當老師,MIPS賣來賣去,最後真淪落的像個妓女一樣。英特爾和AMD屌大霸天。

所以什麼是過時的結構,上層穩定傻逼程序員喜歡,底層抽象實現高效率,這才是最牛逼的架構。這就是cs領域抽象的勝利。具體實現獨立於抽象。如果寫一本處理器史記,感覺John Hennessy 和David Patterson都是可以記入世家的人,雖然他們的王國覆滅了,但是在處理器結構歷史上,John Hennessy 和David Patterson絕壁是對現代處理器影響最深遠的人,他們從學術界,親自操刀殺入工業界,最後雖然失敗了,讓傻逼英特爾ARM撿了便宜,但是John Hennessy 和David Patterson的貢獻非常巨大,所以最後獲得圖靈獎也是理所應當。

而其實英特爾的研發實力也不是弱雞。別看龍芯那樣要飯的那點錢,英特爾每年研發經費可能比整個中國半導體投入都要多,所以英特爾很多技術細節還是領先的。架構這東西,只要程序員喜歡,介面傻逼,又跑的快,誰關心具體細節。

總體來說,兼容和先佔領市場才是王道,想當年江湖上的摩托羅拉去了天堂,施樂也去了天堂,mips雖然還在也等於沒了,sun sparc 也沒什麼存在感了,到了oracle垃圾森手裡只能死了,ibm那麼牛逼讓郭士納大象跳舞整的也是江河日下,最後ppc也只是年年出來裝逼了。當時很多處理器公司都去了天堂,最後結束戰國,歸於x86 arm。只是商業的勝利吧。


推薦閱讀:

TAG:ARM | 科技 | 處理器 |