暫存器重新命名

暫存器重新命名是計算機CPU的微體系結構中的一種技術，避免了機器指令或者微操作不必要的順序化執行，從而提高了處理器的指令級並行的能力。問題定義.計算機的CPU往往用暫存器來儲存指令的運算元與結果。x86指令集體系結構有8個整數暫存器，x86-64指令級體系結構有16個整數暫存器，許多RISC體系結構有32個整數暫存器，IA-64有128個整數暫存器. 在小型處理器，這些指令集體系結構暫存器直接對應於暫存器堆中的物理暫存器。不同的指令可以有不同的執行時間，特別是CISC指令集體系結構上更為明顯。例如，一條讀記憶體的指令的執行時間，足夠執行幾百條其它指令。因此，在允許多條指令並行執行的情況下，那些指令地址順序靠後的指令，比讀取記憶體指令更早完成，這就形成了指令執行順序不同於其在程式中的順序。這種亂序執行是高效能CPU提高運算速度的關鍵辦法之一。考慮下述程式碼片段在亂序執行CPU上的執行：第4、第5、第6條指令在功能上是不依賴於第1、第2、第3條指令的。但是處理器卻不能在第3條指令完成前去完成第4條指令，因為這可能會導致第3條指令把錯誤的資料寫入記憶體。透過改變一些暫存器的名字，可以使上例中指令並行執行所受的限制：現在，4、5、6號指令可以與1、2、3號指令並行執行，二者沒有依賴問題。這使得程式可以用更短時間完成。編譯器會盡力檢測出類似這樣的問題，並把不同的暫存器分配給不同的指令使用。但是，受指令集體系結構的限制，彙編程式可以使用的暫存器名字的數量是有限的。很多高效能CPU的實現—微體系結構—有很多物理暫存器，可以在處理器指令流水線執行時把這些指令集體系結構暫存器對映為不同的物理暫存器，從而在硬體級提供了額外的並行能力。資料衝突.如果多條指令使用了同一個儲存位置，這些指令如果不按程式地址順序執行可能會導致3種資料衝突:任何被讀或寫的儲存都是可以被重名。最常考慮的是通用整數暫存器與浮點暫存器。標誌暫存器、狀態暫存器甚至單個狀態位也是常見的重新命名的物件。記憶體位置也可以被重新命名，雖然這麼做不太常見。全美達的Crusoe處理器的gated store buffer是一種記憶體重新命名。如果程式沒有立即重用暫存器，它就不需要暫存器重新命名這種機制。例如IA-64指令集體系結構提供了128個通用暫存器，就是出於此考慮。但這種努力也遇到了困難：程式的程式碼尺寸增加，會導致指令快取記憶體的未命中增加，處理器執行停頓等待從低階儲存中讀入程式碼。這對運算效能的影響是致命的。體系結構暫存器與物理暫存器.編譯器或者彙編器生成的機器語言程式讀寫有限數量的指令集體系結構暫存器。例如，Alpha ISA使用32個64位寬整數暫存器，32個64位寬浮點暫存器。這些體系結構暫存器，是程式可以直接訪問的邏輯上的暫存器。如果程式設計師在偵錯程式中把這個程式暫停，可以觀察到這64個暫存器與一些狀態暫存器當前儲存的值。一款特定的處理器，實現了這種處理器體系結構。例如Alpha 21264有80個整數暫存器、72個浮點暫存器，作為處理器內物理實現的暫存器。也就是說，Alpha 21264處理器有80個物理存在的位置儲存整數運算的結果，72個位置存放浮點運算的結果。實際上，該款處理器有更多的物理存在的儲存位置，但與暫存器重名關係不大。下面介紹兩種暫存器重新命名方法，區別於為執行單元準備資料的電路。處理器把指令流使用的體系結構暫存器改為用若干位表示的tags所索引的物理暫存器。tag索引的暫存器堆給執行單元，源運算元的暫存器tags將傳送給物理暫存器堆，其中該tags所對應的物理暫存器的內容被髮送給該執行單元。保留站方法，存在多個小型相關的暫存器堆，通常是每個執行單元的輸入口都有一個物理暫存器堆。發射佇列中的每條指令的每個運算元對應著這個物理暫存器堆的一個儲存位置。當一條指令發射給某個執行單元，執行單元對應的暫存器堆的相應條目被讀出傳送給執行單元。重排緩衝區分為data-less與data-ful兩種。Willamette's ROB，其條目指向物理暫存器堆中的暫存器。此外還包括一些簙記資料。這是第一種亂序執行設計，由Andy Glew在Illinois用HaRRM完成。Intel P6的ROB，條目包含了資料。沒有單獨的物理暫存器堆。來自ROB的資料在指令提交後將複製到引退暫存器堆。細節：tag索引暫存器堆.這種重新命名模式用於MIPS R10000、Alpha 21264，以及AMD Athlon的浮點部分。在重新命名階段，每個被引用的體系結構暫存器。運算元暫存器被重新命名後的指令將被放入不同的發射佇列就緒。當指令執行完，其結果的tags將被公告，發射佇列中用這些公告的tags匹配那些未就緒的tags。一個匹配就意味著該運算元就緒了。重新命名檔案也去匹配這些公告的tags，從而標記哪些對應的物理暫存器是就緒的。當發射佇列中的某條指令的所有運算元是就緒的，這條指令就是發射就緒。在每個週期，發射佇列撿出一些就緒指令，傳送到功能單元。未就緒指令仍然留在發射佇列中。這種從發射佇列中無序刪除指令，使得發射佇列的電路實現佔用面積大、功耗高。被髮射的指令讀取源運算元的tag索引在物理暫存器堆中對應的物理暫存器，然後開始執行指令。指令執行結果寫入目的運算元的tag索引在物理暫存器堆對應的物理暫存器，同時公告給每個功能單元輸入端的旁路網路。寫暫存器的指令在引退時，把被寫的目的運算元暫存器使用過的上一個tag放入“空閒tag佇列”中，使得它可以被其它被解碼的指令重用。而該指令的目的運算元暫存器當前對應的tag仍然被佔用，因為後面可能還有指令需要讀取當前tag對應的物理暫存器的內容。一個異常與重排緩衝區中等待順序引退的指令的以前用過的tags。這種機制可以實現恢復任意時刻的重新命名狀態。細節：保留站.這種重新命名模式用於AMD K7與K8的整數暫存器設計。在重新命名階段，作為源運算元的體系結構暫存器在遠期暫存器堆與重新命名檔案中查詢對應的物理暫存器。如果沒有寫指令還沒有完成寫入該物理暫存器，則說明這個源運算元已經就緒。當這條指令被放入發射佇列，從遠期暫存器堆相應的物理暫存器讀出內容放入保留站中對應的條目。指令對目的暫存器的寫入，在重新命名檔案中的產生了一個新的、未就緒的tag。tag數通常是按照指令的順序分配，因此不需要空閒tag先進先出佇列。如同tag索引模式，發射佇列中的未就緒運算元等待匹配的tag公告。但不同於tag索引模式，tag的匹配導致對應的內容資料寫入發射佇列對應的保留站的條目。被髮射的指令從保留站讀取它的運算元，忽略掉那些剛剛公告過的運算元，然後開始執行。保留站暫存器堆通常很小，可能只有8個條目。指令執行結果寫入重排緩衝區，以及保留站，以及遠期暫存器堆。指令引退時，複製重排序緩衝區中的值到體系結構暫存器堆。體系結構暫存器堆用於從異常或者分支預測失敗時恢復。在指令引退時可以識別出異常與分支預測失敗，引起體系結構暫存器堆覆蓋掉遠期暫存器堆的內容，並標記重新命名檔案中所有暫存器都是就緒。通常，沒有辦法為一條處於解碼與引退之間的指令恢復遠期暫存器堆，因此通常沒有辦法在更早期為分支預測失敗做恢復工作。比較兩種模式.在兩種模式下，指令被順序送入發射佇列，但從發射佇列移出是亂序的。保留站具有更好的延遲效能。因為重新命名階段直接獲得暫存器內容，而不是獲得物理暫存器號，再用這個號去獲得內容值。保留站具有更好的從指令發射到執行的延遲效能。因為每個本地暫存器堆遠小於那種大型的用tag索引的中央暫存器堆。tag產生與異常處理也更為簡單。與tag索引的簡單的暫存器堆相比，保留站的物理暫存器堆的總規模更大，功耗更大，更為複雜。更糟糕的是，每個保留站的每個條目可以被每條結果匯流排寫入。例如，每個功能單元具有8條發射佇列條目的處理器，相比於tag索引的模式有9倍的旁路網路，結果直通需要更大的功耗與面積。保留站模式在4個位置儲存結果值。而tag索引模式只需要在物理暫存器堆儲存結果值。由於結果值來自功能單元，保留站模式必須公告結果到許多儲存位置，用掉了非常多的功耗、面積、時間。如果處理器具有非常精確的分支預測、非常關注執行延遲，保留站也是個很好的選擇。歷史.IBM System 360 Model 91是早期支援亂序執行的計算機。它使用Tomasulo演算法用到了暫存器重新命名。1990，POWER1是第一種使用了暫存器重新命名與亂序執行的微處理。最初的R10000設計既沒有發射佇列壓偏—最老的指令在佇列中一直沒有被髮射，直到解碼指令因為缺乏可重新命名的物理暫存器而完全停頓，而所有就緒指令都已經發射了。後來修改設計的R12000使用了部分可變優先順序編碼來克服此問題。早期亂序執行處理器並不區分重新命名與重排序緩衝區/物理暫存器堆的功能。因此，某些最早期的產品，如Sohi的RUU，Metaflow DCAF，組合了排程、重新命名，儲存在一個結構中。大多數現代處理器的重新命名使用了一個對映表，用邏輯暫存器號去索引。例如Intel P6微體系結構。遠期暫存器堆也是如此，並在此存放資料。但是，更早的處理器使用內容定址儲存技術實現重新命名，例如HPSM RAT，以及儲存器別名表。某種程度上，亂序執行的微體系結構的故事就是這些內容定址儲存如何逐步被清除。Intel P6微體系結構是Intel處理器中第一種亂序執行、暫存器重新命名。P6發展出了Pentium Pro、Pentium II、Pentium III、Pentium M、Core、Core 2等處理器系列。