/* Turns a decont into a set, if we know it's not needed. Also make sure we * propagate any needed information. */ static void optimize_decont(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins) { MVMSpeshFacts *obj_facts = MVM_spesh_get_facts(tc, g, ins->operands[1]); if (obj_facts->flags & (MVM_SPESH_FACT_DECONTED | MVM_SPESH_FACT_TYPEOBJ)) { ins->info = MVM_op_get_op(MVM_OP_set); copy_facts(tc, g, ins->operands[0], ins->operands[1]); } else { MVMSpeshFacts *res_facts; if (obj_facts->flags & MVM_SPESH_FACT_KNOWN_TYPE && obj_facts->type) { MVMSTable *stable = STABLE(obj_facts->type); MVMContainerSpec const *contspec = stable->container_spec; if (contspec && contspec->fetch_never_invokes && contspec->spesh) { contspec->spesh(tc, stable, g, bb, ins); } } res_facts = MVM_spesh_get_facts(tc, g, ins->operands[0]); if (obj_facts->flags & MVM_SPESH_FACT_KNOWN_DECONT_TYPE) { res_facts->type = obj_facts->decont_type; res_facts->flags |= MVM_SPESH_FACT_KNOWN_TYPE; } if (obj_facts->flags & MVM_SPESH_FACT_DECONT_CONCRETE) res_facts->flags |= MVM_SPESH_FACT_CONCRETE; else if (obj_facts->flags & MVM_SPESH_FACT_DECONT_TYPEOBJ) res_facts->flags |= MVM_SPESH_FACT_TYPEOBJ; } }
/* Propagates information relating to decontainerization. */ static void decont_facts(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshIns *ins, MVMuint16 out_orig, MVMuint16 out_i, MVMuint16 in_orig, MVMuint16 in_i) { MVMSpeshFacts *out_facts = &(g->facts[out_orig][out_i]); MVMSpeshFacts *in_facts = &(g->facts[in_orig][in_i]); /* If we know the original is decontainerized already, just copy its * info. */ MVMint32 in_flags = in_facts->flags; if ((in_flags & MVM_SPESH_FACT_TYPEOBJ) || ((in_flags & MVM_SPESH_FACT_KNOWN_TYPE) && !in_facts->type->st->container_spec)) { copy_facts(tc, g, out_orig, out_i, in_orig, in_i); return; } /* We may also know the original was containerized, and have some facts * about its contents. */ if (in_flags & MVM_SPESH_FACT_KNOWN_DECONT_TYPE) { out_facts->type = in_facts->decont_type; out_facts->flags |= MVM_SPESH_FACT_KNOWN_TYPE; } if (in_flags & MVM_SPESH_FACT_DECONT_CONCRETE) out_facts->flags |= MVM_SPESH_FACT_CONCRETE; else if (in_flags & MVM_SPESH_FACT_DECONT_TYPEOBJ) out_facts->flags |= MVM_SPESH_FACT_TYPEOBJ; if (in_flags & (MVM_SPESH_FACT_KNOWN_DECONT_TYPE | MVM_SPESH_FACT_DECONT_CONCRETE | MVM_SPESH_FACT_DECONT_TYPEOBJ)) MVM_spesh_facts_depend(tc, g, out_facts, in_facts); }
/* Optimizes a hllize instruction away if the type is known and already in the * right HLL, by turning it into a set. */ static void optimize_hllize(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshIns *ins) { MVMSpeshFacts *obj_facts = MVM_spesh_get_facts(tc, g, ins->operands[1]); if (obj_facts->flags & MVM_SPESH_FACT_KNOWN_TYPE && obj_facts->type) { if (STABLE(obj_facts->type)->hll_owner == g->sf->body.cu->body.hll_config) { ins->info = MVM_op_get_op(MVM_OP_set); copy_facts(tc, g, ins->operands[0], ins->operands[1]); } } }
/* Visits the blocks in dominator tree order, recursively. */ static void optimize_bb(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb) { MVMSpeshCallInfo arg_info; MVMint32 i; /* Look for instructions that are interesting to optimize. */ MVMSpeshIns *ins = bb->first_ins; while (ins) { switch (ins->info->opcode) { case MVM_OP_set: copy_facts(tc, g, ins->operands[0], ins->operands[1]); break; case MVM_OP_istrue: case MVM_OP_isfalse: optimize_istrue_isfalse(tc, g, bb, ins); break; case MVM_OP_if_i: case MVM_OP_unless_i: case MVM_OP_if_n: case MVM_OP_unless_n: case MVM_OP_if_o: case MVM_OP_unless_o: optimize_iffy(tc, g, ins, bb); break; case MVM_OP_prepargs: arg_info.cs = g->sf->body.cu->body.callsites[ins->operands[0].callsite_idx]; arg_info.prepargs_ins = ins; break; case MVM_OP_arg_i: case MVM_OP_arg_n: case MVM_OP_arg_s: case MVM_OP_arg_o: { MVMint16 idx = ins->operands[0].lit_i16; if (idx < MAX_ARGS_FOR_OPT) { arg_info.arg_is_const[idx] = 0; arg_info.arg_facts[idx] = MVM_spesh_get_facts(tc, g, ins->operands[1]); arg_info.arg_ins[idx] = ins; } break; } case MVM_OP_argconst_i: case MVM_OP_argconst_n: case MVM_OP_argconst_s: { MVMint16 idx = ins->operands[0].lit_i16; if (idx < MAX_ARGS_FOR_OPT) { arg_info.arg_is_const[idx] = 1; arg_info.arg_ins[idx] = ins; } break; } case MVM_OP_coerce_in: optimize_coerce(tc, g, bb, ins); break; case MVM_OP_invoke_v: optimize_call(tc, g, bb, ins, 0, &arg_info); break; case MVM_OP_invoke_i: case MVM_OP_invoke_n: case MVM_OP_invoke_s: case MVM_OP_invoke_o: optimize_call(tc, g, bb, ins, 1, &arg_info); break; case MVM_OP_islist: case MVM_OP_ishash: case MVM_OP_isint: case MVM_OP_isnum: case MVM_OP_isstr: optimize_is_reprid(tc, g, ins); break; case MVM_OP_findmeth: optimize_method_lookup(tc, g, ins); break; case MVM_OP_can: case MVM_OP_can_s: break; /* XXX This causes problems, Spesh: failed to fix up handlers (-1, 110, 110) */ /* optimize_can_op(tc, g, bb, ins); break; */ case MVM_OP_create: optimize_repr_op(tc, g, bb, ins, 1); break; case MVM_OP_isconcrete: optimize_isconcrete(tc, g, ins); break; case MVM_OP_istype: optimize_istype(tc, g, ins); break; case MVM_OP_bindattr_i: case MVM_OP_bindattr_n: case MVM_OP_bindattr_s: case MVM_OP_bindattr_o: case MVM_OP_bindattrs_i: case MVM_OP_bindattrs_n: case MVM_OP_bindattrs_s: case MVM_OP_bindattrs_o: optimize_repr_op(tc, g, bb, ins, 0); break; case MVM_OP_getattr_i: case MVM_OP_getattr_n: case MVM_OP_getattr_s: case MVM_OP_getattr_o: case MVM_OP_getattrs_i: case MVM_OP_getattrs_n: case MVM_OP_getattrs_s: case MVM_OP_getattrs_o: optimize_repr_op(tc, g, bb, ins, 1); break; case MVM_OP_box_i: case MVM_OP_box_n: case MVM_OP_box_s: optimize_repr_op(tc, g, bb, ins, 2); break; case MVM_OP_unbox_i: case MVM_OP_unbox_n: case MVM_OP_unbox_s: optimize_repr_op(tc, g, bb, ins, 1); break; case MVM_OP_elems: optimize_repr_op(tc, g, bb, ins, 1); break; case MVM_OP_hllize: optimize_hllize(tc, g, ins); break; case MVM_OP_decont: optimize_decont(tc, g, bb, ins); break; case MVM_OP_assertparamcheck: optimize_assertparamcheck(tc, g, bb, ins); break; case MVM_OP_getlexstatic_o: optimize_getlex_known(tc, g, bb, ins); break; case MVM_OP_getlexperinvtype_o: if (specialized_on_invocant(tc, g)) optimize_getlex_known(tc, g, bb, ins); break; case MVM_OP_sp_log: case MVM_OP_sp_osrfinalize: /* Left-over log instruction that didn't become a guard, or OSR * finalize instruction; just delete it. */ MVM_spesh_manipulate_delete_ins(tc, g, bb, ins); break; } ins = ins->next; } /* Visit children. */ for (i = 0; i < bb->num_children; i++) optimize_bb(tc, g, bb->children[i]); }
/* 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); }