余曉江 羅欣
(西華師范大學 四川省南充市 637000)
2014年加州大學伯克利分校(University of Cal-I fornia at Berkeley, 以下簡稱 UCB)的研究人員Krste Asa-novic、Andrew Waterman、Yunsup Lee 設 計 并 發 布 了RISC-V 指 令 集 架 構[1]。RISC-V 基于精簡指令集計算(RISC)原理構建的開放RISC-V 指令集架構(RISC-V instruction set architecture 簡稱RISC-V ISA)[2]。RISC-V 指令集架構采用的是精簡指令集,同時有著非常良好的可擴展性,并且RISC-V 生態系統迅速的發展,促進了這種新型的RISC-V ISA 在各大處理器設計中得到應用。RISC-V 開源自由協議受到個人、科研團隊以及商業公司的青睞,各大公司紛紛加入RISC-V 聯盟,如蜂鳥、中科院計算所、英偉達、華為、谷歌、阿里巴巴等等[3][4][5]。
大多數早期超標量處理器[6]都是順序執行,RISC-V 處理器設計初期均采用單發射順序執行的流水線工藝[7]。
流水線技術之所以能提高性能,其本質是利用了時間上的并行性,讓原本應該先后執行的指令在時間上一定程度的并行起來,然而這樣也會帶來一些沖突和矛盾,進而可能引發錯誤,這種情況就被稱為流水線冒險。數據冒險是流水線冒險中最常見的一種,數據冒險是指令所需要的數據矛盾,如果一條指令需要某個數據而該數據正在被之前的指令操作,那這條指令就無法執行,就導致了數據冒險。針對流水線冒險其中一種解決方案是使用流水線停頓來延遲下一條指令。從而避免流水線冒險帶來的程序執行錯誤。
在傳統處理器設計中,流水線借助于一個執行單元隊列,讓暫未滿足各類資源的指令在此等待一定周期,或者采用流水線停頓技術(stall)讓整個流水線上相關的資源均陷于一定周期的等待狀態,直至問題解除[8][9]。等待的周期主要取決于兩個因素:前驅指令的執行開銷、以及當前指令所需硬件資源。而這些恰恰是編譯器靜態指令調度策略中的核心影響因素。因此,如果借助于靜態調度策略,為當前指令去權衡計算它需要等待的時間,適當調整指令的位置,在指令排布過程中拉長它和前驅的距離,我們就能保證它在正確的時間完成譯碼以及到達執行功能部件。
綜上所述,雖然成熟的處理器大部分使用動態調度來避免流水線冒險,但是基于RISC-V 指令集的處理器目前尚未成熟,都處在研究設計階段,所以使用RISC-V ISA 的處理器研發時,為縮短研發周期和研發成本。靜態調度是解決流水線冒險最有效的方法。本文提出一種面向RISC-V 處理器的指令調度技術——指令延遲調度技術,用于向RISC-V 處理器研究提供一種實用、有效的軟件解決方案。在RISC-V 處理器研發處于萌芽期的大背景下,編譯器延遲調度技術是一種實用、有效的途徑,使編譯器的研發不受硬件時序控制設計與驗證的約束,直接在具有基本執行功能的FPGA 或者軟件模擬器上進行研發,從而使軟件研發與處理器研發同步前行。
本文提出一種基于RISC-V 處理器的編譯器調度技術——指令延遲調度技術,它通過一個保守的資源開銷評估模型對當前指令的正確發射時間進行評估。通過指令的靜態調度對流水線上的指令到達執行部件的時刻進行干涉,從而有效避免由于指令提前到達執行部件所引發的流水線冒險。指令延遲調度技術是一種實用、有效的軟件解決方案,使核心軟件可以與處理器設計同期同步開展。優化后的表調度分析算法能夠準確地記錄每一個基本塊中指令流中需要插入延遲指令的位置和數量。通過本地延遲指令生成算法,生成占用拍數但又不做任何操作的NOP 指令[10]。指令延遲調度技術根據表調度算法計算出的數據對表調度之后的指令流進行再次調度,使每一拍都有指令發射,從而避免流水線冒險帶來的執行錯誤。經過指令延遲調度的程序在處理器上不需要進行動態調度即可正確高效的執行。為了不影響編譯器的功能模塊和方便進行對比測試。將指令延遲調度封裝在編譯選項-fsched-delay 中,在編譯時,通過使用編譯選項-fsched-delay 來控制編譯器使用指令延遲調度技術。
(1)表調度分析算法。要對表調度后的RTL 進行指令延遲調度,需要優化表調度的分析算法。通過指令調度數據流DUMP 算法的輸出數據流,直觀的顯示了指令信息。RTL 中間表示階段所有指令是由一個結構體存儲即INSN。要對指令進行延遲調度,首先需要了解表調度的調度原理,如圖1 所示。指令INSN 已提交到計劃中,從“Ready”列表移動到“Scheduled”列表。當發生這種情況時,“Pending”列表中的INSN 滿足其依賴關系并移動到“Ready”列表或“Queued”集合,具體取決于是否已經有足夠的時間使其準備就緒;隨著時間的推移,準備就緒的INSN 從“Queued”移動到“Ready”列表;“Pending”列表(P)是未安排的INSN_FORW_DEPS 中的INSN,即準備好,排隊和掛起的INSN?!癚ueued”集合(Q)由變量insn_queue 實現。“Ready”列表(R)由變量ready 和n_ready 實現。“Scheduled”列表(S)是由此傳遞構建的新INSN 鏈。當選擇最好的調度INSN 時,轉換(R-> S)在schedule_block 的調度循環中實現。當INSN 從就緒列表移動到調度列表時,轉換(P-> R 和P-> Q)在schedule_insn 中實現。隨著時間的推移或引入停頓,轉換(Q-> R)在queue_to_insn 中實現。為了減小對編譯器的影響,對表調度分析算法進行優化,計算出延遲調度的相關信息并記錄保存,傳遞到指令延遲調度中。

