-
Notifications
You must be signed in to change notification settings - Fork 5
Data Flow Analysis
Dibyendu Majumdar edited this page Jul 25, 2020
·
3 revisions
- We have a reusable framework for the solver that is based on the implementation in MIR (details below). This is in dataflow_framework.c
- Useful video Foundations of Data Flow Analysis
MIR code is below:
static int rpost_cmp (const void *a1, const void *a2) {
return (*(const struct bb **) a1)->rpost - (*(const struct bb **) a2)->rpost;
}
static int post_cmp (const void *a1, const void *a2) { return -rpost_cmp (a1, a2); }
DEF_VARR (bb_t);
struct data_flow_ctx {
VARR (bb_t) * worklist, *pending;
bitmap_t bb_to_consider;
};
#define worklist gen_ctx->data_flow_ctx->worklist
#define pending gen_ctx->data_flow_ctx->pending
#define bb_to_consider gen_ctx->data_flow_ctx->bb_to_consider
static void solve_dataflow (gen_ctx_t gen_ctx, int forward_p, void (*con_func_0) (bb_t),
int (*con_func_n) (gen_ctx_t, bb_t),
int (*trans_func) (gen_ctx_t, bb_t)) {
size_t i, iter;
bb_t bb, *addr;
VARR (bb_t) * t;
VARR_TRUNC (bb_t, worklist, 0);
for (bb = DLIST_HEAD (bb_t, curr_cfg->bbs); bb != NULL; bb = DLIST_NEXT (bb_t, bb))
VARR_PUSH (bb_t, worklist, bb);
VARR_TRUNC (bb_t, pending, 0);
iter = 0;
while (VARR_LENGTH (bb_t, worklist) != 0) {
VARR_TRUNC (bb_t, pending, 0);
addr = VARR_ADDR (bb_t, worklist);
qsort (addr, VARR_LENGTH (bb_t, worklist), sizeof (bb), forward_p ? rpost_cmp : post_cmp);
bitmap_clear (bb_to_consider);
for (i = 0; i < VARR_LENGTH (bb_t, worklist); i++) {
int changed_p = iter == 0;
edge_t e;
bb = addr[i];
if (forward_p) {
if (DLIST_HEAD (in_edge_t, bb->in_edges) == NULL)
con_func_0 (bb);
else
changed_p |= con_func_n (gen_ctx, bb);
} else {
if (DLIST_HEAD (out_edge_t, bb->out_edges) == NULL)
con_func_0 (bb);
else
changed_p |= con_func_n (gen_ctx, bb);
}
if (changed_p && trans_func (gen_ctx, bb)) {
if (forward_p) {
for (e = DLIST_HEAD (out_edge_t, bb->out_edges); e != NULL;
e = DLIST_NEXT (out_edge_t, e))
if (bitmap_set_bit_p (bb_to_consider, e->dst->index)) VARR_PUSH (bb_t, pending, e->dst);
} else {
for (e = DLIST_HEAD (in_edge_t, bb->in_edges); e != NULL; e = DLIST_NEXT (in_edge_t, e))
if (bitmap_set_bit_p (bb_to_consider, e->src->index)) VARR_PUSH (bb_t, pending, e->src);
}
}
}
iter++;
t = worklist;
worklist = pending;
pending = t;
}
}
static void init_data_flow (gen_ctx_t gen_ctx) {
gen_ctx->data_flow_ctx = gen_malloc (gen_ctx, sizeof (struct data_flow_ctx));
VARR_CREATE (bb_t, worklist, 0);
VARR_CREATE (bb_t, pending, 0);
bb_to_consider = bitmap_create2 (512);
}
static void finish_data_flow (gen_ctx_t gen_ctx) {
VARR_DESTROY (bb_t, worklist);
VARR_DESTROY (bb_t, pending);
bitmap_destroy (bb_to_consider);
free (gen_ctx->data_flow_ctx);
gen_ctx->data_flow_ctx = NULL;
}
The rpost
field in basic nock is computed as below.
This appears to be based on algorithm 3.2 Basic Depth-First Search Algorithm in Building an Optimizing Compiler.
static void DFS (bb_t bb, size_t *pre, size_t *rpost) {
edge_t e;
bb->pre = (*pre)++;
for (e = DLIST_HEAD (out_edge_t, bb->out_edges); e != NULL; e = DLIST_NEXT (out_edge_t, e))
if (e->dst->pre == 0)
DFS (e->dst, pre, rpost);
else if (e->dst->rpost == 0)
e->back_edge_p = TRUE;
bb->rpost = (*rpost)--;
}
static void enumerate_bbs (gen_ctx_t gen_ctx) {
size_t pre, rpost;
pre = 1;
rpost = DLIST_LENGTH (bb_t, curr_cfg->bbs);
DFS (DLIST_HEAD (bb_t, curr_cfg->bbs), &pre, &rpost);
}