管線化與危障
延遲分支(delayed branch)
假設你宣布「我要離開房間了——但首先,挨著我的那位,把話講完。」你把離開那個尷尬的停頓,變成了再多做一件有用事的機會。延遲分支就是把這個交易套到控制危障上:緊接分支之後的那條指令一律執行,無論分支跳不跳,於是那個本會浪費在等分支結果上的週期,改做了真實的工作。
機制如下。分支造成控制危障,是因為它的結果來不及在提取正確的下一條指令時被得知。一個老修法,在 MIPS 這類早期 RISC 設計中很突出,就是重新定義指令集,讓緊接分支之後的那個槽——分支延遲槽——無論分支跳不跳都一律執行。編譯器(或組合語言程式設計師)接著設法用一條無論如何都該跑的真正有用指令填那個槽:常是把分支之前一條不影響條件的指令搬下來填槽。若找不到有用的指令,那個槽就填一個 nop,那個週期就純粹浪費——不比單純停頓更差。
在管線又短又淺的時代,延遲分支是個巧妙又便宜的把戲,把管線的時序直接暴露給軟體。但它已經失寵,而誠實要求我們說出原因:它是個會漏的抽象,把特定的管線深度烙進了架構,所以一旦管線變深,單一延遲槽就成了錯的數目。現代處理器拋棄它,改用分支預測,後者完全在硬體裡藏起控制危障,不必拖累指令集。延遲分支主要作為歷史教訓、以及舊 ISA 裡的遺產包袱而存續。
在 MIPS 中,beq x1, x2, L; add x3, x4, x5——延遲槽裡的 add 無論到 L 的分支跳不跳都會跑。編譯器用一條反正都要跑的指令填那個槽,把分支本會停頓的週期變成有用的工作。
延遲分支一律執行它延遲槽裡的指令,討回一個浪費的週期——一個短管線的把戲,如今已被預測取代。
延遲分支是會漏的抽象的教科書範例:它把微架構的時序暴露給 ISA,結果隨管線加深而難堪地老化。RISC-V 刻意省去延遲槽,把控制危障交給硬體預測。
又稱
另見