123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- // SPDX-License-Identifier: MIT
- //
- // dominate.c - compute the (iterated) dominance frontier of (a set of) nodes.
- //
- // Copyright (C) 2017 - Luc Van Oostenryck
- //
- // The algorithm used is the one described in:
- // "A Linear Time Algorithm for Placing phi-nodes"
- // by Vugranam C. Sreedhar and Guang R. Gao
- //
- #include "dominate.h"
- #include "flowgraph.h"
- #include "linearize.h"
- #include "flow.h"
- #include <assert.h>
- #include <stdlib.h>
- #include <stdio.h>
- struct piggy {
- unsigned int max;
- struct basic_block_list *lists[0];
- };
- static struct piggy *bank_init(unsigned levels)
- {
- struct piggy *bank;
- bank = calloc(1, sizeof(*bank) + levels * sizeof(bank->lists[0]));
- bank->max = levels - 1;
- return bank;
- }
- static void bank_free(struct piggy *bank, unsigned int levels)
- {
- for (; levels-- ;)
- free_ptr_list(&bank->lists[levels]);
- free(bank);
- }
- static void bank_put(struct piggy *bank, struct basic_block *bb)
- {
- unsigned int level = bb->dom_level;
- assert(level <= bank->max);
- add_bb(&bank->lists[level], bb);
- }
- static inline struct basic_block *pop_bb(struct basic_block_list **list)
- {
- return delete_ptr_list_last((struct ptr_list **)list);
- }
- static struct basic_block *bank_get(struct piggy *bank)
- {
- int level = bank->max;
- do {
- struct basic_block *bb = pop_bb(&bank->lists[level]);
- if (bb)
- return bb;
- if (!level)
- return NULL;
- bank->max = --level;
- } while (1);
- }
- #define VISITED 0x1
- #define INPHI 0x2
- #define ALPHA 0x4
- #define FLAGS 0x7
- static void visit(struct piggy *bank, struct basic_block_list **idf, struct basic_block *x, int curr_level)
- {
- struct basic_block *y;
- x->generation |= 1;
- FOR_EACH_PTR(x->children, y) {
- unsigned flags = y->generation & FLAGS;
- if (y->idom == x) // J-edges will be processed later
- continue;
- if (y->dom_level > curr_level)
- continue;
- if (flags & INPHI)
- continue;
- y->generation |= INPHI;
- add_bb(idf, y);
- if (flags & ALPHA)
- continue;
- bank_put(bank, y);
- } END_FOR_EACH_PTR(y);
- FOR_EACH_PTR(x->doms, y) {
- if (y->generation & VISITED)
- continue;
- visit(bank, idf, y, curr_level);
- } END_FOR_EACH_PTR(y);
- }
- void idf_compute(struct entrypoint *ep, struct basic_block_list **idf, struct basic_block_list *alpha)
- {
- int levels = ep->dom_levels;
- struct piggy *bank = bank_init(levels);
- struct basic_block *bb;
- unsigned long generation = bb_generation;
- generation = bb_generation;
- generation += -generation & FLAGS;
- bb_generation = generation + (FLAGS + 1);
- // init all the nodes
- FOR_EACH_PTR(ep->bbs, bb) {
- // FIXME: this should be removed and the tests for
- // visited/in_phi/alpha should use a sparse set
- bb->generation = generation;
- } END_FOR_EACH_PTR(bb);
- FOR_EACH_PTR(alpha, bb) {
- bb->generation = generation | ALPHA;
- bank_put(bank, bb);
- } END_FOR_EACH_PTR(bb);
- while ((bb = bank_get(bank))) {
- visit(bank, idf, bb, bb->dom_level);
- }
- bank_free(bank, levels);
- }
- void idf_dump(struct entrypoint *ep)
- {
- struct basic_block *bb;
- domtree_build(ep);
- printf("%s's IDF:\n", show_ident(ep->name->ident));
- FOR_EACH_PTR(ep->bbs, bb) {
- struct basic_block_list *alpha = NULL;
- struct basic_block_list *idf = NULL;
- struct basic_block *df;
- add_bb(&alpha, bb);
- idf_compute(ep, &idf, alpha);
- printf("\t%s\t<-", show_label(bb));
- FOR_EACH_PTR(idf, df) {
- printf(" %s", show_label(df));
- } END_FOR_EACH_PTR(df);
- printf("\n");
- free_ptr_list(&idf);
- free_ptr_list(&alpha);
- } END_FOR_EACH_PTR(bb);
- }
|