SATySFiのプリミティブ向けコード生成のメモ

SATySFi本体では、`/tools/gencode/vminst.ml`というファイルに全てのプリミティブが定義されており、gencodeというツールを実行することでさまざまなOCamlのソースコードを生成することができます。

gencodeは、SATySFiのソースツリーの頂点で`dune build`等とすると、`_build/default/tools/gencode/gencode.exe`というファイルとして生成されます。

`gencode.ml`を見ると

```tools/gencode/gencode.ml
  let opts =
    [
      ("--gen-vm"             , gen_vminstrs       );
      ("--gen-ir-0"           , gen_ircases_0      );
      ("--gen-ir-1"           , gen_ircases_1      );
      ("--gen-insttype"       , gen_insttype       );
      ("--gen-attype"         , gen_attype         );
      ("--gen-codetype"       , gen_codetype       );
      ("--gen-unliftcode"     , gen_unliftcode     );
      ("--gen-interps-0"      , gen_interps_0      );
      ("--gen-interps-1"      , gen_interps_1      );
      ("--gen-pdf-mode-prims" , gen_pdf_mode_prims );
      ("--gen-text-mode-prims", gen_text_mode_prims);
    ]
  in
```

となっているので、11個のオプションが使えることがわかります。これらの出力を試してみます。
しかし出力は膨大になりすべて掲載できないので、`linear-transform-graphics`というプリミティブに注目し、これに関連する部分のみを抜き出すことにします。

# まずは定義

まずは`vminst.ml`に書かれている`linear-transform-graphics`の定義の部分を抜き出します。

```tools/gencode/vminst.ml
    ; inst "PrimitiveLinearTransformGraphics"
        ~name:"linear-transform-graphics"
        ~type_:{|
~% (tFL @-> tFL @-> tFL @-> tFL @-> tGR @-> tGR)
|}
        ~fields:[
        ]
        ~params:[
          param "a" ~type_:"float";
          param "b" ~type_:"float";
          param "c" ~type_:"float";
          param "d" ~type_:"float";
          param "grelem" ~type_:"graphics_element";
        ]
        ~is_pdf_mode_primitive:true
        ~code:{|
make_graphics (GraphicD.make_linear_trans (a, b, c, d) grelem)
|}
```

# 各オプションをつけてgencodeを実行したときの出力

## gen-vm

```ocaml
  | OpPrimitiveLinearTransformGraphics ->
      begin
        match stack with
        | (_tmp0, _) :: (BaseConstant(BCFloat(d)), _) :: (BaseConstant(BCFloat(c)), _) :: (BaseConstant(BCFloat(b)), _)
 :: (BaseConstant(BCFloat(a)), _) :: stack ->
            let grelem = get_graphics_element _tmp0 in
            let ret =
              make_graphics (GraphicD.make_linear_trans (a, b, c, d) grelem)
            in exec (make_entry ret :: stack) env code dump

        | _ -> report_bug_vm "invalid argument for OpPrimitiveLinearTransformGraphics"
      end
```

`--gen-vm`で生成されたファイル`_build/default/src/__vm.gen.ml`は以下のファイルから参照されています。`exec_op`という関数の実装として使われるようですね。

```src/frontend/bytecomp/vm.cppo.ml
and exec_op (op : instruction) (stack : stack) (env : vmenv) (code : instruction list) dump =
  match op with
    (* ... *)
#include "__vm.gen.ml"
```

## gen-ir-0

```ocaml
    | PrimitiveLinearTransformGraphics(p1, p2, p3, p4, p5) ->
        transform_0_primitive env [p1; p2; p3; p4; p5] OpPrimitiveLinearTransformGraphics
```

`--gen-ir-0`で生成されたファイル`_build/default/src/__ir_0.gen.ml`は以下のファイルから参照されています。`transform_0`という関数の実装として使われるようですね。

