Skip to content

Commit

Permalink
issue #30 Start implementing liveness analysis
Browse files Browse the repository at this point in the history
  • Loading branch information
dibyendumajumdar committed Jul 26, 2020
1 parent ef8c77b commit 77cccce
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 5 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ set(SRCS
src/dataflow_framework.c
src/opt_unusedcode.c
src/membuf.c
src/df_liveness.c
)

message("SOURCE dir is ${RaviCompiler_SOURCE_DIR}")
Expand Down
3 changes: 3 additions & 0 deletions src/bitset.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
#ifndef ravicomp_BITSET_H
#define ravicomp_BITSET_H

#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif
Expand Down
5 changes: 1 addition & 4 deletions src/dataflow_framework.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@

DECLARE_ARRAY(node_array, struct node *);

/**
* The data flow framework is based on the implementation in MIR project.
* https://github.com/vnmakarov/mir
*/
struct dataflow_context {
struct graph *g;
struct node_array worklist;
Expand Down Expand Up @@ -69,6 +65,7 @@ void raviX_solve_dataflow(struct graph *g, bool forward_p,
int changed_p = iter == 0;
struct node *bb = addr[i];
struct node_list *nodes = forward_p ? raviX_predecessors(bb) : raviX_successors(bb);
// TODO should we pass the nodes array to the join function?
if (raviX_node_list_size(nodes) == 0)
join_function(ctx.userdata, raviX_node_index(bb), true);
else
Expand Down
2 changes: 1 addition & 1 deletion src/dataflow_framework.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
extern void raviX_solve_dataflow(
struct graph *g,
bool forward_p, /* Set to true for forward data flow */
int (*join_function)(void *userdata, nodeId_t, bool init), /* Join/Meet operator - init will be true when no successors/predecessors */
int (*join_function)(void *userdata, nodeId_t, bool init), /* Join/Meet operator - if init is true reset the bitsets */
int (*transfer_function)(void *userdata, nodeId_t), /* transfer function */
void *userdata); /* pointer to user data, will be passed to join/transfer functions */

Expand Down
99 changes: 99 additions & 0 deletions src/df_liveness.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Calculate variable liveness
* This will use the Dataflow Framework.
* Implementation inspired by one in MIR
*/


#include "bitset.h"
#include "dataflow_framework.h"
#include "linearizer.h"

struct liveness_info {
nodeId_t node_id;
struct bitset_t in;
struct bitset_t out;
struct bitset_t use;
struct bitset_t def;
};

DECLARE_ARRAY(liveness_info_array, struct liveness_info *);

struct liveness_data {
struct proc *proc;
struct liveness_info_array lives;
};

void init_liveness_data(struct proc *proc, struct liveness_data *liveness_data)
{
memset(liveness_data, 0, sizeof(*liveness_data));
for (unsigned i = 0; i < proc->node_count; i++) {
struct liveness_info *liveness_info = (struct liveness_info *)calloc(1, sizeof(struct liveness_info));
liveness_info->node_id = i;
raviX_bitset_create(&liveness_info->use);
raviX_bitset_create(&liveness_info->def);
raviX_bitset_create(&liveness_info->in);
raviX_bitset_create(&liveness_info->out);
array_push(&liveness_data->lives, liveness_info);
}
}

void destroy_liveness_data(struct liveness_data *liveness_data)
{
for (unsigned i = 0; i < liveness_data->lives.count; i++) {
raviX_bitset_create(&liveness_data->lives.data[i]->use);
raviX_bitset_create(&liveness_data->lives.data[i]->def);
raviX_bitset_create(&liveness_data->lives.data[i]->in);
raviX_bitset_create(&liveness_data->lives.data[i]->out);
}
array_clearmem(&liveness_data->lives);
}

static inline struct liveness_info *get_liveness_info(struct liveness_data *liveness_data, nodeId_t id)
{
return liveness_data->lives.data[id];
}

/* Life analysis */
static int live_join_func(void *userdata, nodeId_t id, bool init)
{
struct liveness_data *liveness_data = (struct liveness_data *)userdata;
struct liveness_info *liveness_info = get_liveness_info(liveness_data, id);
if (init) {
raviX_bitset_clear(&liveness_info->in);
return 0;
} else {
struct node_list *successors = raviX_successors(raviX_graph_node(liveness_data->proc->cfg, id));
int changed = 0;
// out[n] = Union of in[s] where s in succ[n]
for (unsigned i = 0; i < raviX_node_list_size(successors); i++) {
nodeId_t succ_id = raviX_node_list_at(successors, i);
struct liveness_info *successor_liveness_info = get_liveness_info(liveness_data, succ_id);
changed |=
raviX_bitset_ior(&liveness_info->out, &liveness_info->out, &successor_liveness_info->in);
}
return changed;
}
}

static int live_transfer_func(void *userdata, nodeId_t id)
{
struct liveness_data *liveness_data = (struct liveness_data *)userdata;
struct liveness_info *liveness_info = get_liveness_info(liveness_data, id);
// out[n] = use[n] U (out[n] - def[n])
// In bitset terms out[n] = use[n] | (out[n] & ~def[n])
return raviX_bitset_ior_and_compl(&liveness_info->in, &liveness_info->use, &liveness_info->out,
&liveness_info->def);
}

// TODO

// Compute use/def sets of each node
// If a reg appears as the target of an instruction that's a def
// If a reg is used as operand then its a use
// Need to handle ranges / var args too
// Or should we restrict analysis to certain types of regs?

// Right now we have disjoint sets for temps / locals - to do this efficiently we need a merged set of regs for each proc
// Liveness analysis is a backward data flow problem
// see calculate_func_cfg_live_info in mir_genc.c

0 comments on commit 77cccce

Please sign in to comment.