メモ Edit

コード生成 Edit

もっとシンプルなものにしよう。

レジスタ構成 Edit

Full NameShort NameComment
Stack Register PointerSRPスタックレジスタポインタ。
スタックレジスタの先頭アドレス。
言い換えるとSR00の場所。
Stack PointerSPスタックポインタ。現在のスタック位置。
Program CounterPCプログラムカウンタ。現在実行しているバイトコードのポインタ。
Program FunctionPFプログラムの関数オブジェクトのポインタ。デバッグ用。
Program LinePLプログラムのソースコードの行数。デバッグ用。
Link RegisterLRリンクレジスタ。戻り先のバイトコードのポインタ。
Function RegisterFR関数レジスタ。全部で16個。FR00 - FR16。

レジスタの概要 Edit

  • 1つのレジスタのサイズは8バイト。
  • 4バイトでもいいかなと思ったが,64bit環境でポインタが1レジスタで表現できなくなるため,8バイトにした。
  • ただし,メモリがきつきつの環境もあるので32bitモード用意する。その場合,64bitの整数・浮動小数,64bitのアドレス空間は扱えなくなる。
  • 1つのレジスタはUNIONで表現。
    すべてを展開すべてを収束
      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
    
     
    -
    |
    -
    |
    |
    |
    |
    |
    |
    |
    !
    !
     
    
    struct Register
    {
        union
        {
            u32 data32;
            u64 data64;
            s32 i32val;
            s64 i64val;
            f32 f32val;
            f64 f64val;
            void*  ptr; // 64bit環境だとこれは8バイト。
        };
    };
    

スタックレジスタ Edit

  • 計算の一時領域として使うレジスタはStackRegister(スタックレジスタ)呼び,SRと略す。
  • スタックレジスタ数は動的に変更し,最大で256。それを越える必要がある関数はコンパイルエラーとする。
  • SRP(Stack Register Pointer)からのオフセットがスタックレジスタの番号に相当する。
  • SR01ならSRP + 0x08のアドレスとなる。(32bitモードなら+0x04)
  • 通常,関数の先頭でFUNCET命令を使い関数で使用するスタックレジスタの数 x レジスタのサイズ分,スタックから確保し,その先頭アドレスをSRPに設定する。

変数とレジスタ Edit

  • ローカル変数は全てスタックレジスタに割り当てられる。
  • スコープを考慮してスタックレジスタの使用数はなるべく少なくて済むように最適化される。
  • 一時変数もスタックレジスタに割り当てられる。
    すべてを展開すべてを収束
      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
    
    -
    |
    -
    |
    |
    -
    |
    !
    |
    -
    |
    !
    |
    |
    |
    |
    !
    !
    
    utility Hoge {
    static void func()
    {
        int a; // SR01
        int b; // SR02
        {
            int c; // SR03
        }
        int d; // SR02
        {
            int e; // SR03
        }
        d = (a + b) * d; 
        // (a + b)が一時変数としてSR03に格納される
        // SR03 = a + b; 
        // SR02 = R03 * R02;
    }
    };

戻り値とレジスタ Edit

  • 戻り値はFR00に格納される。
  • FUNCRT命令が実行されるとSR00の値はFR00にコピーされる。
    すべてを展開すべてを収束
      1
      2
      3
      4
      5
      6
      7
      8
    
     
    -
    |
    -
    |
    !
    !
     
    
    utility Hoge
    {
        static int GetOne()
        {
            return 1; // FR00 = 1
        }
    };
    

引数とレジスタ Edit

  • 引数は関数レジスタのFR01から順番にレジスタに割り当てられる。
  • 非staticなメンバ関数はFR01にthisポインタが割り当てられる。
  • 関数レジスタは16個しか用意されていないので,引数の最大数はメンバ関数で14個,非メンバ関数は15個となります。(FR00は戻り値として使うため,引数に使用できない)
    すべてを展開すべてを収束
      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
    
     
    -
    |
    |
    |
    |
    |
    -
    |
    |
    !
    !
     
    
    pod Vector3
    {
        float x;
        float y;
        float z;
     
        void func(float addValue)
        {
            // FR01 : this
            // FR02 : addValue
        }
    }
    