```src/frontend/bytecomp/ir.cppo.ml
and transform_0_list (env : frame) (astlst : abstract_tree list) : ir list * frame =
  map_with_env transform_0 env astlst

and transform_0_primitive (env : frame) (astlst : abstract_tree list) (op : instruction) : ir * frame =
  let (irargs, env) = transform_0_list env astlst in
  (IRApplyPrimitive(op, List.length astlst, irargs), env)

and transform_0 (env : frame) (ast : abstract_tree) : ir * frame =
  let return ir = (ir, env) in
  match ast with
    (* ... *)
#include "__ir_0.gen.ml"
```

## gen-ir-1

```ocaml
    | PrimitiveLinearTransformGraphics(p1, p2, p3, p4, p5) ->
        code5 env (fun cv1 cv2 cv3 cv4 cv5 -> CdPrimitiveLinearTransformGraphics(cv1, cv2, cv3, cv4, cv5)) p1 p2 p3 p4 p5
```

`--gen-ir-1`で生成されたファイル`_build/default/src/__ir_1.gen.ml`は以下のファイルから参照されています。`transform_1`という関数の実装として使われるようですね。

```src/frontend/bytecomp/ir.cppo.ml
and code5 env cvf ast1 ast2 ast3 ast4 ast5 =
  let (ir1, env) = transform_1 env ast1 in
  let (ir2, env) = transform_1 env ast2 in
  let (ir3, env) = transform_1 env ast3 in
  let (ir4, env) = transform_1 env ast4 in
  let (ir5, env) = transform_1 env ast5 in
  let codef = function [cv1; cv2; cv3; cv4; cv5] -> cvf cv1 cv2 cv3 cv4 cv5 | _ -> report_bug_ir "code5" in
  (IRCodeCombinator(codef, 5, [ir1; ir2; ir3; ir4; ir5]), env)

and transform_1 (env : frame) (ast : abstract_tree) : ir * frame =
  match ast with
    (* ... *)
#include "__ir_1.gen.ml"
```

## gen-insttype

```ocaml
  | OpPrimitiveLinearTransformGraphics
```
`--gen-insttype`で生成されたファイル`_build/default/src/__insttype.gen.ml`は以下のファイルから参照されています。`instruction`というenumの定義として使われるようですね。

```src/frontend/types.cppo.ml
and instruction =
    (* ... *)
#include "__insttype.gen.ml"
```

## gen-attype

```ocaml
  | PrimitiveLinearTransformGraphics of abstract_tree * abstract_tree * abstract_tree * abstract_tree * abstract_tree
```

`--gen-attype`で生成されたファイル`_build/default/src/__attype.gen.ml`は以下のファイルから参照されています。`abstract_tree`というenumの定義として使われるようですね。

```src/frontend/types.cppo.ml
and abstract_tree =
    (* ... *)
#include "__attype.gen.ml"
```

## gen-codetype

```ocaml
  | CdPrimitiveLinearTransformGraphics of code_value * code_value * code_value * code_value * code_value
```

`--gen-codetype`で生成されたファイル`_build/default/src/__codetype.gen.ml`は以下のファイルから参照されています。`code_value`というenumの定義として使われるようですね。

```src/frontend/types.cppo.ml
and code_value =
    (* ... *)
#include "__codetype.gen.ml"
```
## gen-unliftcode

```ocaml
  | CdPrimitiveLinearTransformGraphics(code0, code1, code2, code3, code4) -> PrimitiveLinearTransformGraphics(aux code0, aux code1, aux code2, aux code3, aux code4)
```

`--gen-unliftcode`で生成されたファイル`_build/default/src/__unliftcode.gen.ml`は以下のファイルから参照されています。`unlift_code`という関数の実装として使われるようですね。

```src/frontend/types.cppo.ml
let rec unlift_code (code : code_value) : abstract_tree =
  let rec aux code =
    match code with
    (* ... *)
#include "__unliftcode.gen.ml"
```

## gen-interps-0

