Skip to content

Instantly share code, notes, and snippets.

@timo
Last active July 17, 2021 20:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timo/eb3a20abba0831d8f598073f44eafcf0 to your computer and use it in GitHub Desktop.
Save timo/eb3a20abba0831d8f598073f44eafcf0 to your computer and use it in GitHub Desktop.
diff to implement disp program to spesh instructions compilation
diff --git a/src/disp/inline_cache.c b/src/disp/inline_cache.c
index 7a10ec31d..c4f88461a 100644
--- a/src/disp/inline_cache.c
+++ b/src/disp/inline_cache.c
@@ -97,6 +97,7 @@ static void dispatch_initial_flattening(MVMThreadContext *tc,
static void dispatch_monomorphic(MVMThreadContext *tc,
MVMDispInlineCacheEntry **entry_ptr, MVMDispInlineCacheEntry *seen,
MVMString *id, MVMCallsite *callsite, MVMuint16 *arg_indices, MVMuint32 bytecode_offset) {
+ MVMint32 cid = tc->cur_frame->spesh_correlation_id;
MVMDispProgram *dp = ((MVMDispInlineCacheEntryMonomorphicDispatch *)seen)->dp;
MVMCallStackDispatchRun *record = MVM_callstack_allocate_dispatch_run(tc,
dp->num_temporaries);
@@ -110,14 +111,15 @@ static void dispatch_monomorphic(MVMThreadContext *tc,
dispatch_initial(tc, entry_ptr, seen, id, callsite, arg_indices, bytecode_offset);
}
else {
- if (MVM_spesh_log_is_logging(tc))
- MVM_spesh_log_dispatch_resolution(tc, bytecode_offset, 0);
+ if (MVM_spesh_log_is_logging(tc) && cid)
+ MVM_spesh_log_dispatch_resolution_for_correlation_id(tc, cid, bytecode_offset, 0);
}
}
static void dispatch_monomorphic_flattening(MVMThreadContext *tc,
MVMDispInlineCacheEntry **entry_ptr, MVMDispInlineCacheEntry *seen,
MVMString *id, MVMCallsite *callsite, MVMuint16 *arg_indices, MVMuint32 bytecode_offset) {
+ MVMint32 cid = tc->cur_frame->spesh_correlation_id;
/* First, perform flattening of the arguments. */
MVMCallStackFlattening *flat_record = MVM_args_perform_flattening(tc, callsite,
tc->cur_frame->work, arg_indices);
@@ -133,8 +135,8 @@ static void dispatch_monomorphic_flattening(MVMThreadContext *tc,
record->arg_info = flat_record->arg_info;
if (MVM_disp_program_run(tc, dp, record)) {
/* It matches, so we're ready to continue. */
- if (MVM_spesh_log_is_logging(tc))
- MVM_spesh_log_dispatch_resolution(tc, bytecode_offset, 0);
+ if (MVM_spesh_log_is_logging(tc) && cid)
+ MVM_spesh_log_dispatch_resolution_for_correlation_id(tc, cid, bytecode_offset, 0);
return;
}
else {
@@ -154,6 +156,7 @@ static void dispatch_monomorphic_flattening(MVMThreadContext *tc,
static void dispatch_polymorphic(MVMThreadContext *tc,
MVMDispInlineCacheEntry **entry_ptr, MVMDispInlineCacheEntry *seen,
MVMString *id, MVMCallsite *callsite, MVMuint16 *arg_indices, MVMuint32 bytecode_offset) {
+ MVMint32 cid = tc->cur_frame->spesh_correlation_id;
/* Set up dispatch run record. */
MVMDispInlineCacheEntryPolymorphicDispatch *entry =
(MVMDispInlineCacheEntryPolymorphicDispatch *)seen;
@@ -167,8 +170,8 @@ static void dispatch_polymorphic(MVMThreadContext *tc,
MVMuint32 i;
for (i = 0; i < entry->num_dps; i++) {
if (MVM_disp_program_run(tc, entry->dps[i], record)) {
- if (MVM_spesh_log_is_logging(tc))
- MVM_spesh_log_dispatch_resolution(tc, bytecode_offset, i);
+ if (MVM_spesh_log_is_logging(tc) && cid)
+ MVM_spesh_log_dispatch_resolution_for_correlation_id(tc, cid, bytecode_offset, i);
return;
}
}
@@ -182,6 +185,7 @@ static void dispatch_polymorphic(MVMThreadContext *tc,
static void dispatch_polymorphic_flattening(MVMThreadContext *tc,
MVMDispInlineCacheEntry **entry_ptr, MVMDispInlineCacheEntry *seen,
MVMString *id, MVMCallsite *callsite, MVMuint16 *arg_indices, MVMuint32 bytecode_offset) {
+ MVMint32 cid = tc->cur_frame->spesh_correlation_id;
/* First, perform flattening of the arguments. */
MVMCallStackFlattening *flat_record = MVM_args_perform_flattening(tc, callsite,
tc->cur_frame->work, arg_indices);
@@ -199,8 +203,8 @@ static void dispatch_polymorphic_flattening(MVMThreadContext *tc,
for (i = 0; i < entry->num_dps; i++) {
if (flat_record->arg_info.callsite == entry->flattened_css[i]) {
if (MVM_disp_program_run(tc, entry->dps[i], record)) {
- if (MVM_spesh_log_is_logging(tc))
- MVM_spesh_log_dispatch_resolution(tc, bytecode_offset, i);
+ if (MVM_spesh_log_is_logging(tc) && cid)
+ MVM_spesh_log_dispatch_resolution_for_correlation_id(tc, cid, bytecode_offset, i);
return;
}
}
diff --git a/src/spesh/disp.c b/src/spesh/disp.c
index e86fc04c4..550bdfdf0 100644
--- a/src/spesh/disp.c
+++ b/src/spesh/disp.c
@@ -85,27 +85,396 @@ static void rewrite_to_sp_dispatch(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSp
ins->operands = new_operands;
}
+static MVMuint32 find_disp_op_first_real_arg(MVMThreadContext *tc, MVMSpeshIns *ins) {
+ if (ins->info->opcode == MVM_OP_dispatch_v) {
+ return 2;
+ }
+ else if (ins->info->opcode == MVM_OP_dispatch_i ||
+ ins->info->opcode == MVM_OP_dispatch_n ||
+ ins->info->opcode == MVM_OP_dispatch_s ||
+ ins->info->opcode == MVM_OP_dispatch_o) {
+ return 3;
+ }
+ return 0;
+}
+/* XXX stolen from spesh/facts.c */
+static void copy_facts(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand to, MVMSpeshOperand from) {
+ MVMSpeshFacts *tfacts = &g->facts[to.reg.orig][to.reg.i];
+ MVMSpeshFacts *ffacts = &g->facts[from.reg.orig][from.reg.i];
+ tfacts->flags = ffacts->flags;
+ tfacts->type = ffacts->type;
+ tfacts->decont_type = ffacts->decont_type;
+ tfacts->value = ffacts->value;
+ tfacts->log_guards = ffacts->log_guards;
+ tfacts->num_log_guards = ffacts->num_log_guards;
+}
+/* XXX Stolen from spesh/optimize.c */
+static void find_deopt_target_and_index(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshIns *ins,
+ MVMuint32 *deopt_target_out, MVMuint32 *deopt_index_out) {
+ MVMSpeshAnn *deopt_ann = ins->annotations;
+ while (deopt_ann) {
+ if (deopt_ann->type == MVM_SPESH_ANN_DEOPT_ONE_INS) {
+ *deopt_target_out = g->deopt_addrs[2 * deopt_ann->data.deopt_idx];
+ *deopt_index_out = deopt_ann->data.deopt_idx;
+ return;
+ }
+ deopt_ann = deopt_ann->next;
+ }
+ MVM_panic(1, "Spesh: unexpectedly missing deopt annotation on prepargs");
+}
+static void add_synthetic_deopt_annotation(MVMThreadContext *tc, MVMSpeshGraph *g,
+ MVMSpeshIns *ins, MVMuint32 deopt_index) {
+ MVMSpeshAnn *ann = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshAnn));
+ ann->type = MVM_SPESH_ANN_DEOPT_SYNTH;
+ ann->data.deopt_idx = deopt_index;
+ ann->next = ins->annotations;
+ ins->annotations = ann;
+}
+static MVMSpeshOperand insert_arg_type_guard(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb,
+ MVMSpeshOperand operand, MVMSpeshIns *insert_pos,
+ MVMint8 concness, MVMSTable *type,
+ MVMuint32 add_comment) {
+ MVMuint32 deopt_target, deopt_index, new_deopt_index;
+
+ MVMuint8 has_type = type != NULL;
+
+ /* Split the SSA version of the arg. */
+ MVMSpeshOperand guard_reg = MVM_spesh_manipulate_split_version(tc, g,
+ operand, bb, insert_pos);
+
+ MVMSpeshFacts *guard_facts;
+
+ /* Insert guard before prepargs (this means they stack up in order). */
+ MVMSpeshIns *guard = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
+ guard->info = MVM_op_get_op(
+ concness == -1 ? (has_type ? MVM_OP_sp_guardtype : MVM_OP_sp_guardjusttype) :
+ concness == 0 ? (has_type ? MVM_OP_sp_guard : MVM_OP_no_op) :
+ concness == 1 ? (has_type ? MVM_OP_sp_guardconc : MVM_OP_sp_guardjustconc) : MVM_OP_no_op
+ );
+ guard->operands = MVM_spesh_alloc(tc, g, 4 * sizeof(MVMSpeshOperand));
+ guard->operands[0] = guard_reg;
+ guard->operands[1] = operand;
+ if (has_type)
+ guard->operands[2].lit_i16 = MVM_spesh_add_spesh_slot_try_reuse(tc, g,
+ (MVMCollectable *)type);
+ else
+ guard->operands[2].lit_i16 = 0;
+ find_deopt_target_and_index(tc, g, insert_pos, &deopt_target, &deopt_index);
+
+ MVM_spesh_manipulate_insert_ins(tc, bb, insert_pos->prev, guard);
+ MVM_spesh_usages_add_by_reg(tc, g, operand, guard);
+ guard_facts = MVM_spesh_get_facts(tc, g, guard_reg);
+ guard_facts->writer = guard;
+
+ if (has_type) {
+ guard_facts->flags |= MVM_SPESH_FACT_KNOWN_TYPE;
+ guard_facts->type = type->WHAT;
+ MVM_spesh_graph_add_comment(tc, g, guard, "set facts to known type on %d(%d)", guard_reg.reg.orig, guard_reg.reg.i);
+ }
+ if (concness == -1) {
+ guard_facts->flags |= MVM_SPESH_FACT_TYPEOBJ;
+ MVM_spesh_graph_add_comment(tc, g, guard, "set facts to known typeobject on %d(%d)", guard_reg.reg.orig, guard_reg.reg.i);
+ }
+ else if (concness == 1) {
+ guard_facts->flags |= MVM_SPESH_FACT_CONCRETE;
+ MVM_spesh_graph_add_comment(tc, g, guard, "set facts to known concrete on %d(%d)", guard_reg.reg.orig, guard_reg.reg.i);
+ }
+
+ if (add_comment) {
+ if (has_type)
+ MVM_spesh_graph_add_comment(tc, g, guard, "inserted dispatch program guard %d(%d) <- %d(%d) for type %s",
+ guard_reg.reg.orig, guard_reg.reg.i,
+ operand.reg.orig, operand.reg.i,
+ MVM_6model_get_stable_debug_name(tc, type));
+ else
+ MVM_spesh_graph_add_comment(tc, g, guard, "inserted dispatch program guard");
+ }
+
+ /* Also give the instruction a deopt annotation, and related it to the
+ * one on the prepargs. */
+ /*
+ * XXX the deopt address is wrong, at least some of the time; it returns to
+ * after the dispatch_* op in the deopted program, so any necessary work
+ * will likely be skipped, resulting in segfaults in spesh guard running
+ * and such
+ */
+ new_deopt_index = MVM_spesh_graph_add_deopt_annotation(tc, g, guard, deopt_target,
+ MVM_SPESH_ANN_DEOPT_ONE_INS);
+ guard->operands[3].lit_ui32 = new_deopt_index;
+ add_synthetic_deopt_annotation(tc, g, guard, deopt_index);
+
+ return guard_reg;
+}
+static MVMSpeshIns *rewrite_dispatch_program(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins,
+ MVMDispProgram *dp) {
+ MVMuint32 i;
+ MVMSpeshOperand *args = &ins->operands[find_disp_op_first_real_arg(tc, ins)];
+ MVMSpeshOperand *temporaries = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshOperand) * dp->num_temporaries);
+ MVMSpeshIns *resume_optimization_point = ins->prev;
+
+ if (dp->first_args_temporary != dp->num_temporaries) {
+ fprintf(stderr, "----\nignoring program with first_args_temporary != num_temporaries\n----\n\n");
+ return NULL;
+ }
+ fprintf(stderr, "----\nbuilding spesh code for disp program\n----\n\n");
+
+ MVM_spesh_graph_add_comment(tc, g, ins->prev ? ins->prev : bb->first_ins, "Rewritten from a %s op", ins->info->name);
+
+ for (i = 0; i < dp->num_temporaries; i++) {
+ /* the "type" of the reg isn't explicit in the program's metadata, it's
+ * implicit in the way it's used.
+ * XXX just go with objects for temporaries
+ */
+ temporaries[i] = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_obj);
+ }
+
+ for (i = 0; i < dp->num_ops; i++) {
+ MVMDispProgramOp *op = &(dp->ops[i]);
+ switch (op->code) {
+ case MVMDispOpcodeGuardArgType:
+ fprintf(stderr, " Guard arg %d (type=%s)\n",
+ op->arg_guard.arg_idx,
+ ((MVMSTable *)dp->gc_constants[op->arg_guard.checkee])->debug_name);
+ args[op->arg_guard.arg_idx] =
+ insert_arg_type_guard(tc, g, bb,
+ args[op->arg_guard.arg_idx], ins,
+ 0, ((MVMSTable *)dp->gc_constants[op->arg_guard.checkee]),
+ 1);
+ break;
+ case MVMDispOpcodeGuardArgTypeConc:
+ fprintf(stderr, " Guard arg %d (type=%s, concrete)\n",
+ op->arg_guard.arg_idx,
+ ((MVMSTable *)dp->gc_constants[op->arg_guard.checkee])->debug_name);
+ args[op->arg_guard.arg_idx] =
+ insert_arg_type_guard(tc, g, bb,
+ args[op->arg_guard.arg_idx], ins,
+ 1, ((MVMSTable *)dp->gc_constants[op->arg_guard.checkee]),
+ 1);
+ break;
+ case MVMDispOpcodeGuardArgTypeTypeObject:
+ fprintf(stderr, " Guard arg %d (type=%s, type object)\n",
+ op->arg_guard.arg_idx,
+ ((MVMSTable *)dp->gc_constants[op->arg_guard.checkee])->debug_name);
+ args[op->arg_guard.arg_idx] =
+ insert_arg_type_guard(tc, g, bb,
+ args[op->arg_guard.arg_idx], ins,
+ -1, ((MVMSTable *)dp->gc_constants[op->arg_guard.checkee]),
+ 1);
+ break;
+ case MVMDispOpcodeGuardArgConc:
+ fprintf(stderr, " Guard arg %d (concrete)\n",
+ op->arg_guard.arg_idx);
+ goto nyi;
+ break;
+ case MVMDispOpcodeGuardArgTypeObject:
+ fprintf(stderr, " Guard arg %d (type object)\n",
+ op->arg_guard.arg_idx);
+ goto nyi;
+ break;
+ case MVMDispOpcodeGuardArgLiteralObj:
+ fprintf(stderr, " Guard arg %d (literal object of type %s)\n",
+ op->arg_guard.arg_idx,
+ STABLE(((MVMObject *)dp->gc_constants[op->arg_guard.checkee]))->debug_name);
+ goto nyi;
+ break;
+ case MVMDispOpcodeGuardArgLiteralStr: {
+ char *c_str = MVM_string_utf8_encode_C_string(tc,
+ ((MVMString *)dp->gc_constants[op->arg_guard.checkee]));
+ fprintf(stderr, " Guard arg %d (literal string '%s')\n",
+ op->arg_guard.arg_idx, c_str);
+ MVM_free(c_str);
+ goto nyi;
+ break;
+ }
+ case MVMDispOpcodeGuardArgLiteralInt:
+ fprintf(stderr, " Guard arg %d (literal integer %"PRIi64")\n",
+ op->arg_guard.arg_idx,
+ dp->constants[op->arg_guard.checkee].i64);
+ goto nyi;
+ break;
+ case MVMDispOpcodeGuardArgLiteralNum:
+ fprintf(stderr, " Guard arg %d (literal number %g)\n",
+ op->arg_guard.arg_idx,
+ dp->constants[op->arg_guard.checkee].n64);
+ goto nyi;
+ break;
+ case MVMDispOpcodeGuardArgNotLiteralObj:
+ fprintf(stderr, " Guard arg %d (not literal object of type %s)\n",
+ op->arg_guard.arg_idx,
+ STABLE(((MVMObject *)dp->gc_constants[op->arg_guard.checkee]))->debug_name);
+ goto nyi;
+ break;
+ case MVMDispOpcodeLoadCaptureValue: {
+ MVMSpeshIns *set_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
+ fprintf(stderr, " Load argument %d into temporary %d\n",
+ op->load.idx, op->load.temp);
+ fprintf(stderr, " adding a set op\n");
+ set_ins->info = MVM_op_get_op(MVM_OP_set);
+ set_ins->operands = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshOperand) * 2);
+ set_ins->operands[0] = temporaries[op->load.temp];
+ set_ins->operands[1] = args[op->load.idx];
+ copy_facts(tc, g, set_ins->operands[0], set_ins->operands[1]);
+ MVM_spesh_graph_add_comment(tc, g, set_ins, "set instruction from LoadCaptureValue");
+ MVM_spesh_usages_add_by_reg(tc, g, set_ins->operands[1], set_ins);
+ MVM_spesh_manipulate_insert_ins(tc, bb, ins->prev, set_ins);
+ break;
+ }
+ case MVMDispOpcodeLoadAttributeObj: {
+ fprintf(stderr, " Deference object attribute at offset %d in temporary %d\n",
+ op->load.idx, op->load.temp);
+ MVMSpeshIns *get_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
+ MVMSpeshFacts *target_facts;
+ get_ins->info = MVM_op_get_op(MVM_OP_sp_p6oget_o);
+ get_ins->operands = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshOperand) * 3);
+ get_ins->operands[1] = temporaries[op->load.temp];
+ temporaries[op->load.temp] = MVM_spesh_manipulate_new_version(tc, g, temporaries[op->load.temp].reg.orig);
+ get_ins->operands[0] = temporaries[op->load.temp];
+ get_ins->operands[2].lit_i16 = op->load.idx;
+ target_facts = MVM_spesh_get_facts(tc, g, ins->operands[0]);
+ MVM_spesh_graph_add_comment(tc, g, get_ins, "p6oget_o instruction from LoadAttributeObj");
+ MVM_spesh_usages_add_by_reg(tc, g, get_ins->operands[1], get_ins);
+ MVM_spesh_manipulate_insert_ins(tc, bb, ins->prev, get_ins);
+ target_facts->writer = get_ins;
+ break;
+ }
+ case MVMDispOpcodeLoadAttributeInt: {
+ fprintf(stderr, " Deference integer attribute at offset %d in temporary %d\n",
+ op->load.idx, op->load.temp);
+ MVMSpeshIns *get_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
+ MVMSpeshFacts *target_facts;
+ get_ins->info = MVM_op_get_op(MVM_OP_sp_p6oget_i);
+ get_ins->operands = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshOperand) * 3);
+ get_ins->operands[1] = temporaries[op->load.temp];
+ temporaries[op->load.temp] = MVM_spesh_manipulate_new_version(tc, g, temporaries[op->load.temp].reg.orig);
+ get_ins->operands[0] = temporaries[op->load.temp];
+ get_ins->operands[2].lit_i16 = op->load.idx;
+ target_facts = MVM_spesh_get_facts(tc, g, ins->operands[0]);
+ MVM_spesh_graph_add_comment(tc, g, get_ins, "p6oget_i instruction from LoadAttributeInt");
+ MVM_spesh_usages_add_by_reg(tc, g, get_ins->operands[1], get_ins);
+ MVM_spesh_manipulate_insert_ins(tc, bb, ins->prev, get_ins);
+ target_facts->writer = get_ins;
+ break;
+ }
+ case MVMDispOpcodeLoadAttributeNum: {
+ fprintf(stderr, " Deference num attribute at offset %d in temporary %d\n",
+ op->load.idx, op->load.temp);
+ MVMSpeshIns *get_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
+ MVMSpeshFacts *target_facts;
+ get_ins->info = MVM_op_get_op(MVM_OP_sp_p6oget_n);
+ get_ins->operands = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshOperand) * 3);
+ get_ins->operands[1] = temporaries[op->load.temp];
+ temporaries[op->load.temp] = MVM_spesh_manipulate_new_version(tc, g, temporaries[op->load.temp].reg.orig);
+ get_ins->operands[0] = temporaries[op->load.temp];
+ get_ins->operands[2].lit_i16 = op->load.idx;
+ target_facts = MVM_spesh_get_facts(tc, g, ins->operands[0]);
+ MVM_spesh_graph_add_comment(tc, g, get_ins, "p6oget_n instruction from LoadAttributeNum");
+ MVM_spesh_usages_add_by_reg(tc, g, get_ins->operands[1], get_ins);
+ MVM_spesh_manipulate_insert_ins(tc, bb, ins->prev, get_ins);
+ target_facts->writer = get_ins;
+ break;
+ }
+ case MVMDispOpcodeLoadAttributeStr: {
+ fprintf(stderr, " Deference string attribute at offset %d in temporary %d\n",
+ op->load.idx, op->load.temp);
+ MVMSpeshIns *get_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
+ MVMSpeshFacts *target_facts;
+ get_ins->info = MVM_op_get_op(MVM_OP_sp_p6oget_s);
+ get_ins->operands = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshOperand) * 3);
+ get_ins->operands[1] = temporaries[op->load.temp];
+ temporaries[op->load.temp] = MVM_spesh_manipulate_new_version(tc, g, temporaries[op->load.temp].reg.orig);
+ get_ins->operands[0] = temporaries[op->load.temp];
+ get_ins->operands[2].lit_i16 = op->load.idx;
+ target_facts = MVM_spesh_get_facts(tc, g, ins->operands[0]);
+ MVM_spesh_graph_add_comment(tc, g, get_ins, "p6oget_s instruction from LoadAttributeStr");
+ MVM_spesh_usages_add_by_reg(tc, g, get_ins->operands[1], get_ins);
+ MVM_spesh_manipulate_insert_ins(tc, bb, ins->prev, get_ins);
+ target_facts->writer = get_ins;
+ break;
+ }
+ case MVMDispOpcodeSet: {
+ MVMSpeshIns *set_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
+ MVMSpeshFacts *target_facts;
+ fprintf(stderr, " Set temporary %d value from temporary %d in bb %p\n",
+ op->load.temp, op->load.idx, bb);
+ set_ins->info = MVM_op_get_op(MVM_OP_set);
+ set_ins->operands = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshOperand) * 2);
+ set_ins->operands[0] = temporaries[op->load.temp];
+ set_ins->operands[1] = temporaries[op->load.idx];
+ copy_facts(tc, g, set_ins->operands[0], set_ins->operands[1]);
+ MVM_spesh_graph_add_comment(tc, g, set_ins, "set instruction from Set");
+ target_facts = MVM_spesh_get_facts(tc, g, ins->operands[0]);
+ MVM_spesh_usages_add_by_reg(tc, g, set_ins->operands[1], set_ins);
+ MVM_spesh_manipulate_insert_ins(tc, bb, ins->prev, set_ins);
+ target_facts->writer = set_ins;
+ break;
+ }
+ case MVMDispOpcodeResultValueObj: {
+ MVMSpeshIns *set_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
+ MVMSpeshFacts *target_facts = MVM_spesh_get_facts(tc, g, ins->operands[0]);
+ fprintf(stderr, " Set result object value from temporary %d\n",
+ op->res_value.temp);
+ set_ins->info = MVM_op_get_op(MVM_OP_set);
+ set_ins->operands = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshOperand) * 2);
+ set_ins->operands[0] = ins->operands[0];
+ set_ins->operands[1] = temporaries[op->res_value.temp];
+ copy_facts(tc, g, set_ins->operands[0], set_ins->operands[1]);
+ MVM_spesh_graph_add_comment(tc, g, set_ins, "set instruction from ResultValueObj");
+ MVM_spesh_usages_add_by_reg(tc, g, set_ins->operands[1], set_ins);
+ MVM_spesh_manipulate_insert_ins(tc, bb, ins->prev, set_ins);
+ MVM_spesh_manipulate_delete_ins(tc, g, bb, ins);
+ target_facts->writer = set_ins;
+ return resume_optimization_point;
+ }
+ default:
+ fprintf(stderr, " .... no %d.\n", op->code);
+ return NULL;
+ }
+ }
+nyi:
+ fprintf(stderr, " NYI, sorry!\n");
+cleanup:
+ for (i = 0; i < dp->num_temporaries; i++) {
+ /* the "type" of the reg isn't explicit in the program's metadata, it's
+ * implicit in the way it's used.
+ * XXX just go with objects for temporaries
+ */
+ MVM_spesh_manipulate_release_temp_reg(tc, g, temporaries[i]);
+ }
+ return NULL;
+}
+
/* Rewrite an unhit dispatch instruction. */
-static void rewrite_unhit(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshIns *ins,
+static MVMSpeshIns *rewrite_unhit(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins,
MVMuint32 bytecode_offset) {
MVM_spesh_graph_add_comment(tc, g, ins, "Never dispatched");
rewrite_to_sp_dispatch(tc, g, ins, bytecode_offset);
+ return ins;
}
/* Rewrite a dispatch instruction that is considered monomorphic. */
-static void rewrite_monomorphic(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshIns *ins,
+static MVMSpeshIns *rewrite_monomorphic(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins,
MVMuint32 bytecode_offset, MVMuint32 outcome) {
- // TODO
- MVM_spesh_graph_add_comment(tc, g, ins, "Deemed monomorphic (outcome %d)", outcome);
+ MVMuint32 disp_slot = MVM_disp_inline_cache_get_slot(tc, g->sf, bytecode_offset);
+ MVMDispInlineCache *cache = &(g->sf->body.inline_cache);
+ MVMDispInlineCacheEntry *entry = cache->entries[bytecode_offset >> cache->bit_shift];
+ MVMuint32 kind = MVM_disp_inline_cache_get_kind(tc, entry);
+ if (kind == MVM_INLINE_CACHE_KIND_MONOMORPHIC_DISPATCH) {
+ MVMSpeshIns *result = rewrite_dispatch_program(tc, g, bb, ins, ((MVMDispInlineCacheEntryMonomorphicDispatch *)entry)->dp);
+ if (result)
+ return result;
+ }
+ MVM_spesh_graph_add_comment(tc, g, ins, "Deemed monomorphic (outcome %d, entry kind %d)", outcome, kind);
rewrite_to_sp_dispatch(tc, g, ins, bytecode_offset);
+ return ins;
}
/* Rewrite a dispatch instruction that is polymorphic or megamorphic. */
-static void rewrite_polymorphic(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshIns *ins,
+static MVMSpeshIns *rewrite_polymorphic(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins,
MVMuint32 bytecode_offset, OutcomeHitCount *outcomes, MVMuint32 num_outcomes) {
// TODO
MVM_spesh_graph_add_comment(tc, g, ins, "Deemed polymorphic");
rewrite_to_sp_dispatch(tc, g, ins, bytecode_offset);
+ return ins;
}
/* Drives the overall process of optimizing a dispatch instruction. The instruction
@@ -115,8 +484,9 @@ static void rewrite_polymorphic(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpesh
static int compare_hits(const void *a, const void *b) {
return ((OutcomeHitCount *)b)->hits - ((OutcomeHitCount *)a)->hits;
}
-void MVM_spesh_disp_optimize(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshPlanned *p,
+MVMSpeshIns *MVM_spesh_disp_optimize(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshPlanned *p,
MVMSpeshIns *ins) {
+ MVMSpeshIns *result = ins;
/* Locate the inline cache bytecode offset. There must always be one. */
MVMSpeshAnn *ann = ins->annotations;
while (ann) {
@@ -169,18 +539,20 @@ void MVM_spesh_disp_optimize(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshPla
}
qsort(outcome_hits, MVM_VECTOR_ELEMS(outcome_hits), sizeof(OutcomeHitCount), compare_hits);
+
/* If there are no hits, we can only rewrite it to sp_dispatch. */
if (MVM_VECTOR_ELEMS(outcome_hits) == 0)
- rewrite_unhit(tc, g, ins, bytecode_offset);
+ result = rewrite_unhit(tc, g, bb, ins, bytecode_offset);
/* If there's one hit, *or* the top hit has > 99% of the total hits, then we
* rewrite it to monomorphic. */
else if ((100 * outcome_hits[0].hits) / total_hits >= 99)
- rewrite_monomorphic(tc, g, ins, bytecode_offset, outcome_hits[0].outcome);
+ result = rewrite_monomorphic(tc, g, bb, ins, bytecode_offset, outcome_hits[0].outcome);
/* Otherwise, it's polymoprhic or megamorphic. */
else
- rewrite_polymorphic(tc, g, ins, bytecode_offset, outcome_hits, MVM_VECTOR_ELEMS(outcome_hits));
+ result = rewrite_polymorphic(tc, g, bb, ins, bytecode_offset, outcome_hits, MVM_VECTOR_ELEMS(outcome_hits));
MVM_VECTOR_DESTROY(outcome_hits);
+ return result;
}
diff --git a/src/spesh/disp.h b/src/spesh/disp.h
index 218189d47..c8a142bb9 100644
--- a/src/spesh/disp.h
+++ b/src/spesh/disp.h
@@ -1,3 +1,3 @@
MVMOpInfo * MVM_spesh_disp_create_dispatch_op_info(MVMThreadContext *tc, MVMSpeshGraph *g,
const MVMOpInfo *base_info, MVMCallsite *cs);
-void MVM_spesh_disp_optimize(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshPlanned *p, MVMSpeshIns *ins);
+MVMSpeshIns *MVM_spesh_disp_optimize(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshPlanned *p, MVMSpeshIns *ins);
diff --git a/src/spesh/facts.c b/src/spesh/facts.c
index b6a78c9cf..b8bfc82e5 100644
--- a/src/spesh/facts.c
+++ b/src/spesh/facts.c
@@ -725,6 +725,7 @@ static void add_bb_facts(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb,
ins->operands[3].reg.orig, ins->operands[3].reg.i);
break;
case MVM_OP_encoderep:
+ case MVM_OP_encoderepconf:
create_facts(tc, g,
ins->operands[0].reg.orig, ins->operands[0].reg.i,
ins->operands[4].reg.orig, ins->operands[4].reg.i);
diff --git a/src/spesh/log.c b/src/spesh/log.c
index 953201337..9a003ef1d 100644
--- a/src/spesh/log.c
+++ b/src/spesh/log.c
@@ -250,3 +250,13 @@ void MVM_spesh_log_dispatch_resolution(MVMThreadContext *tc, MVMuint32 bytecode_
entry->plugin.guard_index = guard_index;
commit_entry(tc, sl);
}
+void MVM_spesh_log_dispatch_resolution_for_correlation_id(MVMThreadContext *tc, MVMint32 cid, MVMuint32 bytecode_offset,
+ MVMuint16 guard_index) {
+ MVMSpeshLog *sl = tc->spesh_log;
+ MVMSpeshLogEntry *entry = &(sl->body.entries[sl->body.used]);
+ entry->kind = MVM_SPESH_LOG_DISPATCH_RESOLUTION;
+ entry->id = cid;
+ entry->plugin.bytecode_offset = bytecode_offset;
+ entry->plugin.guard_index = guard_index;
+ commit_entry(tc, sl);
+}
diff --git a/src/spesh/log.h b/src/spesh/log.h
index fc5b40beb..841c59921 100644
--- a/src/spesh/log.h
+++ b/src/spesh/log.h
@@ -51,3 +51,5 @@ void MVM_spesh_log_plugin_resolution(MVMThreadContext *tc, MVMuint32 bytecode_of
MVMuint16 guard_index);
void MVM_spesh_log_dispatch_resolution(MVMThreadContext *tc, MVMuint32 bytecode_offset,
MVMuint16 guard_index);
+void MVM_spesh_log_dispatch_resolution_for_correlation_id(MVMThreadContext *tc, MVMint32 cid, MVMuint32 bytecode_offset,
+ MVMuint16 guard_index);
diff --git a/src/spesh/optimize.c b/src/spesh/optimize.c
index f773362d2..6a71382a8 100644
--- a/src/spesh/optimize.c
+++ b/src/spesh/optimize.c
@@ -3061,7 +3061,7 @@ static void optimize_bb_switch(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshB
case MVM_OP_dispatch_n:
case MVM_OP_dispatch_s:
case MVM_OP_dispatch_i:
- MVM_spesh_disp_optimize(tc, g, p, ins);
+ ins = MVM_spesh_disp_optimize(tc, g, bb, p, ins);
break;
case MVM_OP_sp_guard:
case MVM_OP_sp_guardconc:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment