1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: MIT 2f08c3bdfSopenharmony_ci// 3f08c3bdfSopenharmony_ci// dominate.c - compute the (iterated) dominance frontier of (a set of) nodes. 4f08c3bdfSopenharmony_ci// 5f08c3bdfSopenharmony_ci// Copyright (C) 2017 - Luc Van Oostenryck 6f08c3bdfSopenharmony_ci// 7f08c3bdfSopenharmony_ci// The algorithm used is the one described in: 8f08c3bdfSopenharmony_ci// "A Linear Time Algorithm for Placing phi-nodes" 9f08c3bdfSopenharmony_ci// by Vugranam C. Sreedhar and Guang R. Gao 10f08c3bdfSopenharmony_ci// 11f08c3bdfSopenharmony_ci 12f08c3bdfSopenharmony_ci#include "dominate.h" 13f08c3bdfSopenharmony_ci#include "flowgraph.h" 14f08c3bdfSopenharmony_ci#include "linearize.h" 15f08c3bdfSopenharmony_ci#include "flow.h" 16f08c3bdfSopenharmony_ci#include <assert.h> 17f08c3bdfSopenharmony_ci#include <stdlib.h> 18f08c3bdfSopenharmony_ci#include <stdio.h> 19f08c3bdfSopenharmony_ci 20f08c3bdfSopenharmony_ci 21f08c3bdfSopenharmony_cistruct piggy { 22f08c3bdfSopenharmony_ci unsigned int max; 23f08c3bdfSopenharmony_ci struct basic_block_list *lists[0]; 24f08c3bdfSopenharmony_ci}; 25f08c3bdfSopenharmony_ci 26f08c3bdfSopenharmony_cistatic struct piggy *bank_init(unsigned levels) 27f08c3bdfSopenharmony_ci{ 28f08c3bdfSopenharmony_ci struct piggy *bank; 29f08c3bdfSopenharmony_ci bank = calloc(1, sizeof(*bank) + levels * sizeof(bank->lists[0])); 30f08c3bdfSopenharmony_ci bank->max = levels - 1; 31f08c3bdfSopenharmony_ci return bank; 32f08c3bdfSopenharmony_ci} 33f08c3bdfSopenharmony_ci 34f08c3bdfSopenharmony_cistatic void bank_free(struct piggy *bank, unsigned int levels) 35f08c3bdfSopenharmony_ci{ 36f08c3bdfSopenharmony_ci for (; levels-- ;) 37f08c3bdfSopenharmony_ci free_ptr_list(&bank->lists[levels]); 38f08c3bdfSopenharmony_ci free(bank); 39f08c3bdfSopenharmony_ci} 40f08c3bdfSopenharmony_ci 41f08c3bdfSopenharmony_cistatic void bank_put(struct piggy *bank, struct basic_block *bb) 42f08c3bdfSopenharmony_ci{ 43f08c3bdfSopenharmony_ci unsigned int level = bb->dom_level; 44f08c3bdfSopenharmony_ci assert(level <= bank->max); 45f08c3bdfSopenharmony_ci add_bb(&bank->lists[level], bb); 46f08c3bdfSopenharmony_ci} 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_cistatic inline struct basic_block *pop_bb(struct basic_block_list **list) 49f08c3bdfSopenharmony_ci{ 50f08c3bdfSopenharmony_ci return delete_ptr_list_last((struct ptr_list **)list); 51f08c3bdfSopenharmony_ci} 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_cistatic struct basic_block *bank_get(struct piggy *bank) 54f08c3bdfSopenharmony_ci{ 55f08c3bdfSopenharmony_ci int level = bank->max; 56f08c3bdfSopenharmony_ci do { 57f08c3bdfSopenharmony_ci struct basic_block *bb = pop_bb(&bank->lists[level]); 58f08c3bdfSopenharmony_ci if (bb) 59f08c3bdfSopenharmony_ci return bb; 60f08c3bdfSopenharmony_ci if (!level) 61f08c3bdfSopenharmony_ci return NULL; 62f08c3bdfSopenharmony_ci bank->max = --level; 63f08c3bdfSopenharmony_ci } while (1); 64f08c3bdfSopenharmony_ci} 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_ci#define VISITED 0x1 68f08c3bdfSopenharmony_ci#define INPHI 0x2 69f08c3bdfSopenharmony_ci#define ALPHA 0x4 70f08c3bdfSopenharmony_ci#define FLAGS 0x7 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_cistatic void visit(struct piggy *bank, struct basic_block_list **idf, struct basic_block *x, int curr_level) 73f08c3bdfSopenharmony_ci{ 74f08c3bdfSopenharmony_ci struct basic_block *y; 75f08c3bdfSopenharmony_ci 76f08c3bdfSopenharmony_ci x->generation |= 1; 77f08c3bdfSopenharmony_ci FOR_EACH_PTR(x->children, y) { 78f08c3bdfSopenharmony_ci unsigned flags = y->generation & FLAGS; 79f08c3bdfSopenharmony_ci if (y->idom == x) // J-edges will be processed later 80f08c3bdfSopenharmony_ci continue; 81f08c3bdfSopenharmony_ci if (y->dom_level > curr_level) 82f08c3bdfSopenharmony_ci continue; 83f08c3bdfSopenharmony_ci if (flags & INPHI) 84f08c3bdfSopenharmony_ci continue; 85f08c3bdfSopenharmony_ci y->generation |= INPHI; 86f08c3bdfSopenharmony_ci add_bb(idf, y); 87f08c3bdfSopenharmony_ci if (flags & ALPHA) 88f08c3bdfSopenharmony_ci continue; 89f08c3bdfSopenharmony_ci bank_put(bank, y); 90f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(y); 91f08c3bdfSopenharmony_ci 92f08c3bdfSopenharmony_ci FOR_EACH_PTR(x->doms, y) { 93f08c3bdfSopenharmony_ci if (y->generation & VISITED) 94f08c3bdfSopenharmony_ci continue; 95f08c3bdfSopenharmony_ci visit(bank, idf, y, curr_level); 96f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(y); 97f08c3bdfSopenharmony_ci} 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_civoid idf_compute(struct entrypoint *ep, struct basic_block_list **idf, struct basic_block_list *alpha) 100f08c3bdfSopenharmony_ci{ 101f08c3bdfSopenharmony_ci int levels = ep->dom_levels; 102f08c3bdfSopenharmony_ci struct piggy *bank = bank_init(levels); 103f08c3bdfSopenharmony_ci struct basic_block *bb; 104f08c3bdfSopenharmony_ci unsigned long generation = bb_generation; 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_ci generation = bb_generation; 107f08c3bdfSopenharmony_ci generation += -generation & FLAGS; 108f08c3bdfSopenharmony_ci bb_generation = generation + (FLAGS + 1); 109f08c3bdfSopenharmony_ci 110f08c3bdfSopenharmony_ci // init all the nodes 111f08c3bdfSopenharmony_ci FOR_EACH_PTR(ep->bbs, bb) { 112f08c3bdfSopenharmony_ci // FIXME: this should be removed and the tests for 113f08c3bdfSopenharmony_ci // visited/in_phi/alpha should use a sparse set 114f08c3bdfSopenharmony_ci bb->generation = generation; 115f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(bb); 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_ci FOR_EACH_PTR(alpha, bb) { 118f08c3bdfSopenharmony_ci bb->generation = generation | ALPHA; 119f08c3bdfSopenharmony_ci bank_put(bank, bb); 120f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(bb); 121f08c3bdfSopenharmony_ci 122f08c3bdfSopenharmony_ci while ((bb = bank_get(bank))) { 123f08c3bdfSopenharmony_ci visit(bank, idf, bb, bb->dom_level); 124f08c3bdfSopenharmony_ci } 125f08c3bdfSopenharmony_ci 126f08c3bdfSopenharmony_ci bank_free(bank, levels); 127f08c3bdfSopenharmony_ci} 128f08c3bdfSopenharmony_ci 129f08c3bdfSopenharmony_civoid idf_dump(struct entrypoint *ep) 130f08c3bdfSopenharmony_ci{ 131f08c3bdfSopenharmony_ci struct basic_block *bb; 132f08c3bdfSopenharmony_ci 133f08c3bdfSopenharmony_ci domtree_build(ep); 134f08c3bdfSopenharmony_ci 135f08c3bdfSopenharmony_ci printf("%s's IDF:\n", show_ident(ep->name->ident)); 136f08c3bdfSopenharmony_ci FOR_EACH_PTR(ep->bbs, bb) { 137f08c3bdfSopenharmony_ci struct basic_block_list *alpha = NULL; 138f08c3bdfSopenharmony_ci struct basic_block_list *idf = NULL; 139f08c3bdfSopenharmony_ci struct basic_block *df; 140f08c3bdfSopenharmony_ci 141f08c3bdfSopenharmony_ci add_bb(&alpha, bb); 142f08c3bdfSopenharmony_ci idf_compute(ep, &idf, alpha); 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_ci printf("\t%s\t<-", show_label(bb)); 145f08c3bdfSopenharmony_ci FOR_EACH_PTR(idf, df) { 146f08c3bdfSopenharmony_ci printf(" %s", show_label(df)); 147f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(df); 148f08c3bdfSopenharmony_ci printf("\n"); 149f08c3bdfSopenharmony_ci 150f08c3bdfSopenharmony_ci free_ptr_list(&idf); 151f08c3bdfSopenharmony_ci free_ptr_list(&alpha); 152f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(bb); 153f08c3bdfSopenharmony_ci} 154