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