/* Visits the blocks in dominator tree order, recursively. */ static void add_bb_facts(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshPlanned *p) { MVMint32 i, is_phi; /* Look for instructions that provide or propagate facts. */ MVMSpeshIns *ins = bb->first_ins; while (ins) { /* See if there's deopt and logged annotations, and if so add logged * facts and guards. */ MVMSpeshAnn *ann = ins->annotations; MVMSpeshAnn *ann_deopt_one = NULL; MVMSpeshAnn *ann_logged = NULL; while (ann) { switch (ann->type) { case MVM_SPESH_ANN_DEOPT_ONE_INS: ann_deopt_one = ann; break; case MVM_SPESH_ANN_LOGGED: ann_logged = ann; } ann = ann->next; } if (p && ann_deopt_one && ann_logged && ins->info->opcode != MVM_OP_speshresolve) log_facts(tc, g, bb, ins, p, ann_deopt_one, ann_logged); /* Look for ops that are fact-interesting. */ switch (ins->info->opcode) { case MVM_OP_set: copy_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[1].reg.orig, ins->operands[1].reg.i); break; case MVM_OP_create: create_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[1].reg.orig, ins->operands[1].reg.i); break; case MVM_OP_sp_fastcreate: case MVM_OP_sp_fastbox_i: case MVM_OP_sp_fastbox_bi: case MVM_OP_sp_fastbox_i_ic: case MVM_OP_sp_fastbox_bi_ic: case MVM_OP_sp_add_I: case MVM_OP_sp_sub_I: case MVM_OP_sp_mul_I: create_facts_with_type(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ((MVMSTable *)g->spesh_slots[ins->operands[2].lit_i16])->WHAT); break; case MVM_OP_clone: copy_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[1].reg.orig, ins->operands[1].reg.i); break; case MVM_OP_box_s: case MVM_OP_box_i: case MVM_OP_box_n: { MVMSpeshFacts *target_facts = &(g->facts[ins->operands[0].reg.orig][ins->operands[0].reg.i]); create_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[2].reg.orig, ins->operands[2].reg.i); target_facts->flags |= MVM_SPESH_FACT_KNOWN_BOX_SRC; break; } case MVM_OP_coerce_sI: { MVMSpeshFacts *target_facts = &(g->facts[ins->operands[0].reg.orig][ins->operands[0].reg.i]); create_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[2].reg.orig, ins->operands[2].reg.i); break; } case MVM_OP_add_I: case MVM_OP_sub_I: case MVM_OP_mul_I: case MVM_OP_div_I: case MVM_OP_mod_I: create_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[3].reg.orig, ins->operands[3].reg.i); break; case MVM_OP_neg_I: case MVM_OP_abs_I: create_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[2].reg.orig, ins->operands[2].reg.i); break; case MVM_OP_nativecallcast: create_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[2].reg.orig, ins->operands[2].reg.i); break; case MVM_OP_trunc_u16: case MVM_OP_trunc_i16: trunc_i16_facts(tc, g, ins); break; case MVM_OP_coerce_ui: case MVM_OP_coerce_iu: trunc_i16_facts(tc, g, ins); break; case MVM_OP_bootint: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTInt); break; case MVM_OP_bootnum: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTNum); break; case MVM_OP_bootstr: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTStr); break; case MVM_OP_bootarray: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTArray); break; case MVM_OP_bootintarray: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTIntArray); break; case MVM_OP_bootnumarray: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTNumArray); break; case MVM_OP_bootstrarray: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTStrArray); break; case MVM_OP_boothash: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTHash); break; case MVM_OP_hllboolfor: { MVMSpeshOperand *name_op = &ins->operands[1]; MVMSpeshFacts *namefacts = &g->facts[name_op->reg.orig][name_op->reg.i]; if (namefacts->writer && namefacts->writer->info->opcode == MVM_OP_const_s) { MVMString *hllname = MVM_cu_string(tc, g->sf->body.cu, ins->operands[1].lit_str_idx); MVMHLLConfig *hll = MVM_hll_get_config_for(tc, hllname); if (hll->true_value && hll->false_value && STABLE(hll->true_value)->WHAT == STABLE(hll->false_value)->WHAT) create_facts_with_type(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, STABLE(hll->true_value)->WHAT); } break; } case MVM_OP_hllbool: { MVMHLLConfig *hll = g->sf->body.cu->body.hll_config; if (hll->true_value && hll->false_value && STABLE(hll->true_value)->WHAT == STABLE(hll->false_value)->WHAT) create_facts_with_type(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, STABLE(hll->true_value)->WHAT); break; } case MVM_OP_hllboxtype_i: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->int_box_type); break; case MVM_OP_hllboxtype_n: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->num_box_type); break; case MVM_OP_hllboxtype_s: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->str_box_type); break; case MVM_OP_hlllist: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->slurpy_array_type); break; case MVM_OP_hllhash: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->slurpy_hash_type); break; case MVM_OP_decont: decont_facts(tc, g, ins, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[1].reg.orig, ins->operands[1].reg.i); break; case MVM_OP_wval: wval_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[1].lit_i16, ins->operands[2].lit_i16); break; case MVM_OP_wval_wide: wval_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[1].lit_i16, ins->operands[2].lit_i64); break; case MVM_OP_sp_getwvalfrom: wvalfrom_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[1].lit_i16, ins->operands[2].lit_i64); break; case MVM_OP_sp_getspeshslot: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, (MVMObject *)g->spesh_slots[ins->operands[1].lit_i16]); break; case MVM_OP_iter: iter_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[1].reg.orig, ins->operands[1].reg.i); break; case MVM_OP_newexception: create_facts_with_type(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTException); break; case MVM_OP_getlexref_i: case MVM_OP_getlexref_i32: case MVM_OP_getlexref_i16: case MVM_OP_getlexref_i8: case MVM_OP_getlexref_u32: case MVM_OP_getlexref_u16: case MVM_OP_getlexref_u8: create_facts_with_type(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->int_lex_ref); break; case MVM_OP_getlexref_n: case MVM_OP_getlexref_n32: create_facts_with_type(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->num_lex_ref); break; case MVM_OP_getlexref_s: create_facts_with_type(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->str_lex_ref); break; case MVM_OP_getattrref_i: case MVM_OP_getattrsref_i: create_facts_with_type(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->int_attr_ref); break; case MVM_OP_getattrref_n: case MVM_OP_getattrsref_n: create_facts_with_type(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->num_attr_ref); break; case MVM_OP_getattrref_s: case MVM_OP_getattrsref_s: create_facts_with_type(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->str_attr_ref); break; case MVM_OP_atposref_i: create_facts_with_type(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->int_pos_ref); break; case MVM_OP_atposref_n: create_facts_with_type(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->num_pos_ref); break; case MVM_OP_atposref_s: create_facts_with_type(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->str_pos_ref); break; case MVM_OP_const_i64: case MVM_OP_const_i32: case MVM_OP_const_i16: case MVM_OP_const_i8: case MVM_OP_const_n64: case MVM_OP_const_n32: case MVM_OP_const_i64_32: case MVM_OP_const_i64_16: case MVM_OP_const_s: literal_facts(tc, g, ins); break; case MVM_OP_sp_getstringfrom: getstringfrom_facts(tc, g, ins); break; case MVM_OP_encode: create_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[3].reg.orig, ins->operands[3].reg.i); break; case MVM_OP_encoderep: create_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[4].reg.orig, ins->operands[4].reg.i); break; case MVM_OP_setdispatcher: case MVM_OP_setdispatcherfor: g->sets_dispatcher = 1; break; case MVM_OP_sp_guard: case MVM_OP_sp_guardconc: case MVM_OP_sp_guardtype: case MVM_OP_sp_guardobj: case MVM_OP_sp_guardjustconc: case MVM_OP_sp_guardjusttype: sp_guard_facts(tc, g, bb, ins); break; default: if (ins->info->opcode == (MVMuint16)-1) discover_extop(tc, g, ins); } ins = ins->next; } /* Visit children. */ for (i = 0; i < bb->num_children; i++) add_bb_facts(tc, g, bb->children[i], p); }
/* Visits the blocks in dominator tree order, recursively. */ static void add_bb_facts(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMint32 cur_deopt_idx) { MVMint32 i, is_phi; /* Look for instructions that provide or propagate facts. */ MVMSpeshIns *ins = bb->first_ins; while (ins) { /* See if there's a deopt annotation, and sync cur_deopt_idx. */ MVMSpeshAnn *ann = ins->annotations; while (ann) { if (ann->type == MVM_SPESH_ANN_DEOPT_ONE_INS || ann->type == MVM_SPESH_ANN_DEOPT_ALL_INS) { cur_deopt_idx = ann->data.deopt_idx; break; } ann = ann->next; } /* Look through operands for reads and writes. */ is_phi = ins->info->opcode == MVM_SSA_PHI; for (i = 0; i < ins->info->num_operands; i++) { /* Reads need usage tracking; if the read is after a deopt point * relative to the write then give it an extra usage bump. */ if ((is_phi && i > 0) || (!is_phi && (ins->info->operands[i] & MVM_operand_rw_mask) == MVM_operand_read_reg)) { MVMSpeshFacts *facts = &(g->facts[ins->operands[i].reg.orig][ins->operands[i].reg.i]); facts->usages += facts->deopt_idx == cur_deopt_idx ? 1 : 2; } /* Writes need the current deopt index and the writing instruction * to be specified. */ if ((is_phi && i == 0) || (!is_phi && (ins->info->operands[i] & MVM_operand_rw_mask) == MVM_operand_write_reg)) { MVMSpeshFacts *facts = &(g->facts[ins->operands[i].reg.orig][ins->operands[i].reg.i]); facts->deopt_idx = cur_deopt_idx; facts->writer = ins; } } /* Look for ops that are fact-interesting. */ switch (ins->info->opcode) { case MVM_OP_inc_i: case MVM_OP_inc_u: case MVM_OP_dec_i: case MVM_OP_dec_u: /* These all read as well as write a value, so bump usages. */ g->facts[ins->operands[0].reg.orig][ins->operands[0].reg.i - 1].usages++; break; case MVM_OP_set: copy_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[1].reg.orig, ins->operands[1].reg.i); break; case MVM_OP_create: create_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[1].reg.orig, ins->operands[1].reg.i); break; case MVM_OP_box_s: case MVM_OP_box_i: case MVM_OP_box_n: { MVMSpeshFacts *target_facts = &(g->facts[ins->operands[0].reg.orig][ins->operands[0].reg.i]); create_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[2].reg.orig, ins->operands[2].reg.i); target_facts->flags |= MVM_SPESH_FACT_KNOWN_BOX_SRC; break; } case MVM_OP_add_I: case MVM_OP_sub_I: case MVM_OP_mul_I: case MVM_OP_div_I: case MVM_OP_mod_I: create_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[3].reg.orig, ins->operands[3].reg.i); break; case MVM_OP_neg_I: case MVM_OP_abs_I: create_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[2].reg.orig, ins->operands[2].reg.i); break; case MVM_OP_bootint: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTInt); break; case MVM_OP_bootnum: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTNum); break; case MVM_OP_bootstr: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTStr); break; case MVM_OP_bootarray: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTArray); break; case MVM_OP_bootintarray: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTIntArray); break; case MVM_OP_bootnumarray: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTNumArray); break; case MVM_OP_bootstrarray: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTStrArray); break; case MVM_OP_boothash: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTHash); break; case MVM_OP_hllboxtype_i: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->int_box_type); break; case MVM_OP_hllboxtype_n: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->num_box_type); break; case MVM_OP_hllboxtype_s: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->str_box_type); break; case MVM_OP_hlllist: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->slurpy_array_type); break; case MVM_OP_hllhash: object_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, g->sf->body.cu->body.hll_config->slurpy_hash_type); break; case MVM_OP_decont: decont_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[1].reg.orig, ins->operands[1].reg.i); break; case MVM_OP_wval: wval_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[1].lit_i16, ins->operands[2].lit_i16); break; case MVM_OP_wval_wide: wval_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[1].lit_i16, ins->operands[2].lit_i64); break; case MVM_OP_iter: iter_facts(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, ins->operands[1].reg.orig, ins->operands[1].reg.i); break; case MVM_OP_newexception: create_facts_with_type(tc, g, ins->operands[0].reg.orig, ins->operands[0].reg.i, tc->instance->boot_types.BOOTException); break; case MVM_OP_const_i64: case MVM_OP_const_i32: case MVM_OP_const_i16: case MVM_OP_const_i8: case MVM_OP_const_n64: case MVM_OP_const_n32: case MVM_OP_const_i64_32: case MVM_OP_const_i64_16: case MVM_OP_const_s: literal_facts(tc, g, ins); break; case MVM_OP_sp_log: { MVMuint16 po = ins->prev ? ins->prev->info->opcode : bb->pred[0]->last_ins->info->opcode; if (po != MVM_OP_getlexstatic_o && po != MVM_OP_getlexperinvtype_o) log_facts(tc, g, bb, ins); break; } default: if (ins->info->opcode == (MVMuint16)-1) discover_extop(tc, g, ins); } ins = ins->next; } /* Visit children. */ for (i = 0; i < bb->num_children; i++) add_bb_facts(tc, g, bb->children[i], cur_deopt_idx); }