LoginSignup
10
8

More than 5 years have passed since last update.

GCC treeの視覚化

Posted at

GCCのtreeを理解するために、treeをgraphvizで視覚化してみました。

treeはgccのfront endで使われている構文木を表すデータ構造です。
最初はテキストエディタでgraphvizのdot形式で書いてみたけど、変換ツールがあったので、変換ツールを使ってみました。

まとめ

  • gccのオプション -fdump-tree-original-raw で 最適化前のtreeをdumpすることができる。
  • treeのdumpは独自のフォーマットで関数毎に生成する。
  • 関数が一つの場合に、treeのdumpをgraphvizのdot形式に変換するツールがある。
  • 変換したdotファイルをgraphvizで描画するとtreeが視覚化できる。

図の読み方は別エンントリで説明する予定とします。

テキストエディタで書いてみた

  • 変数宣言のtreeを GCC 的语法树结构 の図を見ながらgraphvizで図にしてみました。 その話は割愛します

変換ツールを使ってみた

変換手順

  • 上記のURLからpre.awkとtree.awkを入手する。
  • gawk (GNU awk)をインストールする。
  • pre.awkとtree.awkの先頭にあるawkのpathを修正する。
  • chmod で実行権限を付加する。
  • gcc のオプション -fdump-tree-original-raw を使って、パース直後のtreeをdumpする。
gcc -fdump-tree-original-raw test.c
  • test.c.003t.originalが生成される。
  • 変換ツールpre.awkとtreeviz.awkを使う。
./pre.awk test.c.003t.original |./treeviz.awk  >test.dot
  • graphvizでグラフを描画する。
dot -Tpng test.dot  -o test.png
  • test.pngを表示する

test.png

  • test.cの内容
int main() {
    return 0;
}
  • test.c.003t.original の内容内容
    • treeのdumpは関数毎に出力される。
;; Function main (null)
;; enabled by -tree-original

@1      bind_expr        type: @2       body: @3      
@2      void_type        name: @4       algn: 8       
@3      return_expr      type: @2       expr: @5      
@4      type_decl        name: @6       type: @2      
@5      modify_expr      type: @7       op 0: @8       op 1: @9      
@6      identifier_node  strg: void     lngt: 4       
@7      integer_type     name: @10      size: @11      algn: 32      
                         prec: 32       sign: signed   min : @12     
                         max : @13     
@8      result_decl      type: @7       scpe: @14      srcp: test.c:1      
                         note: artificial              size: @11     
                         algn: 32      
@9      integer_cst      type: @7       low : 0       
@10     type_decl        name: @15      type: @7      
@11     integer_cst      type: @16      low : 32      
@12     integer_cst      type: @7       high: -1       low : -2147483648 
@13     integer_cst      type: @7       low : 2147483647 
@14     function_decl    name: @17      type: @18      srcp: test.c:1      
                         link: extern  
@15     identifier_node  strg: int      lngt: 3       
@16     integer_type     name: @19      size: @20      algn: 64      
                         prec: 64       sign: unsigned min : @21     
                         max : @22     
@17     identifier_node  strg: main     lngt: 4       
@18     function_type    unql: @23      size: @11      algn: 32      
                         retn: @7      
@19     identifier_node  strg: bitsizetype             lngt: 11      
@20     integer_cst      type: @16      low : 64      
@21     integer_cst      type: @16      low : 0       
@22     integer_cst      type: @16      low : -1      
@23     function_type    size: @11      algn: 32       retn: @7  

変換ツールのソースコード調査

pre.awk
#! /usr/local/bin/gawk -f
/^[^;]/{
  gsub(/^@/, "~@", $0);
  gsub(/( *):( *)/, ":", $0);
  print;
}
  • ソースコードの説明
    • RSを改行から@~に変えるための準備。
    • :前後の余計な空白を削除
treeviz.awk
#! /usr/local/bin/gawk -f
BEGIN {RS = "~@"; printf "digraph G {\n  node [shape = record];";}
/^[0-9]/{
  gsub("op ", "op");
  s = sprintf("%s [label = \"{%s | {", $1, $1);
  for(i = 2; i < NF ; i++)
    s = s sprintf("%s | ", $i);  
  s = s sprintf("%s}}\"];\n", $i);

  $0 = s;
  while (/([a-zA-Z0-9]+):@([0-9]+)/){
    format = sprintf("<\\1>\\1 \\3\n   %s:\\1 -> \\2;", $1);
    $0 = gensub(/([a-zA-Z0-9]+):@([0-9]+)(.*)$/, format, "g"); 
  };
  printf "    %s\n", $0;
}
END {print "}"}
  • ソースコードの説明
    • 複数行にまたがるノードを簡単に取り扱うために、awkのRSを改行から"~@"に変更、こうするとノードと行が1対1に対応する。
    • graphvizのヘッダー部分を表示
    • 要素名に"op 1"のように空白があると面倒なので、空白を除去
    • ノードのラベルの先頭を追加
    • 各要素を取り出し、ラベルに追加
    • ラベルを終了
    • ラベルのうち、リンクを張る必要があるものを抽出
    • リンクをはるものはラベルを から に修正
    • リンクを追加
  • 変更箇所
    • 要素名に"op 1"のように空白があると面倒なので、空白を除去
    • リンクを張る必要のある要素を抽出する正規表現を変更
  • 制限事項
    • このツールはdumpファイルにtreeが1つの場合にのみ動作する。複数の関数があると、同じ名前のノードが複数存在してしまうので変換に失敗する。

gccの-fdump-tree-original-rawの意味

-fdump-tree-switch
-fdump-tree-switch-options
-fdump-tree-switch-options=filename
Control the dumping at various stages of processing the intermediate language tree to a file. 
The file name is generated by appending a switch-specific suffix to the source file name, and 
the file is created in the same directory as the output file. In case of =filename option, the 
dump is output on the given file instead of the auto named dump files. If the ‘-options’ form is 
used, options is a list of ‘-’ separated options which control the details of the dump. Not all 
options are applicable to all dumps; those that are not meaningful are ignored. The following 
options are available

...

‘raw’
Print a raw representation of the tree. By default, trees are pretty-printed into a C-like representation. 

...

‘original’
Dump before any tree based optimization, to file.original. 
  • dumpの実装は、dumpfile.cにあります。
  • -fdumpオプションの解析は dumpfile.c の dump_switch_p_1()で行います。
  • -fdumpオプションはテーブル dump_files[] と dump_options[]の文字列を比較する。
    • dump_files はtree-original の部分の文字列
    • dump_optionsはrawの部分の文字列
  • 過去のマニュアルを見たところ gcc-4.x以降ならCで-fdump-tree-original-raw が使えるようです。

参考

10
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
8