Xtensa處理器窗寄存器函數(shù)調(diào)用機(jī)制與應(yīng)用
現(xiàn)代處理器為了更好的支持高級(jí)編程語(yǔ)言的高效編譯,通常處理器所擁有的通用寄存器的數(shù)目都有16個(gè)甚至32個(gè)之多,如此多的寄存器在比較復(fù)雜的應(yīng)用程序上實(shí)現(xiàn)深度嵌套調(diào)用的時(shí)候,為了保證程序的正確執(zhí)行,寄存器要頻繁的進(jìn)行入棧和出棧操作,這樣頻繁的堆棧存儲(chǔ)器訪問將明顯降低應(yīng)用程序的性能,為有效解決這一問題,tensilica的Xtensa架構(gòu)設(shè)計(jì)了一種Windows旋轉(zhuǎn)方式的寄存器管理機(jī)制,將邏輯寄存器和物理寄存器分開,在函數(shù)調(diào)用的時(shí)候通過windows滑動(dòng)切換邏輯寄存器,從而避免寄存器覆蓋,減少壓棧和出棧的操作,更大限度的提高性能。
本文引用地址:http://butianyuan.cn/article/185680.htm以一個(gè)MP3解碼器為例(如表1),假設(shè)外部存儲(chǔ)器的訪問的R/W等待cycles分別為100和20,可以看到采用Call8的windows旋轉(zhuǎn)大幅減少M(fèi)CPS到9%之多。
表1:MP3解碼器。
那么Windows寄存器機(jī)制是如何工作的,它又有那些典型應(yīng)用呢? 本文將詳細(xì)闡述這一主題。
寄存器Windows函數(shù)調(diào)用機(jī)制原理
1.AR物理寄存器環(huán)形Buffer
該方法的基本實(shí)現(xiàn)原理是用更多的物理AR寄存器組成一個(gè)環(huán)形的buffer,這些物理寄存器每4個(gè)為一組(pane),用一個(gè)WindowStart的每個(gè)比特依次表示是否該組作為邏輯寄存器窗口的起始位置或者占用,當(dāng)前的邏輯寄存器的起始位置則用WindowBase狀態(tài)寄存器來表示。如圖1,在發(fā)生函數(shù)調(diào)用的時(shí)候則通過修改WindowBase寄存器,滑動(dòng)邏輯寄存器窗口,設(shè)置相應(yīng)的WindowStart比特標(biāo)識(shí)當(dāng)前邏輯窗口在環(huán)形物理AR寄存器buffer中的位置。這樣父子函數(shù)看到的是不同的物理寄存器,避免了寄存器的壓棧和出棧。要說明的是,如果AR物理寄存器的數(shù)目為NAREG,則WindowStart的比特?cái)?shù)則為NAREG/4,而WindowBase的比特位數(shù)則為log(NAREG/4),如圖1所示,物理寄存器數(shù)為32,則WindowStart比特?cái)?shù)為8,WindowBase比特?cái)?shù)則為3.
圖1:Windows AR寄存器環(huán)形buffer.
2.Windows ABI函數(shù)調(diào)用規(guī)范
以每4個(gè)寄存器(pane)為單位,函數(shù)調(diào)用的時(shí)候窗口可以滑動(dòng)4個(gè)、8個(gè)、或者12個(gè)物理寄存器,分別可以用call4、call8、call12指令來實(shí)現(xiàn),而最典型的應(yīng)用則為call8,在c語(yǔ)言層面,編譯器通過XPG的core配置,可以為函數(shù)調(diào)用分別產(chǎn)生非windows機(jī)制的call0和call8,那么call8的Windows ABI函數(shù)調(diào)用規(guī)范是怎樣的呢? 參考圖2,左上角說明的是子函數(shù)調(diào)用約用規(guī)范,a0被用來保存返回地址,a1則為sp堆棧指針,a2~a7則用來傳遞函數(shù)入?yún)ⅲ瑓?shù)超過6個(gè)的時(shí)候則需要使用堆棧了,以對(duì)調(diào)用者函數(shù)和被調(diào)用函數(shù)來說,a0~a7為獨(dú)立的寄存器,可以自由使用,而a8~a15則為scratch寄存器,隨時(shí)會(huì)被子函數(shù)使用,調(diào)用者函數(shù)如果要使用,則在調(diào)用子函數(shù)前要壓棧保存。
圖2:Window ABI調(diào)用規(guī)范。
為方便寄存器正常的保存與恢復(fù),以及調(diào)用棧的高效回溯,有必要對(duì)函數(shù)的Frame??臻g做統(tǒng)一的安排,在call8的Windows ABI規(guī)范下,Tensilica進(jìn)行了如下設(shè)計(jì)(如圖3)。
圖3:Windows ABI堆棧布局。
每級(jí)函數(shù)FrAME下包含有Base Area用于存儲(chǔ)其父函數(shù)的基本寄存器a0~a3,可能的extra area保存其子函數(shù)的擴(kuò)展寄存器a4~a7(call8),或者a4~a11(call12),函數(shù)局部變量(非寄存器變量)和alloc分配空間,及用于傳子函數(shù)所需要的??臻g等等。
當(dāng)較新的深度函數(shù)Fun(i)的寄存器窗口覆蓋到過去的函數(shù)Fun(p)時(shí),基本寄存器a0~a3保存到Fun(p+1)的basic area,額外的寄存器則存入Fun(p)的extra area,當(dāng)函數(shù)Fun(p+1)返回時(shí),如果檢測(cè)到underflow則相應(yīng)地將base area和extra area的寄存器恢復(fù)到Fun(p)的活動(dòng)窗口,讀者可以參考Tensilica的代碼體會(huì)一下,這樣的布局在壓棧和恢復(fù)的時(shí)候代碼是最高效和節(jié)省空間的。
3.Windows寄存器覆蓋問題
物理AR寄存器的數(shù)目是有限的,典型情況下,32個(gè)物理寄存器發(fā)生深度為3次,64個(gè)AR發(fā)生7次的函數(shù)調(diào)用后將會(huì)覆蓋到原來的函數(shù)寄存器窗,那么如何有效檢測(cè)和處理寄存器overflow問題呢?
寄存器的覆蓋檢測(cè)只發(fā)生在如下兩種情況:
函數(shù)調(diào)用時(shí),參考如下硬件semanTIcs:
CALLn/CALLXn
PS.CALLINC ← n32
AR[n||2'b00] ← n || (PC + 3)290
ENTRY s,imm12
WindowCheck (00,PS.CALLINC,00)
if as > 3 | PS.WOE = 0 | PS.EXCM = 1 then
-- undefined operatiON
-- may raise illegal instruction exception
else
AR[PS.CALLINC||s10] ← AR[s]- (017||imm12||03)
WindowBase ← WindowBase + (02||PS.CALLINC)
WindowStartWindowBase ← 1
endif
在發(fā)生函數(shù)調(diào)用,執(zhí)行call指令的時(shí)候,窗遞增值(call4、call8、call12分別對(duì)應(yīng)1、2、3)存入PS處理器狀態(tài)寄存器的CALLINC域,在進(jìn)入函數(shù)的入口處ENTRY指令將首先進(jìn)行Window重疊檢測(cè),條件滿足的時(shí)候?qū)⒂|發(fā)相應(yīng)的windows overflow異常,引導(dǎo)程序進(jìn)行覆蓋寄存器的入棧保護(hù)。
正常模式下函數(shù)內(nèi)部指令的寄存器引用,如xxx ar,as,at,處理器在非異常模式下將進(jìn)行正常的window檢測(cè),否則產(chǎn)生非法指令異常。
4.Windows寄存器檢測(cè)方法
寄存器覆蓋檢測(cè)通過如下硬件semantic實(shí)現(xiàn):
WindowCheck
n ← if (wr ≠ 2'b00 or ws ≠ 2'b00 or wt ≠ 2'b00) and WindowStartWindowBase+1 then 2'b01
else if (wr1 or ws1 or wt1) and WindowStartWindowBase+2 then 2'b10
else if (wr = 2'b11 or ws = 2'b11 or wt = 2'b11) and WindowStartWindowBase+3 then 2'b11
else 2'b00
if CWOE = 1 and n ≠ 2'b00 then
PS.OWB ← WindowBase
m ← WindowBase + (2'b00||n)
PS.EXCM ← 1
EPC[1] ← PC
nextPC ← if WindowStartm+1 then WindowOverflow4
else if WindowStartm+2 then WindowOverflow8
else WindowOverflow12
WindowBase ← m(注:和Overflow跳轉(zhuǎn)并行)
endif
通過深入解析如上原語(yǔ),有如下注意要點(diǎn):任何地方引用a0~a3不會(huì)產(chǎn)生windows異常,因此在用戶的c或者匯編代碼里可以任意使用,為什么呢? 因?yàn)樵赼0~a3引用的任意環(huán)境里,當(dāng)前函數(shù)的邏輯窗里的物理寄存器,要么是無覆蓋安全到達(dá),要么是經(jīng)過了函數(shù)調(diào)用entry指令觸發(fā)windows overflow異常,在異常里,a0~a3的所在物理AR寄存器已經(jīng)安全地壓棧保存了。
a15~a4之間的高位寄存器(比如a15)引用會(huì)觸發(fā)低位寄存器(如a4)的寄存器覆蓋檢測(cè),哪怕沒有指令顯式的應(yīng)用低位寄存器,觸發(fā)的順序?qū)⑹窍冗M(jìn)行overflow4,overflow8,至overflow12,從而最有效和最安全地保存活動(dòng)寄存器。通過了解以上兩點(diǎn),讀者可以深入理解Tensilica提供的高效XTOS代碼,透徹體會(huì)相關(guān)代碼的精妙之處。
c語(yǔ)言相關(guān)文章:c語(yǔ)言教程
評(píng)論