国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

基于國(guó)產(chǎn)GPU的GLSL編譯器設(shè)計(jì)?

2019-07-10 08:18彭獲然熊庭剛胡艷明
關(guān)鍵詞:編譯器詞法寄存器

彭獲然 熊庭剛 胡艷明 黃 亮

(武漢數(shù)字工程研究所 武漢 430205)

1 引言

在圖形處理器不斷發(fā)展的過(guò)程中,圖形應(yīng)用對(duì)可編程能力的需求日益增長(zhǎng),高級(jí)著色語(yǔ)言應(yīng)運(yùn)而生。開(kāi)發(fā)者通過(guò)使用高級(jí)著色語(yǔ)言編寫(xiě)著色器來(lái)自定義發(fā)生在圖形處理流程中關(guān)鍵處的處理過(guò)程,利用底層的圖形硬件實(shí)現(xiàn)更多樣復(fù)雜的渲染效果[1]。圖形驅(qū)動(dòng)中的著色語(yǔ)言編譯器便承擔(dān)起編譯著色器的任務(wù),并在圖形渲染管線(xiàn)中扮演重要角色,其生成的機(jī)器代碼的質(zhì)量會(huì)直接影響圖形渲染的效果和效率。

2 GLSL和OpenGL中的著色器

GLSL 是OpenGL 規(guī)范中用來(lái)編寫(xiě)著色器的高級(jí)著色語(yǔ)言,其語(yǔ)法源于C 語(yǔ)言,二者的源碼非常相似,這使得著色器的編寫(xiě)和閱讀對(duì)于有C 語(yǔ)言基礎(chǔ)的開(kāi)發(fā)者來(lái)說(shuō)更加容易。在OpenGL 2.0中,開(kāi)發(fā)者可使用GLSL version1.10 編寫(xiě)頂點(diǎn)著色器和片段著色器程序。圖1 展示了應(yīng)用程序中OpenGL 著色器的執(zhí)行模型,應(yīng)用程序通過(guò)OpenGL API 中的函數(shù)調(diào)用編譯器對(duì)著色器源碼字符串進(jìn)行處理,得到可執(zhí)行機(jī)器碼。

3 GLSL編譯器設(shè)計(jì)

本文的GLSL 編譯器的流程如圖2 所示。其前端包含預(yù)處理、詞法分析、語(yǔ)法及語(yǔ)義分析和中間代碼生成;其后端包含代碼優(yōu)化和鏈接,最終生成目標(biāo)機(jī)器代碼。編譯器前后端之間使用一種標(biāo)準(zhǔn)的中間表示形式進(jìn)行過(guò)渡,便于使用相對(duì)成熟的機(jī)器無(wú)關(guān)的優(yōu)化技術(shù)[2]。

圖1 OpenGL著色器執(zhí)行模型

圖2 GLSL編譯器流程

3.1 GLSL編譯器前端設(shè)計(jì)

