OpenJDK Internals 1.0 documentation

C1コンパイラのHIR最適化

«  C1コンパイラの内部構造   ::   Contents   ::   Devirtualization  »

C1コンパイラのHIR最適化

HIR Optimizationは、BytecodeからHIRへ変換終わった後に行う

c1_Compilation.cpp::build_hir()

_hir->optimize();
  IR::optimize()
    opt.eliminate_conditional_expressions();
    opt.eliminate_blocks();
    opt.eliminate_null_checks();

eliminate_conditional_expressions

@todo 時間があればコードを追うこと

CE_Eliminator::block_do()が本体

ブロックの終端のifを取得
ifはint型かobject型か判定

true  block
false block
true_instruction
false_instruction

a = (b > c) ? b : c;

BB:
  if ... then BBn false BBm
BBn:
  const n
  goto BBs
BBm:
  const m
  goto BBs
BBs:
  phi [][]

CEE Java:

public static int CETest(int ret, int n,int  m) {
  ret += (n < m) ? n : m;
  return ret;
}

CEE HIR

B62:
  i179 = i103 - i76
  i180 = i178 - i151
  v186 = if i179 > i180 then B73 else B72  <-- replace  i186 = ifop (i179 > i180) ixx, iyy;
                                           <-- add      goto B74
B73:                                       <-- delete
  v188 = goto B74                          <-- delete
B72:                                       <-- delete
  v187 = goto B74                          <-- delete
B74:
  i189 = [i179,i180]                       <-- replace
  v190 = goto B70
B70:
  i191 = i151 + i189

GlobalValueNumbering

@todo 時間があればコードを追うこと

c1_ValueMap.hpp::GlobalValueNumbering(IR* ir)

ShortLoopOptimizer short_loop_optimizer(this);

for (int i = 1; i < num_blocks; i++) {
  BlockBegin* block = blocks->at(i);

  ...

  if (num_preds == 1) {
    // nothing to do here

  } else if (block->is_set(BlockBegin::linear_scan_loop_header_flag)) {
    // block has incoming backward branches -> try to optimize short loops
    if (!short_loop_optimizer.process(block)) {          <-- ループは特別に処理
      // loop is too complicated, so kill all memory loads because there might be
      // stores to them in the loop
      current_map()->kill_memory();
    }

  } else {
    // only incoming forward branches that are already processed
    for (int j = 0; j < num_preds; j++) {
      BlockBegin* pred = block->pred_at(j);
      ValueMap* pred_map = value_map_of(pred);

      if (pred_map != NULL) {
        // propagate killed values of the predecessor to this block
        current_map()->kill_map(value_map_of(pred));
      } else {
        // kill all memory loads because predecessor not yet processed
        // (this can happen with non-natural loops and OSR-compiles)
        current_map()->kill_memory();
      }
    }
  }

  if (block->is_set(BlockBegin::exception_entry_flag)) {
    current_map()->kill_exception();
  }

  TRACE_VALUE_NUMBERING(tty->print("value map before processing block: "); current_map()->print());

  // visit all instructions of this block
  for (Value instr = block->next(); instr != NULL; instr = instr->next()) {
    assert(!instr->has_subst(), "substitution already set");

    // check if instruction kills any values
    instr->visit(this);

    if (instr->hash() != 0) {
      Value f = current_map()->find_insert(instr);  <-- ここがキモ
      if (f != instr) {
        assert(!f->has_subst(), "can't have a substitution");
        instr->set_subst(f);
        subst_count++;
      }
    }
  }

  // remember value map for successors
  set_value_map_of(block, current_map());
}

EscapeAnalysis

c1コンパイラからは呼ばれません!!!

wimmerの資料によるとclientからも呼ばれるようだが、昔のJDKもしくはSun JDKだけなのかもしれない。

Serverだとbreakを確認できた。

Sharkだとifdef切ってるけど、多分動かないんだろうと推測

C1コンパイラのLIR最適化

EdgeMoveOptimizer

c1_LinearScan.cpp::EdgeMoveOptimizer::optimize(BlockList* code)

EdgeMoveOptimizer optimizer = EdgeMoveOptimizer();

// ignore the first block in the list (index 0 is not processed)
for (int i = code->length() - 1; i >= 1; i--) {
  BlockBegin* block = code->at(i);

  if (block->number_of_preds() > 1 && !block->is_set(BlockBegin::exception_entry_flag)) {
    optimizer.optimize_moves_at_block_end(block);
  }
  if (block->number_of_sux() == 2) {
    optimizer.optimize_moves_at_block_begin(block);
  }
}

preds > 1 –> ブロックへのjumpが複数ある場合

CFGの合流ブロックとか、loopのheaderとか

code sink みたいな処理

sux == 2 –> ブロックからのjumpが複数ある場合

分岐とか、loopのback_edgeとか

code hoist みたいな処理

ControlFlowOptimizer

c1_LiearScan.cpp::ControlFlowOptimize::optimize(BlockList* code)

ControlFlowOptimizer optimizer = ControlFlowOptimizer();

// push the OSR entry block to the end so that we're not jumping over it.
BlockBegin* osr_entry = code->at(0)->end()->as_Base()->osr_entry();
if (osr_entry) {
  int index = osr_entry->linear_scan_number();
  assert(code->at(index) == osr_entry, "wrong index");
  code->remove_at(index);
  code->append(osr_entry);
}

optimizer.reorder_short_loops(code);
optimizer.delete_empty_blocks(code);
optimizer.delete_unnecessary_jumps(code);
optimizer.delete_jumps_to_return(code);

reorder_short_loops()

下記のようなケースをpost jumpっぽくする

end_block

B4 (V) [35, 50] -> B3 dom B3 sux: B3 pred: B3

__bci__use__tid____instr____________________________________
35   1    i19    31
38   1    i20    i15 * i19
41   2    i21    1
. 41   1    i22    i16 + i21
. 44   1    i23    a11[i16] (C)
. 45   1    i24    i20 + i23
. 47   1    i26    i17 + i21
. 50   0     27    goto B3 (safepoint)

header_block

B3 (LHbV) [28, 32] -> B5 B4 dom B1 sux: B5 B4 pred: B1 B4

__bci__use__tid____instr____________________________________
. 32   0     18    if i17 >= i12 then B5 else B4

delete_unnecessary_jumps()

last_branchが次のブロックへの飛び先だったらdelete

cmp branch1 branch2の場合、branch1が次のブロックへのjumpだったら、 branch1を書き換えて、condの条件を反転 branch2を削除

«  C1コンパイラの内部構造   ::   Contents   ::   Devirtualization  »