ひとり勉強会

ひとり楽しく勉強会

iseq_peephole_optimize

コンパイル結果を局所的に見て、ちょこちょこっと命令列を効率の良いものに書き換えていく最適化を、ピープホール最適化(覗き穴最適化)と言います。現在のYARVでは、無駄なジャンプ命令を見つけては書き換えるというピープホール最適化を行っています。

static int
iseq_peephole_optimize(yarv_iseq_t *iseq, LINK_ELEMENT *list)
{
    INSN *iobj = (INSN *)list;
  again:

iseqという命令列の中の、iobjという命令を最適化しようと試みます。まずは、無条件ジャンプ命令だった場合の最適化。

  if (iobj->insn_id == BIN(jump)) {
	INSN *niobj, *diobj, *piobj;
	diobj = (INSN *)get_destination_insn(iobj);
	niobj = (INSN *)get_next_insn(iobj);

    if (diobj == niobj) {
      REMOVE_ELEM(&iobj->link);
    }

直後の命令にジャンプするような命令は無駄です。別にジャンプしなくても放っておけば直後の命令に行きますから。というわけで、そういう命令を見つけたら削除しています。

  else if (iobj != diobj && diobj->insn_id == BIN(jump)) {
    OPERAND_AT(iobj, 0) = OPERAND_AT(diobj, 0);
    goto again;
  }

ジャンプ先がさらにジャンプ命令だった場合、2段ジャンプするよりは、1回で最終目的地までジャンプした方が効率的ですねという最適化。同じ効率化は、条件ジャンプ命令(branchif/branchunless)命令の先が無条件ジャンプ命令だった場合、にも使えます。

  if (iobj->insn_id == BIN(branchif) ||
    iobj->insn_id == BIN(branchunless)) {
    INSN *nobj = (INSN *)get_destination_insn(iobj);
      if (nobj->insn_id == BIN(jump)) {
        OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0);
    }
  }

などなど。この辺りについては、YARV Maniacs 【第7回】 にささださんによる解説があります。