diff --git a/build/Makefile.in b/build/Makefile.in index 2b67f6377e..ce71e6394a 100644 --- a/build/Makefile.in +++ b/build/Makefile.in @@ -192,6 +192,7 @@ OBJECTS = src/core/callsite@obj@ \ src/spesh/candidate@obj@ \ src/spesh/manipulate@obj@ \ src/spesh/args@obj@ \ + src/spesh/usages@obj@ \ src/spesh/facts@obj@ \ src/spesh/optimize@obj@ \ src/spesh/dead_bb_elimination@obj@ \ @@ -354,6 +355,7 @@ HEADERS = src/moar.h \ src/spesh/candidate.h \ src/spesh/manipulate.h \ src/spesh/args.h \ + src/spesh/usages.h \ src/spesh/facts.h \ src/spesh/optimize.h \ src/spesh/dead_bb_elimination.h \ diff --git a/src/moar.h b/src/moar.h index 8c46a16b88..c88baccd71 100644 --- a/src/moar.h +++ b/src/moar.h @@ -149,6 +149,7 @@ MVM_PUBLIC const MVMint32 MVM_jit_support(void); #include "spesh/candidate.h" #include "spesh/manipulate.h" #include "spesh/args.h" +#include "spesh/usages.h" #include "spesh/facts.h" #include "spesh/optimize.h" #include "spesh/dead_bb_elimination.h" diff --git a/src/spesh/facts.h b/src/spesh/facts.h index 33839e9a69..064cfc017f 100644 --- a/src/spesh/facts.h +++ b/src/spesh/facts.h @@ -1,4 +1,4 @@ -/* Facts we might have about a local. */ +/* Facts we might have about a particular SSA version of a register. */ struct MVMSpeshFacts { /* Flags indicating things we know. */ MVMint32 flags; @@ -24,6 +24,10 @@ struct MVMSpeshFacts { * this is unique). */ MVMSpeshIns *writer; + /* Usages of this version of the register; thanks to SSA form, this taken + * together with writer form a define-use chain. */ + MVMSpeshUsages usage; + /* The deoptimization index in effect at the point of declaration, or -1 * if none yet. */ MVMint32 deopt_idx; diff --git a/src/spesh/usages.c b/src/spesh/usages.c new file mode 100644 index 0000000000..ac9aa5334d --- /dev/null +++ b/src/spesh/usages.c @@ -0,0 +1,68 @@ +#include "moar.h" + +/* Adds a usage of an SSA value. */ +void MVM_spesh_usages_add(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshFacts *facts, MVMSpeshIns *by) { + MVMSpeshUseChainEntry *entry = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshUseChainEntry)); + entry->user = by; + entry->next = facts->usage.users; + facts->usage.users = entry; +} +void MVM_spesh_usages_add_by_reg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand used, MVMSpeshIns *by) { + MVM_spesh_usages_add(tc, g, MVM_spesh_get_facts(tc, g, used), by); +} + +/* Removes a usage of an SSA value. */ +void MVM_spesh_usages_delete(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshFacts *facts, MVMSpeshIns *by) { + MVMSpeshUseChainEntry *cur = facts->usage.users; + MVMSpeshUseChainEntry *prev = NULL; + while (cur) { + if (cur->user == by) { + if (prev) + prev->next = cur->next; + else + facts->usage.users = cur->next; + return; + } + prev = cur; + cur = cur->next; + } + MVM_oops(tc, "Spesh: instruction missing from define-use chain"); +} +void MVM_spesh_usages_delete_by_reg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand used, MVMSpeshIns *by) { + MVM_spesh_usages_delete(tc, g, MVM_spesh_get_facts(tc, g, used), by); +} + +/* Marks that an SSA value is required for deopt purposes. */ +void MVM_spesh_usages_add_for_deopt(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshFacts *facts) { + facts->usage.deopt_required = 1; +} + +/* Checks if the value is used, either by another instruction in the graph or + * by being needed for deopt. */ +MVMuint32 MVM_spesh_usages_is_used(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand check) { + MVMSpeshFacts *facts = MVM_spesh_get_facts(tc, g, check); + return facts->usage.deopt_required || facts->usage.users; +} + +/* Checks if the value is used due to being required for deopt. */ +MVMuint32 MVM_spesh_usages_is_used_by_deopt(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand check) { + MVMSpeshFacts *facts = MVM_spesh_get_facts(tc, g, check); + return facts->usage.deopt_required; +} + +/* Checks if there is precisely one known non-deopt user of the value. */ +MVMuint32 MVM_spesh_usages_used_once(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand check) { + MVMSpeshFacts *facts = MVM_spesh_get_facts(tc, g, check); + return !facts->usage.deopt_required && facts->usage.users && !facts->usage.users->next; +} + +/* Gets the count of usages, excluding use for deopt purposes. */ +MVMuint32 MVM_spesh_usages_count(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand check) { + MVMuint32 count = 0; + MVMSpeshUseChainEntry *cur = MVM_spesh_get_facts(tc, g, check)->usage.users; + while (cur) { + count++; + cur = cur->next; + } + return count; +} diff --git a/src/spesh/usages.h b/src/spesh/usages.h new file mode 100644 index 0000000000..c0720092ad --- /dev/null +++ b/src/spesh/usages.h @@ -0,0 +1,24 @@ +/* Usage information, which is held per SSA written register. */ +struct MVMSpeshUsages { + /* The use chain entries. */ + MVMSpeshUseChainEntry *users; + + /* Does the instruction need to be preserved for the sake of deopt? */ + MVMuint16 deopt_required; +}; + +/* Linked list of using instructions. */ +struct MVMSpeshUseChainEntry { + MVMSpeshIns *user; + MVMSpeshUseChainEntry *next; +}; + +void MVM_spesh_usages_add(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshFacts *facts, MVMSpeshIns *by); +void MVM_spesh_usages_add_by_reg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand used, MVMSpeshIns *by); +void MVM_spesh_usages_delete(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshFacts *facts, MVMSpeshIns *by); +void MVM_spesh_usages_delete_by_reg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand used, MVMSpeshIns *by); +void MVM_spesh_usages_add_for_deopt(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshFacts *facts); +MVMuint32 MVM_spesh_usages_is_used(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand check); +MVMuint32 MVM_spesh_usages_is_used_by_deopt(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand check); +MVMuint32 MVM_spesh_usages_used_once(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand check); +MVMuint32 MVM_spesh_usages_count(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand check); diff --git a/src/types.h b/src/types.h index 727b085d0f..309ede5a24 100644 --- a/src/types.h +++ b/src/types.h @@ -198,6 +198,8 @@ typedef struct MVMSpeshPlan MVMSpeshPlan; typedef struct MVMSpeshPlanned MVMSpeshPlanned; typedef struct MVMSpeshArgGuard MVMSpeshArgGuard; typedef struct MVMSpeshArgGuardNode MVMSpeshArgGuardNode; +typedef struct MVMSpeshUsages MVMSpeshUsages; +typedef struct MVMSpeshUseChainEntry MVMSpeshUseChainEntry; typedef struct MVMSTable MVMSTable; typedef struct MVMStaticFrame MVMStaticFrame; typedef struct MVMStaticFrameBody MVMStaticFrameBody;