GLSL編譯器前端負(fù)責(zé)讀入著色器源碼并生成基于中間表示形式的中間代碼。首先前端根據(jù)GLSL 的預(yù)處理指令對(duì)著色器源碼進(jìn)行預(yù)處理,包括宏定義的替換和條件編譯部分源碼的刪減等。GLSL 的預(yù)處理指令的功能和使用方法與C 語(yǔ)言類(lèi)似,存在少量區(qū)別(如沒(méi)有#include 指令等),在GLSL的官方文檔中有詳細(xì)說(shuō)明[3]。

3.1.1 詞法分析

GLSL編譯器前端的核心部分包含詞法分析和語(yǔ)法語(yǔ)義分析。詞法分析器讀入預(yù)處理后生成的字符流,剔除其中的注釋部分并組織成有意義的詞素序列;對(duì)于每個(gè)詞素,詞法分析器產(chǎn)生詞法單元作為輸出,包含行號(hào)信息、詞素類(lèi)型及詞素的值,詞素類(lèi)型有標(biāo)識(shí)符、操作符、關(guān)鍵字、常量以及空白符。其中標(biāo)識(shí)符、操作符和關(guān)鍵字的值為其字符串,常量的值即為其本身的值,空白符沒(méi)有值。本文使用開(kāi)源的Flex工具根據(jù)GLSL的詞法規(guī)則生成詞法分析器,其工作流程如圖3所示。

使用Flex來(lái)生成詞法分析器時(shí),需要用正則表達(dá)式(Regular Expression,RE)這一強(qiáng)大的符號(hào)表示法來(lái)描述目標(biāo)語(yǔ)言的字符模式[4]。描述GLSL 的標(biāo)識(shí)符的代碼如下所示,標(biāo)識(shí)符由字母、下劃線(xiàn)和數(shù)字組成且開(kāi)頭不能是數(shù)字:

identifier{nodigit}({nodigit}{|digit})*

nodigit [_A-Za-z]

digit [0-9]

圖3 Flex和詞法分析器

常量(包括八進(jìn)制、十進(jìn)制、十六進(jìn)制的整數(shù)和浮點(diǎn)數(shù))也用類(lèi)似的方法描述其模式,空白字符和操作符采用逐個(gè)列舉的方式,關(guān)鍵字則使用關(guān)鍵字列表從標(biāo)識(shí)符中區(qū)分出來(lái)。

以圖4 中這段頂點(diǎn)著色器源碼example.vert 為例,經(jīng)詞法分析會(huì)生成如下詞法單元序列(行號(hào)信息在此省略):(關(guān)鍵字 ,“attribute”),(關(guān)鍵字,“vec4”),(標(biāo) 識(shí) 符 ,“my_Vertex”),(操 作 符 ,“;”)……(標(biāo)識(shí)符,“gl_Position”),(操作符,“=”),(標(biāo)識(shí)符,“my_TransformMatrix”),(操作符,“*”),(標(biāo)識(shí)符,“my_Vertex”),(操作符,“;”),(操作符,“}”)。

圖4 頂點(diǎn)著色器源碼示例example.vert

3.1.2 語(yǔ)法分析與語(yǔ)義分析

在詞法分析完成后,語(yǔ)法分析器獲得一個(gè)詞法單元序列,根據(jù)GLSL的語(yǔ)法識(shí)別其中的語(yǔ)法成分,并驗(yàn)證其結(jié)構(gòu)可以由GLSL 的語(yǔ)法生成,否則進(jìn)行錯(cuò)誤處理。此外,語(yǔ)法分析器還需要檢查前述序列是否符合GLSL的語(yǔ)義,例如類(lèi)型是否匹配,被使用的變量是否已定義等;若著色器語(yǔ)法語(yǔ)義正確,語(yǔ)法分析器將根據(jù)著色器中的語(yǔ)句構(gòu)造語(yǔ)法樹(shù),語(yǔ)法樹(shù)中的每個(gè)內(nèi)部節(jié)點(diǎn)表示一個(gè)運(yùn)算,而該節(jié)點(diǎn)的子節(jié)點(diǎn)表示該運(yùn)算的分量[5]。本文所述編譯器的語(yǔ)法分析器采用開(kāi)源的Bison 工具生成,其工作流程如圖5所示。

圖5 Bison和語(yǔ)法分析器

使用Bison 生成語(yǔ)法分析器時(shí),在Bison 源程序中使用LALR(1)語(yǔ)法來(lái)描述目標(biāo)語(yǔ)言的語(yǔ)法規(guī)則[6]。圖6 是Bison 源程序中描述語(yǔ)法規(guī)則的部分片段,包括動(dòng)作函數(shù)的參數(shù)類(lèi)型定義,終結(jié)符定義,變量標(biāo)識(shí)符的模式和相應(yīng)動(dòng)作。著色器的詞法單元序列會(huì)在語(yǔ)法分析器中匹配到具體的語(yǔ)法范式,并執(zhí)行該范式對(duì)應(yīng)的動(dòng)作函數(shù),完成著色語(yǔ)言程序語(yǔ)法樹(shù)的創(chuàng)建。

圖6 Bison程序片段

