• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            歲月流轉,往昔空明

            C++博客 首頁 新隨筆 聯系 聚合 管理
              118 Posts :: 3 Stories :: 413 Comments :: 0 Trackbacks

            表達式值的存儲

            LLVM中基本數據類型及存儲類型

            值是編譯器所需要處理的基本數據。它出現在各個角落,條件分支、表達式、返回語句。甚至是函數地址也可以被視作是值類型。

            對于編譯器而言,最基本的值是整數和浮點。其他的值都可以用這兩者來表達,例如布爾和指針。如果你是從一個最基本的指令集開始寫起,那么整數和浮點的數值運算、轉換、基于整數寄存器的跳轉和地址取值是一個寄存器機的最基本操作。所有更加高級的操作,例如數組、結構體、指針、函數、對象等,都可以建立在這一基礎上。

            如果一個指令系統在整數和浮點數之外,額外提供了布爾、分支、函數調用和結構體的支持,那么它與高級語言將會貼近更多,生成代碼的方式也更加簡單。

            在高級語義的數據結構上,LLVM提供了相當良好的支持。它支持的原生類型(First class)包括: 各種精度的整型和浮點數,指針、向量,結構體和數組。這些類型的數據存取和運算都是有指令直接支撐,而不需要自行計算并生成更加原始的指令。

            在存儲類型上,LLVM提供了Value, Argument, Alloca, GlobalVariable, Pointer五種存儲類型。Value是右值,它不可取引用,不可更改。Argument表示了函數實參,它是Value的一個派生類。所以對參數的任何更改行為實際上都是不被允許的。Alloca保存了棧地址,GlobalVariable保存了全局變量的地址,Pointer則是一般意義上的指針。

            除了存儲指令,LLVM所有的指令都是針對Value的操作,并返回一個Value。所以

            Var a = Alloca int
            Var b = Alloca int
            Var c = Alloca int
            c = ADD a, b
            

            這樣的操作,在LLVM中實際上是將a和b的地址相加,并把C從變量替換成一個左值(注意,是替換,變量的值沒有任何變化)。

            在LLVM中,正確的做法應當類似于下面這樣:

            a = Alloca int
            b = Alloca int
            c = Alloca int
            a_v = load a
            b_v = load b
            c_v = ADD a, b
            store c, c_v
            

            要先將值從變量中讀出,進行操作,再保存到另外一個變量中。

            表達式值的數據結構

            一個的表達式參數或結果可能是左值或右值。例如++x輸入一個左值返回一個左值,而x++就返回一個右值。A+B則是需要兩個右值并返回一個右值。

            一個左值可以很方便的轉化為右值,但是右值轉化成左值通常是很困難的。地址信息被丟棄了,或者它根本就是一個字面常量,都會導致一個右值將永遠是右值。將右值構造成左值的唯一辦法,就是構造臨時對象并將右值賦予左值。當這個左值被讀取時,如果臨時對象除了初始化之外從未被寫過,并且它關聯的右值依然有效,那么這個操作會被優化成直接返回那個原始的右值,從而避免臨時左值的讀寫操作。

            在Clang(一個C++編譯器的前端)中對左值和右值進行了嚴格的區分。這是由于C++需要額外的處理臨時對象。臨時對象意味著盡管它有右值的語義,但是實際上是左值的存儲。這是需要將真正的左值和臨時的左值區分開,并提供特定語境下的轉化。

            SASL沒有處理復雜的臨時對象問題,因此它使用了一個相對簡單的辦法來解決左右值的判定和存儲。

            我們設計了一個數據結構,用于保存任何可能的值。

            struct Data{
                bool isRef;
                Value* rval;
                Alloca* local;
                GlobalVariable* global;
                struct Aggregated{
                    Data* parent;
                    int index;
                } agg;
            };
            

            rval用于處理Argument和右值時的情況。Local意味著它是一個局部變量,global說明它是一個全局變量,agg則用于處理structure member。Parent指向包含當前變量的聚合變量,index則指明了當前變量在聚合變量中的位次。

            SASL提供了load, load_ptr 和 store 來數據的存取,而不要關心它的具體存儲類型。

            左值/右值語義

            在Data這個結構中,rval, local, global和agg四個值是互斥的。當然這里的我們也可以選擇union+enum的方式來表達。

            首先來看,這個結構如何表達左值/右值語義。

            來看isRef,這是一個標記位。它表示了data存儲的值究竟是值本身還是地址。如果是isref為真,那么data便可以被認為是一個左值。Isref為假,那么當它是rval的時候,它就是一個真正的右值了。如果是Alloca或者GlobalVariable,因為它們本身就代表了地址,那么它仍然是一個右值。如果是agg,那么要取決于它的聚合量是左值還是右值。

            如果參數需要左值,那么可以直接從data拷貝,或者使用load_ptr + isRef創建一個新的右值Data。如果參數需要右值,那么可以通過load的方式獲取一個右值。

            數據存取的實現

            llvm::Value* load( cgllvm_sctxt* data ){
              assert(data);
              Value* val = data->val;
              do{
                if( val ){ break; }
                if( data->local ){ val = builder()->CreateLoad( data->local );
                  break;
                }
                if( data->global ){
                  val = builder()->CreateLoad( data->global );
                  break;
                }
                if( data.agg.parent ){
                  val = load( data->agg.parent );
                  val = builder()->CreateExtractValue( val, data->agg.index );
                  break;
                }
              } while(0);
            
              if( data->is_ref ){val = builder()->CreateLoad( val );}
              return val;
            }
            
            
            llvm::Value* load_ptr( cgllvm_sctxt* data ){
            
              Value* addr = NULL;
              if( data->val ){ addr = NULL; }
              if( data->local ){
                addr = data->local;
              }
              if( data->global ){
                addr = data->global;
              }
              if( data->agg.parent ){
                addr = builder()->CreateGEP( load_ptr(data->agg.parent), 0, data->arg.index );
              }
            
              if( data->is_ref ){
                if( !addr ){
                  addr = data->val;
                } else {
                  addr = builder()->CreateLoad( addr );
                }
              }
            
              return addr;
            }
            
            void store( llvm::Value* v, cgllvm_sctxt* data ){
              Value* addr = load_ptr( data );
              builder()->CreateStore( v, addr );
            }
            
            posted on 2011-04-13 11:04 空明流轉 閱讀(1659) 評論(1)  編輯 收藏 引用

            評論

            # re: SALVIA Shading Language中的表達式值的表示與Graphics Pipeline語義的表達(上) 2011-04-13 14:20 千暮(zblc)
            我擦 這代碼清晰  回復  更多評論
              

            国产精品免费久久久久影院| 久久精品国产黑森林| 久久亚洲精品无码aⅴ大香| 久久久久亚洲av成人无码电影| 天堂无码久久综合东京热| 久久久国产视频| 国产精品久久久福利| 久久精品人妻一区二区三区| 国产日产久久高清欧美一区| 久久精品国产99久久丝袜| 国产69精品久久久久99尤物| 伊人久久大香线蕉精品| 国产99久久久国产精品小说| 久久久中文字幕日本| 亚洲精品无码久久久久AV麻豆| 久久久久99精品成人片试看| 国产亚洲成人久久| 久久久无码一区二区三区| 久久精品中文闷骚内射| 97久久久久人妻精品专区| 久久免费视频观看| 国产成人无码精品久久久性色| 久久亚洲精品中文字幕三区| 精品久久香蕉国产线看观看亚洲| 久久精品国产秦先生| 久久精品国产精品亚洲人人| 亚洲精品无码专区久久同性男| 久久这里只有精品首页| 亚洲AV日韩AV天堂久久| 国产精品久久久久久久app| 久久久久久国产精品美女| 欧洲性大片xxxxx久久久| 久久这里的只有是精品23| 久久人人爽人人爽人人AV| 少妇被又大又粗又爽毛片久久黑人 | 中文成人无码精品久久久不卡| 欧美日韩精品久久久久| 97久久超碰国产精品2021| 久久精品国产亚洲av瑜伽| 久久无码国产专区精品| 亚洲国产成人久久综合一|