iseq_insns_unification
命令融合。こちらも同じく現在はOFFになってるみたいです。一応ソースだけ読んでみました。
さっき見たオペランド融合は、よくある「命令+オペランド」の組を1個の専用融合命令に置き換えてしまう最適化でした。こっちの命令融合というのは、よく連続する命令、「命令+命令」の組を1個の専用融合命令に置き換えてしまう最適化です。仕組み的には3命令以上の連続「命令+命令+命令+...」も一気に融合するケースも考えて作られていましたが、実際には使われていない模様。
融合したい命令+命令の組は、ビルド時に定義ファイル"opt_insn_unif.def"から自動生成されます。(自動生成スクリプトはオペランド融合のものと同じ、"tool/insns2vm.rb"。)定義ファイルの中身はこんな感じで、
putobject putobject putobject putstring putobject setlocal putobject setdynamic putstring putstring putstring putobject putstring setlocal putstring setdynamic ...
たとえば最初の行はputobjectの直後にまたputobjectするパターンをまとめる、UNIFIED_putobject_putobject という専用命令を定義しています。この定義に対応して、テーブルが自動生成されます(Makefileと同じディレクトリの、optunifs.incというファイルです)。
static int UNIFIED_putobject_0[] = { BIN(UNIFIED_putobject_putobject), 3, BIN(putobject)}; static int UNIFIED_putobject_1[] = { BIN(UNIFIED_putobject_putstring), 3, BIN(putstring)}; static int UNIFIED_putobject_2[] = { BIN(UNIFIED_putobject_setlocal), 3, BIN(setlocal)}; static int UNIFIED_putobject_3[] = { BIN(UNIFIED_putobject_setdynamic), 3, BIN(setdynamic)}; ... static int *UNIFIED_putobject[] = {(int *)5, UNIFIED_putobject_0, UNIFIED_putobject_1, UNIFIED_putobject_2, UNIFIED_putobject_3}; ... static int **unified_insns_data[] = { 0, UNIFIED_getlocal, 0, ... 0, 0, UNIFIED_putobject, UNIFIED_putstring, 0, ...
unified_insns_data[1個目の命令] とテーブルをひくと、1個目の命令に対応する融合命令のリストが手に入ります。そのリストでループをまわして、次の命令と2個目の命令で一致するものがあったら置き換え、なければ何もしない、という処理で最適化が行われます。
static int iseq_insns_unification(yarv_iseq_t *iseq, LINK_ANCHOR *anchor) { list = FIRST_ELEMENT(anchor); while (list) { if (list->type == ISEQ_ELEMENT_INSN) { iobj = (INSN *)list; id = iobj->insn_id; if (unified_insns_data[id] != 0) { int **entry = unified_insns_data[id]; }
テーブルを引いて、
for (j = 1; j < (int)entry[0]; j++) { int *unified = entry[j]; LINK_ELEMENT *li = list->next;
ループを回して、
for (k = 2; k < unified[1]; k++) { if (li->type != ISEQ_ELEMENT_INSN || ((INSN *)li)->insn_id != unified[k]) { goto miss; } li = li->next; }
次の命令ととマッチしていたら
/* matched */ niobj = new_unified_insn(iseq, unified[0], unified[1] - 1, list); ... 続く ...
置き換え、となっています。