アセンブラのイメージ Edit

すべてを展開すべてを収束
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 
-
|
!
 
-
|
|
!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0:int add(int a, int b)
1:{
2:    return a + b;
3:}
4:void func()
5:{
6:   int i = 3;
7:   i = add(i , 4);
8:}
 
# 命令コード
Instruction:
  add:
    DFUNC  0x0000
    DLINE  1 // '{'の位置
    FUNCET 0x03 0x03  
    DLINE  2
    ADDI32 R00 R01 R02
    DLINE  3 // '}'の位置
    FUNCLV 0x03       
 
  func:
    DFUNC   0x0001
    DLINE   5
    FUNCET  0x02 0x00
    DLINE   6
    LDSRC4  SR00 0x0000
    DLINE   7
    LDSRC4  SR01 0x0004
    LDFRSR  FR01 SR00 
    LDFRSR  FR02 SR01
    CALL    0x0000   
    LDRF    SR00 FR00
    FUNCLV  0x02
 
# コンパイル時に確定する定数のテーブル
ConstantTable:
  0x0000: 3
  0x0004: 4
 
SymbolTable:
  0x0000: int add(int,int)
  0x0004: void func()

命令コード Edit

  • どの命令コードも32bitで統一。
  • SRegおよびFRegはu8。
命令書式コメント
ロード
LDSRC1LDSRC4 SReg ConstantTableIndex(u16)ConstantTableの値を指定したスタックレジスタにロード
LDSRC2
LDSRC4
LDSRC8
LDSRSRLDSR SReg1 SReg2SReg2の値をSReg1にロード
LDSRSPLDSRSP SReg1 StackPointerOffset(u16)StackPointerから相対アドレス分移動したアドレスをReg1にロード
LDSRPTLDSRPT SReg1 SReg2SReg2の値をアドレスとみなし,SReg2が指す値を取得する
LDSROJLDSROJ SReg1 SReg2SReg2の値をobject型とみなし,SReg2が指すobjectの実体のアドレスのアドレスを取得する
LDFRSRLDFRSR FReg SRegSRegの値をFRegにロード
演算
ADDxxxADDI32 SReg1 SReg2 SReg3SReg1 = SReg2 + SReg3
SUBxxxSUBI32 SReg1 SReg2 SReg3SReg1 = SReg2 - SReg3
MULxxxMULS32 SReg1 SReg2 SReg3SReg1 = SReg2 * SReg3
DIVxxxMULS32 SReg1 SReg2 SReg3SReg1 = SReg2 / SReg3
MODxxxMODS32 SReg1 SReg2 SReg3SReg1 = SReg2 % SReg3
関数あれこれ
FUNCETFUNCIN AllocSRegNum CopyFRegNumFunction Enter.
まずスタックに現在のSPR,LR,PL,PFをつみ,SPを変更する。
AllocSRegNumで指定された数,スタックレジスタを確保し,SPRに設定する。SPを変更する。
CopyFRegNumで指定された数,スタックレジスタにFRに内容をコピーする。
FUNCLVFUNCRT FreeSRegNumFunction Leave.
FreeSRegNumで指定された数,スタックレジスタを解放しSPを変更する。
PF,PL,LR,SPR,をスタックから取り出し設定する。SPも変更する。
PCにLRを代入する。
PUSHPUSH PushStackSize(u16)PushStackSize分,SPを移動する。SP -= PushStackSize。
POPPOP PopStackSize(u16)PopStackSize分,SPを移動する。SP += PopStackSize。
CALLCALL SymbolTableIndex(u16)LRにPCを代入する。
SymbolTableIndexが示す関数の先頭バイトコードをPCに設定する。
デバッグ
DLINEDLINE ConstantValue(u24)デバッグ情報のプログラム行数を代入するための命令。
PLにConstantValueを代入する。
DFUNCDFUNC SymbolTableIndex(u16)デバッグ情報の関数オブジェクトを代入するための命令。
PFにSymbolTableIndexが示すアドレスを代入する。

オブジェクトファイル Edit

  • Cでいう.oのファイル。

含まれるもの

  • モジュール名
  • 定数テーブル
  • シンボルテーブル
  • シンボル一覧
  • シンボル解決情報

