編輯語:
晶片開放社群(OCC)面向開發者推出RISC-V系列内容,通過多角度、全方位解讀RISC-V,系統性梳理總結相關理論知識,建構RISC-V知識圖譜,促進開發者對RISC-V生态全貌的了解。
前兩期内容,我們從“商業模式”角度介紹了RISC-V架構的起源、發展過程和未來趨勢,為後續介紹奠定了基礎。本期是“技術創新”主題内容,将通過闡述代碼密度的決定因素,帶大家了解RISC-V架構代碼密度的現狀,并簡單介紹平頭哥對RISC-V代碼密度的優化成果。
對于記憶體受限的嵌入式晶片(包括MCU和成本要求的AP類晶片)來說,代碼密度非常重要。同樣功能的程式,如果代碼密度過大,就可能導緻因ROM空間裝載不下而無法使用。是以,在嵌入式領域中,代碼密度是最重要的名額之一。那麼,代碼密度由什麼決定?如何提高代碼密度呢?RISC-V的代碼密度現狀又如何?通過本文,我們将為大家一一解答。
01 代碼密度的決定因素
如上面的倒金字塔所示,代碼密度主要由指令集、ABI、編譯器、Runtime庫、程式代碼五個部分決定。處在金字塔的越底端,說明該因素越底層,更新的頻率越小,但輻射和影響的範圍卻越廣。
02 指令集
指令集是代碼密度最根本的決定性因素,它決定了一個操作在最優的情況下需要編譯成多少位寬的編碼。
很多體系結構比如ARM、RISC-V、C-SKY都是16位指令、32位指令混編的,同樣的一條指令,如果能夠被編譯成16位指令,那麼它顯然比編譯成32位指令占用更小的空間;再比如,一個乘累加的操作,如果指令集中存在乘累加指令,那麼它隻需要一條指令來實作乘累加操作,如果沒有則需要至少兩條指令來完成相同的操作,假設指令都是32位的,顯然一條指令将占用更少的空間。
由于指令集的編碼空間是有限的,是以指令集設計的核心是将哪些指令(包括指令操作數的範圍)放到編碼空間當中,就像一個商場的店面是有限的,當我們把需求最廣的商家引進來時,商場的銷量就會達到最高。
03 ABI
ABI的全稱是Application Binary Interface,是二進制級别的協定,它指導着編譯器如何生成代碼和二進制程式,同樣也指導着使用者如何寫彙編代碼。它主要包含函數調用約定(calling convention)、資料的對齊方式等内容。
其中對代碼密度影響最大的就是函數調用約定,它規定了堆棧寄存器、連結寄存器、哪些寄存器需要在函數頭尾儲存和恢複、哪些寄存器可以作為參數寄存器等,還有一些特殊用途的寄存器。大部分特殊寄存器都是會被高頻使用的,配合指令集設計可以降低代碼密度;需要儲存和恢複的寄存器個數同樣也會影響代碼密度。
04 編譯器
編譯器是開發者最直接接觸的工具,也是給開發者體感最強的代碼密度影響因素。它對代碼密度的影響主要展現在兩方面:
① 編譯器本身的優化能力,優化能力的強弱是影響編譯器産品競争力的最主要的因素。
② 編譯器的使用方法,比如GCC,除了添加-Os之外,還可以添加-ffunction-sections -fdata-sections -Wl,--gc-sections來删除沒有用到的函數。
05 Runtime庫
Runtime庫是指程式運作所需的一些基本的函數庫,它們一般都是預先編譯好,和編譯器一起打包釋出,是工具鍊的一部分。由于這些函數的使用頻率較高,一般程式都會用到一部分Runtime庫的函數,對這些函數做針對性地優化會有比較好的收益。
06 程式代碼
開發者書寫的代碼品質也會影響程式的代碼密度,雖然編譯器能夠優化一部分備援代碼,但是并不能保證百分之百的優化,是以開發者也要注意代碼的品質。
07 RISC-V架構的代碼密度現狀
RISC-V的代碼密度表現一直被人诟病,那麼,它的現狀真的這麼不值一提嗎?
首先,RISC-V對代碼密度做過一些專門的優化:
- 在指令集方面,它通過量化分析的方法測試了spec等benchmark,找到高頻指令并将它們放到16位指令的編碼當中,這就是目前的compress指令集;
- 在ABI方面,rv32e通過限制16個寄存器,使代碼可以生産更多的16位指令;
- 在編譯器和Runtime中,它支援-msave-restore功能通過庫函數調用的方式彌補了由于沒有push/pop指令造成的一部分代碼密度損失。
這裡需要特别指出的是,RISC-V的連結器做了較多的relax優化,即某些指令的目标符号距離比較接近的時候,可以優化使用更少的指令。比如函數跳轉,比如具體在4k之内,可以使用一條jalr指令實作,而如果超過4k的話,則需要auipc+jalr或者lui+jalr兩條指令實作。一般在未連結的object檔案中,預留的都是指令條數最多的形式,連結之後很大一部分将被優化。如果測試的benchmark如果統計的是object檔案,比如CSiBE,那麼結果會比實際的要差一些。
那麼,在做了這些優化之後,為什麼RISC-V的代碼密度還是被這麼多人诟病呢?主要是由于compress指令集設計時,基于的benchmark是spec2006,它在應用PC端非常具有代表性,但在嵌入式領域卻不具有典型性。是以在RISC-V 64位核中,它的代碼密度表現還不錯,但是在真正關心代碼密度的嵌入式領域表現卻不盡如人意。其次,ABI也需要重新針對嵌入式領域做量化評估和設計。
08 平頭哥對RISC-V的代碼密度優化
針對代碼密度,RISC-V社群目前也在不斷地優化中,比如code-size TG和EABI TG的成立。平頭哥也參與其中,在優化代碼密度的道路上不斷前行。目前,平頭哥所做的優化有如下兩個方面:
① Runtime庫
平頭哥設計開發了一套針對嵌入式領域的、最大化優化代碼密度的Lower-Level Runtime Library。目前玄鐵E902、玄鐵E906和玄鐵E907均已支援該Runtime庫,它相對于libgcc提升40%;相對于Arm的macrolib,玄鐵E902與M0-plus相當,玄鐵E906、玄鐵E907與M4相當。
② ABI
目前,社群正在設計、制定針對嵌入式領域的新的ABI——EABI(Embedded ABI),它不僅會調整Calling Convention以減少中斷延遲,也會考慮代碼密度,使用量化分析地方法設計出一套對嵌入式領域優化的ABI。平頭哥作為EABI Task Group的Co-Chair,也參與其中推動EABI的前進。
09 下期預告
以上是對RISC-V代碼密度的全面介紹,後續文章我們還将繼續更新關于RISC-V指令集優劣勢分析的文章。下期内容,我們将站在“應用開發”視角,為大家描述基于RISC-V架構的玄鐵C處理器的安全拓展。