余曉江 羅欣
(西華師范大學(xué) 四川省南充市 637000)
2014年加州大學(xué)伯克利分校(University of Cal-I fornia at Berkeley, 以下簡稱 UCB)的研究人員Krste Asa-novic、Andrew Waterman、Yunsup Lee 設(shè) 計 并 發(fā) 布 了RISC-V 指 令 集 架 構(gòu)[1]。RISC-V 基于精簡指令集計算(RISC)原理構(gòu)建的開放RISC-V 指令集架構(gòu)(RISC-V instruction set architecture 簡稱RISC-V ISA)[2]。RISC-V 指令集架構(gòu)采用的是精簡指令集,同時有著非常良好的可擴(kuò)展性,并且RISC-V 生態(tài)系統(tǒng)迅速的發(fā)展,促進(jìn)了這種新型的RISC-V ISA 在各大處理器設(shè)計中得到應(yīng)用。RISC-V 開源自由協(xié)議受到個人、科研團(tuán)隊(duì)以及商業(yè)公司的青睞,各大公司紛紛加入RISC-V 聯(lián)盟,如蜂鳥、中科院計算所、英偉達(dá)、華為、谷歌、阿里巴巴等等[3][4][5]。
大多數(shù)早期超標(biāo)量處理器[6]都是順序執(zhí)行,RISC-V 處理器設(shè)計初期均采用單發(fā)射順序執(zhí)行的流水線工藝[7]。
流水線技術(shù)之所以能提高性能,其本質(zhì)是利用了時間上的并行性,讓原本應(yīng)該先后執(zhí)行的指令在時間上一定程度的并行起來,然而這樣也會帶來一些沖突和矛盾,進(jìn)而可能引發(fā)錯誤,這種情況就被稱為流水線冒險。數(shù)據(jù)冒險是流水線冒險中最常見的一種,數(shù)據(jù)冒險是指令所需要的數(shù)據(jù)矛盾,如果一條指令需要某個數(shù)據(jù)而該數(shù)據(jù)正在被之前的指令操作,那這條指令就無法執(zhí)行,就導(dǎo)致了數(shù)據(jù)冒險。針對流水線冒險其中一種解決方案是使用流水線停頓來延遲下一條指令。從而避免流水線冒險帶來的程序執(zhí)行錯誤。
在傳統(tǒng)處理器設(shè)計中,流水線借助于一個執(zhí)行單元隊(duì)列,讓暫未滿足各類資源的指令在此等待一定周期,或者采用流水線停頓技術(shù)(stall)讓整個流水線上相關(guān)的資源均陷于一定周期的等待狀態(tài),直至問題解除[8][9]。等待的周期主要取決于兩個因素:前驅(qū)指令的執(zhí)行開銷、以及當(dāng)前指令所需硬件資源。而這些恰恰是編譯器靜態(tài)指令調(diào)度策略中的核心影響因素。因此,如果借助于靜態(tài)調(diào)度策略,為當(dāng)前指令去權(quán)衡計算它需要等待的時間,適當(dāng)調(diào)整指令的位置,在指令排布過程中拉長它和前驅(qū)的距離,我們就能保證它在正確的時間完成譯碼以及到達(dá)執(zhí)行功能部件。
綜上所述,雖然成熟的處理器大部分使用動態(tài)調(diào)度來避免流水線冒險,但是基于RISC-V 指令集的處理器目前尚未成熟,都處在研究設(shè)計階段,所以使用RISC-V ISA 的處理器研發(fā)時,為縮短研發(fā)周期和研發(fā)成本。靜態(tài)調(diào)度是解決流水線冒險最有效的方法。本文提出一種面向RISC-V 處理器的指令調(diào)度技術(shù)——指令延遲調(diào)度技術(shù),用于向RISC-V 處理器研究提供一種實(shí)用、有效的軟件解決方案。在RISC-V 處理器研發(fā)處于萌芽期的大背景下,編譯器延遲調(diào)度技術(shù)是一種實(shí)用、有效的途徑,使編譯器的研發(fā)不受硬件時序控制設(shè)計與驗(yàn)證的約束,直接在具有基本執(zhí)行功能的FPGA 或者軟件模擬器上進(jìn)行研發(fā),從而使軟件研發(fā)與處理器研發(fā)同步前行。
本文提出一種基于RISC-V 處理器的編譯器調(diào)度技術(shù)——指令延遲調(diào)度技術(shù),它通過一個保守的資源開銷評估模型對當(dāng)前指令的正確發(fā)射時間進(jìn)行評估。通過指令的靜態(tài)調(diào)度對流水線上的指令到達(dá)執(zhí)行部件的時刻進(jìn)行干涉,從而有效避免由于指令提前到達(dá)執(zhí)行部件所引發(fā)的流水線冒險。指令延遲調(diào)度技術(shù)是一種實(shí)用、有效的軟件解決方案,使核心軟件可以與處理器設(shè)計同期同步開展。優(yōu)化后的表調(diào)度分析算法能夠準(zhǔn)確地記錄每一個基本塊中指令流中需要插入延遲指令的位置和數(shù)量。通過本地延遲指令生成算法,生成占用拍數(shù)但又不做任何操作的NOP 指令[10]。指令延遲調(diào)度技術(shù)根據(jù)表調(diào)度算法計算出的數(shù)據(jù)對表調(diào)度之后的指令流進(jìn)行再次調(diào)度,使每一拍都有指令發(fā)射,從而避免流水線冒險帶來的執(zhí)行錯誤。經(jīng)過指令延遲調(diào)度的程序在處理器上不需要進(jìn)行動態(tài)調(diào)度即可正確高效的執(zhí)行。為了不影響編譯器的功能模塊和方便進(jìn)行對比測試。將指令延遲調(diào)度封裝在編譯選項(xiàng)-fsched-delay 中,在編譯時,通過使用編譯選項(xiàng)-fsched-delay 來控制編譯器使用指令延遲調(diào)度技術(shù)。
(1)表調(diào)度分析算法。要對表調(diào)度后的RTL 進(jìn)行指令延遲調(diào)度,需要優(yōu)化表調(diào)度的分析算法。通過指令調(diào)度數(shù)據(jù)流DUMP 算法的輸出數(shù)據(jù)流,直觀的顯示了指令信息。RTL 中間表示階段所有指令是由一個結(jié)構(gòu)體存儲即INSN。要對指令進(jìn)行延遲調(diào)度,首先需要了解表調(diào)度的調(diào)度原理,如圖1 所示。指令I(lǐng)NSN 已提交到計劃中,從“Ready”列表移動到“Scheduled”列表。當(dāng)發(fā)生這種情況時,“Pending”列表中的INSN 滿足其依賴關(guān)系并移動到“Ready”列表或“Queued”集合,具體取決于是否已經(jīng)有足夠的時間使其準(zhǔn)備就緒;隨著時間的推移,準(zhǔn)備就緒的INSN 從“Queued”移動到“Ready”列表;“Pending”列表(P)是未安排的INSN_FORW_DEPS 中的INSN,即準(zhǔn)備好,排隊(duì)和掛起的INSN?!癚ueued”集合(Q)由變量insn_queue 實(shí)現(xiàn)?!癛eady”列表(R)由變量ready 和n_ready 實(shí)現(xiàn)?!癝cheduled”列表(S)是由此傳遞構(gòu)建的新INSN 鏈。當(dāng)選擇最好的調(diào)度INSN 時,轉(zhuǎn)換(R-> S)在schedule_block 的調(diào)度循環(huán)中實(shí)現(xiàn)。當(dāng)INSN 從就緒列表移動到調(diào)度列表時,轉(zhuǎn)換(P-> R 和P-> Q)在schedule_insn 中實(shí)現(xiàn)。隨著時間的推移或引入停頓,轉(zhuǎn)換(Q-> R)在queue_to_insn 中實(shí)現(xiàn)。為了減小對編譯器的影響,對表調(diào)度分析算法進(jìn)行優(yōu)化,計算出延遲調(diào)度的相關(guān)信息并記錄保存,傳遞到指令延遲調(diào)度中。
圖1:編譯器指令調(diào)度數(shù)據(jù)流對比
圖2:編譯器編譯出的匯編碼對比
圖3:指令延遲調(diào)度技術(shù)優(yōu)化后的編譯器與官方編譯器編譯SPEC2017 Benchmarks 的耗時對比圖
(2)延遲指令生成算法。由于指令流里的指令是由源碼翻譯過來的,從一開始轉(zhuǎn)換到RTL 時,就生成了雙向鏈表,經(jīng)過表調(diào)度時,指令隊(duì)列進(jìn)行指令調(diào)度后依然是一個雙向鏈表。那么在進(jìn)行延遲調(diào)度時,要在雙向鏈表中插入延遲指令NOP。就要對雙向鏈表進(jìn)行維護(hù)。每一條指令都有一個前驅(qū)和后繼,當(dāng)前指令、前驅(qū)指令和后繼指令都是相互依賴的。當(dāng)insn 需要延遲時,首先就要斷開雙向鏈表prev 和insn,將nop 指令放在prev 和insn 之間。把insn的前驅(qū)設(shè)置為nop,prev 的后繼修改為nop,并把nop 的前驅(qū)設(shè)置為prev,后繼為insn。根據(jù)機(jī)器模型獲取nop 指令的RTL 結(jié)構(gòu),設(shè)置nop 指令所屬的基本塊為insn 的基本塊。
(3)指令延遲調(diào)度算法。指令延遲調(diào)度算法根據(jù)表調(diào)度分析算法記錄并傳遞來的數(shù)據(jù)使用延遲指令生成算法在需要延遲的指令前插入足夠的空操作指令NOP 來占用無指令的拍數(shù)。為盡量避免對編譯器其他功能的影響,我們選擇在編譯器表調(diào)度完成之后,RTL 翻譯成匯編碼之前,進(jìn)行指令延遲調(diào)度。首先判斷是否在編譯時使用了-fsched-delay 編譯選項(xiàng),以下所有操作都是在使用-fscheddelay編譯選項(xiàng)的情況下實(shí)現(xiàn)。接著判斷當(dāng)前是否屬于最后一次調(diào)度,即前面說的重載后調(diào)度(after reload)。當(dāng)兩個條件同時滿足時,對當(dāng)前基本快中已經(jīng)調(diào)度好的指令流進(jìn)行遍歷,尋找需要延遲的指令。當(dāng)遍歷到INSN 的編號INSN_UID 為表調(diào)度分析算法傳來數(shù)據(jù)中的INSN_UID 時,即這條INSN 需要在發(fā)射前插入NOP 延遲,根據(jù)數(shù)據(jù)中記錄的延遲拍數(shù)循環(huán)插入NOP 指令。調(diào)用延遲指令生成算法進(jìn)行指令生成。最后對指令在調(diào)度過程中的LUID 進(jìn)行維護(hù),以保證調(diào)度過程中每一條指令在調(diào)度過程中都有唯一的識別ID。
(1)指令延遲調(diào)度技術(shù)是通過靜態(tài)調(diào)度中使用停頓避免流水線冒險帶來的執(zhí)行錯誤,經(jīng)過應(yīng)用該技術(shù)的RISC-V GCC 編譯器編譯程序時,使用-fsched-verbose=n 編譯選項(xiàng)可輸出指令調(diào)度過程,能夠直觀的看到指令延遲調(diào)度的結(jié)果,如圖1 所示。
另一方面,指令延遲調(diào)度技術(shù)在靜態(tài)調(diào)度中完成了空拍指令的填充,生成的匯編碼中會明確顯示NOP 在相應(yīng)的位置,如圖2 所示。
經(jīng)過如圖1 和圖2 的試驗(yàn)驗(yàn)證,指令延遲調(diào)度技術(shù)能夠在指定拍數(shù)處填充NOP 指令,并且正確的生成對應(yīng)的匯編碼,來延遲下一條指令。編譯器的性能是在對編譯器改進(jìn)后的綜合評估,主要通過編譯時間來進(jìn)行比較,使SPEC2017 作為測試用例,測試了使用指令延遲調(diào)度技術(shù)的RISC-V GCC 編譯器編譯時間。實(shí)驗(yàn)編譯器運(yùn)行環(huán)境為:32 核Intel Xeon E7-4809 主頻2.00GHz 的CPU,64 位ubuntu14.04 系統(tǒng),一級指令/數(shù)據(jù)Cache 各32K,二級Cache256K。實(shí)驗(yàn)結(jié)果如圖3 所示。
圖3 中分別使用指令延遲調(diào)度技術(shù)優(yōu)化后的RISC-V GCC 編譯器和官方RISC-V GCC 編譯器在相同條件下編譯SPEC2017 中使用C 語言編寫的Benchmarks,由圖可見,優(yōu)化后的編譯器和原編譯器編譯相同Benchmarks 耗時相差不超過1s,實(shí)驗(yàn)證明,指令延遲調(diào)度技術(shù)對RISC-V GCC 的性能影響很小,達(dá)到了設(shè)計初期最小化編譯器影響的要求。為了驗(yàn)證優(yōu)化后的編譯器編譯出的程序可以正確的在RISC-V 處理器上運(yùn)行,以stream 作為測試程序,分別在超導(dǎo)模擬器和火苗原型系統(tǒng)上測試通過,能夠正確的執(zhí)行完成。超導(dǎo)v1 版本模擬器:位模式32 位,譯指隊(duì)列大小151,一級Cache128byte,二級Cache32K,寄存器個數(shù)16?;鹈缭拖到y(tǒng):4 核Labeled RISC-V 系統(tǒng),100 MHz rocket 核心, 16KB L1 Icache, 16KB L1 Dcache, 2MB L2 cache,16GB DDR4 SO-DIMMs,Linux 4.6.2 內(nèi)核。
指令調(diào)度在編譯器中是非常關(guān)鍵的環(huán)節(jié),指令延遲調(diào)度技術(shù)是RISC-V GCC 編譯器在RTL 一級的指令調(diào)度優(yōu)化,在RISC-V 處理器研發(fā)過程中作為編譯器輔助有著重要作用,尤其是在超導(dǎo)計算機(jī)研究中作為編譯器優(yōu)化研究意義重大。本文通過對RISC-V GCC 編譯器的改進(jìn)和優(yōu)化,為進(jìn)一步研究和優(yōu)化RSIC-V GCC 奠定了編譯器基礎(chǔ),更為快速研究新型的RISC-V 指令集架構(gòu)處理器起著重要的推動作用。