Skip to content

Commit

Permalink
Minimal escape analysis and scalar replacement
Browse files Browse the repository at this point in the history
This only handles the case where:

* No aliasing
* No deoptimizing instructions
* No control flow (conditionals, loops)
* No escapes of the allocation (we'll later add partial escape handling
  by materializing the object where needed)
* Only P6opaque objects that have object attributes
* Must have lowered the creation and access already (which we will
  have in cases where we know enough to do EA anyway)

Developed with masak++.
  • Loading branch information
jnthn committed Jul 25, 2018
1 parent 4c7281a commit e7c1855
Show file tree
Hide file tree
Showing 13 changed files with 353 additions and 30 deletions.
2 changes: 2 additions & 0 deletions build/Makefile.in
Expand Up @@ -210,6 +210,7 @@ OBJECTS = src/core/callsite@obj@ \
src/spesh/arg_guard@obj@ \
src/spesh/plugin@obj@ \
src/spesh/frame_walker@obj@ \
src/spesh/pea@obj@ \
src/strings/decode_stream@obj@ \
src/strings/ascii@obj@ \
src/strings/parse_num@obj@ \
Expand Down Expand Up @@ -373,6 +374,7 @@ HEADERS = src/moar.h \
src/spesh/arg_guard.h \
src/spesh/plugin.h \
src/spesh/frame_walker.h \
src/spesh/pea.h \
src/strings/unicode_gen.h \
src/strings/normalize.h \
src/strings/decode_stream.h \
Expand Down
10 changes: 10 additions & 0 deletions src/6model/reprs/P6opaque.c
Expand Up @@ -1696,6 +1696,16 @@ size_t MVM_p6opaque_attr_offset(MVMThreadContext *tc, MVMObject *type,
return repr_data->attribute_offsets[slot];
}

/* Gets the attribute index given we know the slot offset. */
MVMuint32 MVM_p6opaque_offset_to_attr_idx(MVMThreadContext *tc, MVMObject *type, size_t offset) {
MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)type->st->REPR_data;
MVMuint32 i;
for (i = 0; i < repr_data->num_attributes; i++)
if (repr_data->attribute_offsets[i] == offset)
return i;
MVM_oops(tc, "P6opaque: slot offset not found");
}

#ifdef DEBUG_HELPERS
/* This is meant to be called in a debugging session and not used anywhere else.
* Plese don't delete. */
Expand Down
1 change: 1 addition & 0 deletions src/6model/reprs/P6opaque.h
Expand Up @@ -123,4 +123,5 @@ MVM_STATIC_INLINE MVMint64 MVM_p6opaque_read_int64(MVMThreadContext *tc,

size_t MVM_p6opaque_attr_offset(MVMThreadContext *tc, MVMObject *type,
MVMObject *class_handle, MVMString *name);
MVMuint32 MVM_p6opaque_offset_to_attr_idx(MVMThreadContext *tc, MVMObject *type, size_t offset);
void MVM_P6opaque_at_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister *value, MVMuint16 kind);
3 changes: 3 additions & 0 deletions src/core/vector.h
Expand Up @@ -18,6 +18,9 @@
x ## _alloc = 0; \
} while (0)