以example.vert為例,經(jīng)過(guò)語(yǔ)法分析后得到圖7所示的語(yǔ)法樹(shù),同時(shí)生成名字信息表(部分名字信息表見(jiàn)表1)。

表1 部分名字信息

圖7 example.vert的語(yǔ)法樹(shù)

由于三地址代碼拆分了多運(yùn)算符算術(shù)表達(dá)式以及控制流語(yǔ)句的嵌套結(jié)構(gòu),比較適用于目標(biāo)代碼的生成和優(yōu)化,故本文所述編譯器采用三地址碼作為中間表示形式。對(duì)于GLSL,三地址代碼中的地址可以是屬性(Attribute)、一致變量(Uniform)、著色器中明確定義的變量、輸出變量(Output)、臨時(shí)變量和常數(shù)。

首先將語(yǔ)法分析器輸出的語(yǔ)法樹(shù)轉(zhuǎn)換為三地址代碼語(yǔ)法樹(shù),轉(zhuǎn)換的過(guò)程中需要根據(jù)目標(biāo)GPU平臺(tái)的指令集作一些變換。以圖7 語(yǔ)法樹(shù)為例,由于目標(biāo)GPU 平臺(tái)的乘法指令只支持標(biāo)量或四分量向量作操作數(shù),故將矩陣乘法拆分為多條向量乘法和加法指令,得到如圖8所示三地址代碼語(yǔ)法樹(shù)。

接下來(lái)通過(guò)深度優(yōu)先遍歷三地址代碼語(yǔ)法樹(shù)可得到如表2 所示的三地址代碼中間表示形式,中間表示可輸出到文本文件中方便調(diào)試(注:表2 中OP 代表操作符,DST 代表目的操作數(shù),SRC 代表源操作數(shù))。

圖8 三地址代碼語(yǔ)法樹(shù)

表2 三地址代碼中間表示形式

3.2 GLSL編譯器后端設(shè)計(jì)

GLSL 編譯器后端讀入中間代碼,由代碼優(yōu)化模塊負(fù)責(zé)對(duì)其優(yōu)化,通過(guò)改進(jìn)中間代碼,以達(dá)到生成更好的目標(biāo)代碼的目的。鏈接模塊則要完成鏈接樹(shù)的創(chuàng)建,并根據(jù)鏈接樹(shù)來(lái)分配物理寄存器資源并設(shè)置相應(yīng)寄存器模式,最終生成符合GPU 指令集的目標(biāo)機(jī)器代碼。

3.2.1 優(yōu)化

優(yōu)化部分分為機(jī)器無(wú)關(guān)的優(yōu)化和機(jī)器相關(guān)的優(yōu)化。本文所述編譯器采取的機(jī)器無(wú)關(guān)代碼優(yōu)化方式包含:死代碼消除,函數(shù)展開(kāi),常量傳播,冗余判斷消除,公共子表達(dá)式消除,循環(huán)展開(kāi)和代碼移動(dòng)等較為成熟的中間代碼優(yōu)化技術(shù)[7~10]。

而針對(duì)所用國(guó)產(chǎn)GPU 的SIMD 指令集架構(gòu),本文采取的機(jī)器相關(guān)代碼優(yōu)化包含乘加指令優(yōu)化和向量指令合并。具體如下。

1)乘加指令優(yōu)化:由于目標(biāo)機(jī)器的指令集包含乘加指令,且著色器一般包含大量乘法和加法運(yùn)算,乘加指令優(yōu)化將大大提高程序的性能;如果一條加法指令只依賴(lài)之前的一條乘法指令,且乘法指令的目標(biāo)使能與加法指令一致,相應(yīng)的乘法指令和加法指令可以被合并成一條乘加指令。

例如MUL R0 R1 R2

//R0 ←R1*R2

ADD R3 R4 R0

//R3 ←R4+R0

兩條指令若滿(mǎn)足條件可優(yōu)化為

MAD R3 R1 R2 R4

//R3 ←R4+(R1*R2)

2)合并向量指令:目標(biāo)機(jī)器的指令集基于向量指令,提高向量指令的利用效率是代碼優(yōu)化的重要目標(biāo);對(duì)于多條具備相同指令碼的指令,如果其相應(yīng)操作數(shù)可分配到同一向量寄存器上而不影響運(yùn)算結(jié)果,便可合并為一條向量指令,向量指令合并可降低代碼長(zhǎng)度同時(shí)減少寄存器使用量[11]。

例如:[x,y,0,0]←[a,b,0,0]+[c,d,0,0]

[0,0,z,w]←[0,0,e,f]+[0,0,g,h]

兩條語(yǔ)句可以合并為:

[x,y,z,w]←[a,b,e,f]+[c,d,g,h]

example.vert 的三地址代碼經(jīng)過(guò)優(yōu)化之后,用偽代碼表示如表3 所示,指令數(shù)量得到明顯的精簡(jiǎn)。

表3 優(yōu)化之后得到的代碼

3.2.2 鏈接

目標(biāo)機(jī)器碼的鏈接由鏈接器完成,鏈接器負(fù)責(zé)鏈接樹(shù)的創(chuàng)建,并根據(jù)鏈接樹(shù)來(lái)分配國(guó)產(chǎn)GPU 中的物理寄存器資源并設(shè)置相應(yīng)寄存器模式,最終生成符合國(guó)產(chǎn)GPU 指令集的目標(biāo)機(jī)器代碼。鏈接器的工作主要有兩方面要求:生成高效率的目標(biāo)機(jī)器代碼和有效地利用目標(biāo)機(jī)器上的可用資源。

由于只涉及寄存器運(yùn)算分量的指令要比那些涉及內(nèi)存運(yùn)算分量的指令運(yùn)行快得多,而GPU 的寄存器資源又非常有限,因此如何提升寄存器資源的利用效率成為鏈接階段的一個(gè)重要工作內(nèi)容。如果一個(gè)變量的值存放在寄存器中,而之后一直不會(huì)被使用,那么這個(gè)寄存器就應(yīng)該被分配給另外一個(gè)變量[12]。表4 簡(jiǎn)單地展示了寄存器分配的這一基本思路(其中uniform(0)為矩陣,由連續(xù)四個(gè)寄存器按順序分別存儲(chǔ)一列元素,各列使用相對(duì)尋址訪(fǎng)問(wèn)),相對(duì)于表3 減少了三個(gè)臨時(shí)寄存器占用而不影響程序結(jié)果。

為了有效利用寄存器資源,需要綜合考慮函數(shù)調(diào)用及循環(huán)嵌套,記錄屬性、變量和輸出的使用信息以及各條指令代碼的啟示性信息,包括當(dāng)前代碼屬于哪個(gè)函數(shù)體,當(dāng)前代碼調(diào)用者,當(dāng)前代碼最深的函數(shù)嵌套層次,當(dāng)前代碼對(duì)應(yīng)的臨時(shí)寄存器的后續(xù)使用信息[13~14]。

表4 example.vert程序寄存器分配示意

鏈接器最后需要輸出目標(biāo)機(jī)器代碼。國(guó)產(chǎn)GPU 的指令集包括常用算術(shù)運(yùn)算,超越函數(shù)計(jì)算,流程控制和紋理操作等。指令集支持一個(gè)目的操作數(shù)和三個(gè)源操作數(shù)。源操作數(shù)可以任意取反或取絕對(duì)值;指令支持源操作數(shù)和目的操作數(shù)的任意分量選擇;目的操作數(shù)可設(shè)置飽和操作;指令支持相對(duì)尋址模式。為了更好地契合國(guó)產(chǎn)GPU 的指令集架構(gòu),且保證代碼轉(zhuǎn)化的靈活性,本文采取模式匹配的方法生成機(jī)器代碼[15],具體步驟如下:

第一步,將指令指針I(yè)P 設(shè)置到中間代碼起始位置;

第二步,模式指針PP 設(shè)置到目標(biāo)模式起始位置;

第三步,判斷模式對(duì)應(yīng)指令數(shù)是否大于剩余未轉(zhuǎn)換的中間代碼,若是,進(jìn)入第四步;否則進(jìn)入第五步;