```ocaml
  | PrimitiveLinearTransformGraphics(_ast0, _ast1, _ast2, _ast3, _ast4) ->
      let a = get_float (interpret_0_value env _ast0) in
      let b = get_float (interpret_0_value env _ast1) in
      let c = get_float (interpret_0_value env _ast2) in
      let d = get_float (interpret_0_value env _ast3) in
      let grelem = get_graphics_element (interpret_0_value env _ast4) in
        return @@ begin
          make_graphics (GraphicD.make_linear_trans (a, b, c, d) grelem)
        end
```

`--gen-interps-0`で生成されたファイル`_build/default/src/__evaluator_0.gen.ml`は以下のファイルから参照されています。`interpret_0`という関数の実装として使われるようですね。

```src/frontend/evaluator.cppo.ml
and interpret_0_value env ast =
  fst @@ interpret_0 env ast

and interpret_0 (env : environment) (ast : abstract_tree) : syntactic_value * environment option =
  let return v = (v, None) in
  match ast with
    (* ... *)
#include "__evaluator_0.gen.ml"
```

## gen-interps-1

```ocaml
  | PrimitiveLinearTransformGraphics(_ast0, _ast1, _ast2, _ast3, _ast4) ->
      let _code0 = interpret_1_value env _ast0 in
      let _code1 = interpret_1_value env _ast1 in
      let _code2 = interpret_1_value env _ast2 in
      let _code3 = interpret_1_value env _ast3 in
      let _code4 = interpret_1_value env _ast4 in
      return @@ CdPrimitiveLinearTransformGraphics(_code0, _code1, _code2, _code3, _code4)
```

`--gen-interps-1`で生成されたファイル`_build/default/src/__evaluator_1.gen.ml`は以下のファイルから参照されています。`interpret_1`という関数の実装として使われるようですね。

```src/frontend/evaluator.cppo.ml
and interpret_1_value env ast =
  fst @@ interpret_1 env ast

and interpret_1 (env : environment) (ast : abstract_tree) : code_value * environment option =
  let return cd = (cd, None) in
  match ast with
    (* ... *)
#include "__evaluator_1.gen.ml"
```

## gen-pdf-mode-prims

```ocaml
        ("linear-transform-graphics",
          begin
            ~% (tFL @-> tFL @-> tFL @-> tFL @-> tGR @-> tGR)
          end,
          lambda5 (fun _v1 _v2 _v3 _v4 _v5 -> PrimitiveLinearTransformGraphics(_v1, _v2, _v3, _v4, _v5))
        );
```

`--gen-pdf-mode-prims`で生成されたファイル`_build/default/src/__primitives_pdf_mode.gen.ml`は以下のファイルから参照されています。`pdf_mode_table`という配列の要素として使われるようですね。

```src/frontend/evaluator.cppo.ml
let pdf_mode_table =
  List.append general_table
    [
      ("inline-fil", ~% tIB, (fun _ -> base (BCHorz(HorzBox.([HorzPure(PHSOuterFil)])))));
      ("inline-nil", ~% tIB, (fun _ -> base (BCHorz([])))                               );
      ("omit-skip-after", ~% tIB, (fun _ -> base (BCHorz(HorzBox.([HorzOmitSkipAfter])))));
      ("block-nil" , ~% tBB, (fun _ -> base (BCVert([])))                               );
      ("clear-page", ~% tBB, (fun _ -> base (BCVert(HorzBox.([VertClearPage]))))        );

#include "__primitives_pdf_mode.gen.ml"
    ]
```

## gen-text-mode-prims

出力されない


`--gen-text-mode-prims`で生成されたファイル`_build/default/src/__primitives_text_mode.gen.ml`は以下のファイルから参照されています。`text_mode_table`という配列の要素として使われるようですね。

```src/frontend/evaluator.cppo.ml
let text_mode_table =
  List.append general_table
    [
#include "__primitives_text_mode.gen.ml"
    ]
```