#define MVM_VECTOR_ELEMS(x) \
(x ## _num)

#define MVM_VECTOR_SIZE(x) \
(sizeof(*x) * (x ## _alloc))

Expand Down
1 change: 1 addition & 0 deletions src/moar.h
Expand Up @@ -149,6 +149,7 @@ MVM_PUBLIC const MVMint32 MVM_jit_support(void);
#include "spesh/manipulate.h"
#include "spesh/args.h"
#include "spesh/usages.h"
#include "spesh/pea.h"
#include "spesh/facts.h"
#include "spesh/optimize.h"
#include "spesh/dead_bb_elimination.h"
Expand Down
4 changes: 4 additions & 0 deletions src/spesh/facts.h
Expand Up @@ -30,6 +30,10 @@ struct MVMSpeshFacts {

/* Has the instruction that wrote this value been deleted? */
MVMuint16 dead_writer;

/* Information associated with this value for the use of partial escape
* analysis. */
MVMSpeshPEAInfo pea;
};

/* Various fact flags. */
Expand Down
92 changes: 64 additions & 28 deletions src/spesh/manipulate.c
Expand Up @@ -250,48 +250,55 @@ void MVM_spesh_manipulate_remove_handler_successors(MVMThreadContext *tc, MVMSpe
bb->num_handler_succ = 0;
}

static void ensure_more_temps(MVMThreadContext *tc, MVMSpeshGraph *g) {
if (g->num_temps == g->alloc_temps) {
MVMSpeshTemporary *new_temps;
g->alloc_temps += 4;
new_temps = MVM_spesh_alloc(tc, g, g->alloc_temps * sizeof(MVMSpeshTemporary));
if (g->num_temps)
memcpy(new_temps, g->temps, g->num_temps * sizeof(MVMSpeshTemporary));
g->temps = new_temps;
}
}

/* Gets a temporary register of the specified kind to use in some transform.
* Will only actually extend the frame if needed; if an existing temporary
* was requested and then released, then it will just use a new version of
* that. */
MVMSpeshOperand MVM_spesh_manipulate_get_temp_reg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMuint16 kind) {
static MVMSpeshOperand make_temp_reg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMuint16 kind,
MVMuint16 reuse) {
MVMSpeshOperand result;
MVMSpeshFacts **new_facts;
MVMuint16 *new_fact_counts;
MVMuint16 i;

/* First, see if we can find an existing free temporary; use it if so. */
for (i = 0; i < g->num_temps; i++) {
if (g->temps[i].kind == kind && !g->temps[i].in_use) {
/* Add new facts slot. */
MVMuint16 orig = g->temps[i].orig;
MVMSpeshFacts *new_fact_row = MVM_spesh_alloc(tc, g,
(g->fact_counts[orig] + 1) * sizeof(MVMSpeshFacts));
memcpy(new_fact_row, g->facts[orig],
g->fact_counts[orig] * sizeof(MVMSpeshFacts));
g->facts[orig] = new_fact_row;
g->fact_counts[orig]++;

/* Mark it in use and add extra version. */
g->temps[i].in_use++;
g->temps[i].i++;

/* Produce and return result. */
result.reg.orig = orig;
result.reg.i = g->temps[i].i;
return result;
if (reuse) {
for (i = 0; i < g->num_temps; i++) {
if (g->temps[i].kind == kind && !g->temps[i].in_use) {
/* Add new facts slot. */
MVMuint16 orig = g->temps[i].orig;
MVMSpeshFacts *new_fact_row = MVM_spesh_alloc(tc, g,
(g->fact_counts[orig] + 1) * sizeof(MVMSpeshFacts));
memcpy(new_fact_row, g->facts[orig],
g->fact_counts[orig] * sizeof(MVMSpeshFacts));
g->facts[orig] = new_fact_row;
g->fact_counts[orig]++;

/* Mark it in use and add extra version. */
g->temps[i].in_use++;
g->temps[i].i++;

/* Produce and return result. */
result.reg.orig = orig;
result.reg.i = g->temps[i].i;
return result;
}
}
}

/* Make sure we've space in the temporaries store. */
if (g->num_temps == g->alloc_temps) {
MVMSpeshTemporary *new_temps;
g->alloc_temps += 4;
new_temps = MVM_spesh_alloc(tc, g, g->alloc_temps * sizeof(MVMSpeshTemporary));
if (g->num_temps)
memcpy(new_temps, g->temps, g->num_temps * sizeof(MVMSpeshTemporary));
g->temps = new_temps;
}
ensure_more_temps(tc, g);

/* Allocate temporary and set up result. */
g->temps[g->num_temps].orig = result.reg.orig = g->num_locals;
Expand Down Expand Up @@ -324,6 +331,9 @@ MVMSpeshOperand MVM_spesh_manipulate_get_temp_reg(MVMThreadContext *tc, MVMSpesh

return result;
}
MVMSpeshOperand MVM_spesh_manipulate_get_temp_reg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMuint16 kind) {
return make_temp_reg(tc, g, kind, 1);
}

/* Releases a temporary register, so it can be used again later. */
void MVM_spesh_manipulate_release_temp_reg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand temp) {
Expand All @@ -340,6 +350,32 @@ void MVM_spesh_manipulate_release_temp_reg(MVMThreadContext *tc, MVMSpeshGraph *
MVM_oops(tc, "Spesh: releasing non-existing temp");
}

/* Gets a frame-unique register, adding it to the set of registers of the
* frame. This does not hand back a particular version, it just selects the
* unversioned register. */
MVMuint16 MVM_spesh_manipulate_get_unique_reg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMuint16 kind) {
return make_temp_reg(tc, g, kind, 0).reg.orig;
}

/* Get the current version of an SSA temporary. */
MVMuint16 MVM_spesh_manipulate_get_current_version(MVMThreadContext *tc, MVMSpeshGraph *g,
MVMuint16 orig) {
MVMuint32 i;
for (i = 0; i < g->num_temps; i++)
if (g->temps[i].orig == orig)
return g->temps[i].i;
MVM_oops(tc, "Could not find register version for %d", orig);
}

/* Create and return a new version of an SSA temporary. */
MVMuint16 MVM_spesh_manipulate_new_version(MVMThreadContext *tc, MVMSpeshGraph *g,
MVMuint16 orig) {
MVMuint32 i;
for (i = 0; i < g->num_temps; i++)
if (g->temps[i].orig == orig)
return ++g->temps[i].i;
MVM_oops(tc, "Could not find register version for %d", orig);
}

MVMSpeshBB *MVM_spesh_manipulate_split_BB_at(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins) {
MVMSpeshBB *new_bb = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshBB));
Expand Down
5 changes: 5 additions & 0 deletions src/spesh/manipulate.h
Expand Up @@ -7,5 +7,10 @@ void MVM_spesh_manipulate_remove_successor(MVMThreadContext *tc, MVMSpeshBB *bb,
MVM_PUBLIC void MVM_spesh_manipulate_remove_handler_successors(MVMThreadContext *tc, MVMSpeshBB *bb);
MVMSpeshOperand MVM_spesh_manipulate_get_temp_reg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMuint16 kind);
void MVM_spesh_manipulate_release_temp_reg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand temp);
MVMuint16 MVM_spesh_manipulate_get_unique_reg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMuint16 kind);
MVMuint16 MVM_spesh_manipulate_get_current_version(MVMThreadContext *tc, MVMSpeshGraph *g,
MVMuint16 orig);
MVMuint16 MVM_spesh_manipulate_new_version(MVMThreadContext *tc, MVMSpeshGraph *g,
MVMuint16 orig);

MVMSpeshBB *MVM_spesh_manipulate_split_BB_at(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins);
2 changes: 1 addition & 1 deletion src/spesh/optimize.c
Expand Up @@ -2881,13 +2881,13 @@ void MVM_spesh_optimize(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshPlanned
eliminate_pointless_gotos(tc, g);
MVM_spesh_usages_remove_unused_deopt(tc, g);
eliminate_dead_ins(tc, g);

merge_bbs(tc, g);

/* Make a second pass through the graph doing things that are better
* done after inlinings have taken place. Note that these things must not
* add new fact dependencies. */
second_pass(tc, g, g->entry);
MVM_spesh_pea(tc, g);
#if MVM_SPESH_CHECK_DU
MVM_spesh_usages_check(tc, g);
#endif
Expand Down

0 comments on commit e7c1855

Please sign in to comment.