圖1:編譯器指令調度數據流對比

圖2:編譯器編譯出的匯編碼對比

圖3:指令延遲調度技術優化后的編譯器與官方編譯器編譯SPEC2017 Benchmarks 的耗時對比圖
(2)延遲指令生成算法。由于指令流里的指令是由源碼翻譯過來的,從一開始轉換到RTL 時,就生成了雙向鏈表,經過表調度時,指令隊列進行指令調度后依然是一個雙向鏈表。那么在進行延遲調度時,要在雙向鏈表中插入延遲指令NOP。就要對雙向鏈表進行維護。每一條指令都有一個前驅和后繼,當前指令、前驅指令和后繼指令都是相互依賴的。當insn 需要延遲時,首先就要斷開雙向鏈表prev 和insn,將nop 指令放在prev 和insn 之間。把insn的前驅設置為nop,prev 的后繼修改為nop,并把nop 的前驅設置為prev,后繼為insn。根據機器模型獲取nop 指令的RTL 結構,設置nop 指令所屬的基本塊為insn 的基本塊。
(3)指令延遲調度算法。指令延遲調度算法根據表調度分析算法記錄并傳遞來的數據使用延遲指令生成算法在需要延遲的指令前插入足夠的空操作指令NOP 來占用無指令的拍數。為盡量避免對編譯器其他功能的影響,我們選擇在編譯器表調度完成之后,RTL 翻譯成匯編碼之前,進行指令延遲調度。首先判斷是否在編譯時使用了-fsched-delay 編譯選項,以下所有操作都是在使用-fscheddelay編譯選項的情況下實現。接著判斷當前是否屬于最后一次調度,即前面說的重載后調度(after reload)。當兩個條件同時滿足時,對當前基本快中已經調度好的指令流進行遍歷,尋找需要延遲的指令。當遍歷到INSN 的編號INSN_UID 為表調度分析算法傳來數據中的INSN_UID 時,即這條INSN 需要在發射前插入NOP 延遲,根據數據中記錄的延遲拍數循環插入NOP 指令。調用延遲指令生成算法進行指令生成。最后對指令在調度過程中的LUID 進行維護,以保證調度過程中每一條指令在調度過程中都有唯一的識別ID。
(1)指令延遲調度技術是通過靜態調度中使用停頓避免流水線冒險帶來的執行錯誤,經過應用該技術的RISC-V GCC 編譯器編譯程序時,使用-fsched-verbose=n 編譯選項可輸出指令調度過程,能夠直觀的看到指令延遲調度的結果,如圖1 所示。
另一方面,指令延遲調度技術在靜態調度中完成了空拍指令的填充,生成的匯編碼中會明確顯示NOP 在相應的位置,如圖2 所示。
經過如圖1 和圖2 的試驗驗證,指令延遲調度技術能夠在指定拍數處填充NOP 指令,并且正確的生成對應的匯編碼,來延遲下一條指令。編譯器的性能是在對編譯器改進后的綜合評估,主要通過編譯時間來進行比較,使SPEC2017 作為測試用例,測試了使用指令延遲調度技術的RISC-V GCC 編譯器編譯時間。實驗編譯器運行環境為:32 核Intel Xeon E7-4809 主頻2.00GHz 的CPU,64 位ubuntu14.04 系統,一級指令/數據Cache 各32K,二級Cache256K。實驗結果如圖3 所示。
圖3 中分別使用指令延遲調度技術優化后的RISC-V GCC 編譯器和官方RISC-V GCC 編譯器在相同條件下編譯SPEC2017 中使用C 語言編寫的Benchmarks,由圖可見,優化后的編譯器和原編譯器編譯相同Benchmarks 耗時相差不超過1s,實驗證明,指令延遲調度技術對RISC-V GCC 的性能影響很小,達到了設計初期最小化編譯器影響的要求。為了驗證優化后的編譯器編譯出的程序可以正確的在RISC-V 處理器上運行,以stream 作為測試程序,分別在超導模擬器和火苗原型系統上測試通過,能夠正確的執行完成。超導v1 版本模擬器:位模式32 位,譯指隊列大小151,一級Cache128byte,二級Cache32K,寄存器個數16?;鹈缭拖到y:4 核Labeled RISC-V 系統,100 MHz rocket 核心, 16KB L1 Icache, 16KB L1 Dcache, 2MB L2 cache,16GB DDR4 SO-DIMMs,Linux 4.6.2 內核。
指令調度在編譯器中是非常關鍵的環節,指令延遲調度技術是RISC-V GCC 編譯器在RTL 一級的指令調度優化,在RISC-V 處理器研發過程中作為編譯器輔助有著重要作用,尤其是在超導計算機研究中作為編譯器優化研究意義重大。本文通過對RISC-V GCC 編譯器的改進和優化,為進一步研究和優化RSIC-V GCC 奠定了編譯器基礎,更為快速研究新型的RISC-V 指令集架構處理器起著重要的推動作用。