モジュール名 Edit

  • モジュール名が文字列として格納される。

定数テーブル Edit

  • 必要な定数テーブルの長さ。
  • コンパイル時に解決されている定数郡。
  • .oのファイルサイズ縮小のために,コンパイル時に解決されている定数郡は定数テーブルの先頭に置いておく。
  • そうしておくことで,リンク時に解決される定数郡のデータ量が.oから削減される。(.sbssと同じ考え方)

シンボルテーブル Edit

  • 必要なシンボルテーブルの長さのみ格納される。

シンボル一覧 Edit

ユーザー定義型リスト
  • ユーザー定義型についての情報が0個以上格納されている。
    項目内容
    シンボルのパス文字列BaseLib.Math.Vector3
    継承しているクラスのパス文字列Foo
    実装しているインターフェースのリスト別項:インターフェースのリストを参照
    変数リスト別項:変数リストを参照
    関数リスト別項:関数リストを参照
インターフェースのリスト
  • インターフェースについての情報が0個以上格納されている。
    項目内容
    シンボルのパス文字列BaseLib.IDrawable
変数リスト
  • 変数についての情報が0個以上格納されている。
    項目内容
    型を示すシンボルのパス文字列float
    シンボル名文字列x
    staticフラグbool(staticか否か)
    readonlyフラグbool(readonlyか否か)
    constフラグbool(constか否か)
関数リスト
  • 関数についての情報が0個以上格納されている。
    項目内容
    シンボル名文字列add
    戻り値の型を示すシンボルのパス文字列BaseLib.Math.Vector3
    戻り値のconstフラグbool(constか否か)
    引数リスト別項:引数リストを参照
    staticフラグbool(staticか否か)
    constフラグbool(constか否か)
    命令コードバイトコード
引数リスト
  • 引数についての情報が0個以上格納されている。
    項目内容
    型を示すシンボルのパス文字列float
    constフラグbool(constか否か)
    refフラグbool(refか否か)

シンボル解決情報 Edit

  • シンボルの種類は変数・関数・ユーザー定義型の3つ。
変数
項目内容
代入先定数テーブル or シンボルテーブル-
シンボルパス解決するシンボルのパスBaseLib.Math.Vector3.x
シンボルの何を取得するのか。・変数オブジェクト(SSVariableのポインタ)
・サイズ
・先頭からのオフセット距離
-
関数
項目内容
代入先シンボルテーブル-
シンボルパス解決するシンボルのパスBaseLib.Math.Vector3.add
引数リスト引数の型のリスト
属性const,staticなどの属性
シンボルの何を取得するのか。・関数オブジェクト(SSFunctionのポインタ)-
ユーザー定義型
項目内容
代入先定数テーブル-
シンボルパス解決するシンボルのパスBaseLib.Math.Vector3
シンボルの何を取得するのか。・サイズ-

意味解析 Edit

構文解析が終わった後,コード生成より前にやること。

  • ModuleをModuleReposに登録。
  • TypePathを解決し,型にリンクさせる
  • 関数名・変数名がだぶっていないかチェック。
  • 定数(enum,immutable)の確定
  • ユーザー定義型のサイズの決定
  • ユーザー定義型の静的・非静的メンバ変数の位置を決定
  • 自動生成関数の生成
  • 関数のレジスタ割り当ての決定
  • 関数の定数テーブルを作成
  • 関数の非値型のスタックマッピングおよびスタックサイズを決定

道のり Edit

  • 意味解析
    • まずutilityと関数だけにしぼる
    • 全てのModuleをシンボルツリーに登録
    • 全ての型をシンボルツリーに登録
    • 関数をシンボルツリーに登録。
    • 関数の中身を意味解析
      • 関数の中身のTypePathやIdentPathのシンボルを解決
      • 意味解析したStatementに置き換え。

仕様変更履歴 Edit

2010/07/29
  • prototype moduleの概念を追加。
  • classの代入演算子オーバーロードを禁止に。D言語準拠にした。
  • オブジェクトハンドルの概念をなくした。
  • isと!isを追加。セットでIdentityExpressionも追加。

    ホーム 一覧 検索 最終更新 バックアップ リンク元   ヘルプ   最終更新のRSS