第四步,模式指針PP 設(shè)為下一模式起始位置并重復(fù)第三步;

第五步,從模式指針PP和指令指針I(yè)P開(kāi)始,逐條判斷各指令是否匹配,若模式得到完整匹配便生成該模式對(duì)應(yīng)的機(jī)器指令代碼并進(jìn)入下一步,否則執(zhí)行第四步;

第六步,指令指針增加已匹配模式對(duì)應(yīng)指令數(shù),若所有中間代碼已完成匹配,結(jié)束流程,否則執(zhí)行第二步。

4 實(shí)驗(yàn)與結(jié)果

本文使用如圖9 所示的頂點(diǎn)和片段著色器對(duì)編譯器進(jìn)行基本功能測(cè)試。

頂點(diǎn)著色器經(jīng)編譯器處理得到如表5 所示偽代碼。

片段著色器經(jīng)編譯器處理得到偽代碼如表6所示。

應(yīng)用程序輸出渲染效果如圖10 所示,說(shuō)明著色器經(jīng)編譯器編譯可正常工作,驗(yàn)證了編譯器的基本功能。

圖9 測(cè)試用著色器

表5 實(shí)驗(yàn)頂點(diǎn)著色器優(yōu)化后偽代碼

表6 實(shí)驗(yàn)片段著色器偽代碼

圖10 渲染效果

5 結(jié)語(yǔ)

本文根據(jù)GLSLv1.10的特點(diǎn),借助Flex與Bison工具設(shè)計(jì)了GLSL 編譯器的前端;以三地址碼作為中間表示使后端可以應(yīng)用多種成熟的機(jī)器無(wú)關(guān)代碼優(yōu)化技術(shù),并針對(duì)國(guó)產(chǎn)GPU 平臺(tái)的SIMD 指令集架構(gòu)應(yīng)用乘加指令優(yōu)化和向量指令合并進(jìn)一步優(yōu)化代碼;最終鏈接生成目標(biāo)機(jī)器代碼。該編譯器可將GLSLv1.10 編寫(xiě)的著色器編譯成該國(guó)產(chǎn)GPU 平臺(tái)上可執(zhí)行的代碼,為國(guó)產(chǎn)GPU 對(duì)OpenGL 規(guī)范的支持做出了一定的貢獻(xiàn),由于對(duì)應(yīng)的版本相對(duì)落后,與今天商用平臺(tái)的仍有很大差距,今后仍需進(jìn)一步拓展編譯器功能,以支持更高版本的GLSL,同時(shí)繼續(xù)深入研究編譯過(guò)程中的優(yōu)化技術(shù),以提高輸出機(jī)器碼質(zhì)量。

猜你喜歡
編譯器詞法寄存器
面向理想性能空間的跨架構(gòu)編譯分析方法
Lite寄存器模型的設(shè)計(jì)與實(shí)現(xiàn)
運(yùn)行速度大突破華為《方舟編譯器》詳解
二進(jìn)制翻譯中動(dòng)靜結(jié)合的寄存器分配優(yōu)化方法
移位寄存器及算術(shù)運(yùn)算應(yīng)用
應(yīng)用于詞法分析器的算法分析優(yōu)化
詞法分析程序的設(shè)計(jì)與實(shí)現(xiàn)研究
2010年高考英語(yǔ)“相似”考題例析
優(yōu)化編譯器的設(shè)計(jì)
基于ARM嵌入式平臺(tái)的x86譯碼SOC架構(gòu)設(shè)計(jì)
诸暨市| 石家庄市| 宿迁市| 宜都市| 德惠市| 弥勒县| 丰镇市| 永城市| 五台县| 渑池县| 龙川县| 万山特区| 连山| 大同县| 克东县| 高青县| 儋州市| 南溪县| 垫江县| 民乐县| 赫章县| 伊川县| 日照市| 老河口市| 松阳县| 东乡| 定安县| 靖江市| 大姚县| 盐源县| 绍兴市| 攀枝花市| 宣城市| 东源县| 汉沽区| 灌南县| 英德市| 雅江县| 蓬溪县| 安岳县| 蓬莱市|