1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * Storage - associate pseudos with "storage" that keeps them alive
3f08c3bdfSopenharmony_ci * between basic blocks.  The aim is to be able to turn as much of
4f08c3bdfSopenharmony_ci * the global storage allocation problem as possible into a local
5f08c3bdfSopenharmony_ci * per-basic-block one.
6f08c3bdfSopenharmony_ci *
7f08c3bdfSopenharmony_ci * Copyright (C) 2004 Linus Torvalds
8f08c3bdfSopenharmony_ci */
9f08c3bdfSopenharmony_ci#include <stdio.h>
10f08c3bdfSopenharmony_ci#include <stdlib.h>
11f08c3bdfSopenharmony_ci#include <assert.h>
12f08c3bdfSopenharmony_ci
13f08c3bdfSopenharmony_ci#include "symbol.h"
14f08c3bdfSopenharmony_ci#include "expression.h"
15f08c3bdfSopenharmony_ci#include "linearize.h"
16f08c3bdfSopenharmony_ci#include "storage.h"
17f08c3bdfSopenharmony_ci
18f08c3bdfSopenharmony_ciALLOCATOR(storage, "storages");
19f08c3bdfSopenharmony_ciALLOCATOR(storage_hash, "storage hash");
20f08c3bdfSopenharmony_ci
21f08c3bdfSopenharmony_ci#define MAX_STORAGE_HASH 64
22f08c3bdfSopenharmony_cistatic struct storage_hash_list *storage_hash_table[MAX_STORAGE_HASH];
23f08c3bdfSopenharmony_ci
24f08c3bdfSopenharmony_cistatic inline unsigned int storage_hash(struct basic_block *bb, pseudo_t pseudo, enum inout_enum inout)
25f08c3bdfSopenharmony_ci{
26f08c3bdfSopenharmony_ci	unsigned hash = hashval(bb) + hashval(pseudo) + hashval(inout);
27f08c3bdfSopenharmony_ci	hash += hash / MAX_STORAGE_HASH;
28f08c3bdfSopenharmony_ci	return hash & (MAX_STORAGE_HASH-1);
29f08c3bdfSopenharmony_ci}
30f08c3bdfSopenharmony_ci
31f08c3bdfSopenharmony_cistatic int hash_list_cmp(const void *_a, const void *_b)
32f08c3bdfSopenharmony_ci{
33f08c3bdfSopenharmony_ci	const struct storage_hash *a = _a;
34f08c3bdfSopenharmony_ci	const struct storage_hash *b = _b;
35f08c3bdfSopenharmony_ci	if (a->pseudo != b->pseudo)
36f08c3bdfSopenharmony_ci		return a->pseudo < b->pseudo ? -1 : 1;
37f08c3bdfSopenharmony_ci	return 0;
38f08c3bdfSopenharmony_ci}
39f08c3bdfSopenharmony_ci
40f08c3bdfSopenharmony_cistatic void sort_hash_list(struct storage_hash_list **listp)
41f08c3bdfSopenharmony_ci{
42f08c3bdfSopenharmony_ci	sort_list((struct ptr_list **)listp, hash_list_cmp);
43f08c3bdfSopenharmony_ci}
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_cistruct storage_hash_list *gather_storage(struct basic_block *bb, enum inout_enum inout)
46f08c3bdfSopenharmony_ci{
47f08c3bdfSopenharmony_ci	int i;
48f08c3bdfSopenharmony_ci	struct storage_hash *entry, *prev;
49f08c3bdfSopenharmony_ci	struct storage_hash_list *list = NULL;
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_ci	for (i = 0; i < MAX_STORAGE_HASH; i++) {
52f08c3bdfSopenharmony_ci		struct storage_hash *hash;
53f08c3bdfSopenharmony_ci		FOR_EACH_PTR(storage_hash_table[i], hash) {
54f08c3bdfSopenharmony_ci			if (hash->bb == bb && hash->inout == inout)
55f08c3bdfSopenharmony_ci				add_ptr_list(&list, hash);
56f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(hash);
57f08c3bdfSopenharmony_ci	}
58f08c3bdfSopenharmony_ci	sort_hash_list(&list);
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_ci	prev = NULL;
61f08c3bdfSopenharmony_ci	FOR_EACH_PTR(list, entry) {
62f08c3bdfSopenharmony_ci		if (prev && entry->pseudo == prev->pseudo) {
63f08c3bdfSopenharmony_ci			assert(entry == prev);
64f08c3bdfSopenharmony_ci			DELETE_CURRENT_PTR(entry);
65f08c3bdfSopenharmony_ci		}
66f08c3bdfSopenharmony_ci		prev = entry;
67f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(entry);
68f08c3bdfSopenharmony_ci	PACK_PTR_LIST(&list);
69f08c3bdfSopenharmony_ci	return list;
70f08c3bdfSopenharmony_ci}
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_cistatic void name_storage(void)
73f08c3bdfSopenharmony_ci{
74f08c3bdfSopenharmony_ci	int i;
75f08c3bdfSopenharmony_ci	int name = 0;
76f08c3bdfSopenharmony_ci
77f08c3bdfSopenharmony_ci	for (i = 0; i < MAX_STORAGE_HASH; i++) {
78f08c3bdfSopenharmony_ci		struct storage_hash *hash;
79f08c3bdfSopenharmony_ci		FOR_EACH_PTR(storage_hash_table[i], hash) {
80f08c3bdfSopenharmony_ci			struct storage *storage = hash->storage;
81f08c3bdfSopenharmony_ci			if (storage->name)
82f08c3bdfSopenharmony_ci				continue;
83f08c3bdfSopenharmony_ci			storage->name = ++name;
84f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(hash);
85f08c3bdfSopenharmony_ci	}
86f08c3bdfSopenharmony_ci}
87f08c3bdfSopenharmony_ci
88f08c3bdfSopenharmony_cistruct storage *lookup_storage(struct basic_block *bb, pseudo_t pseudo, enum inout_enum inout)
89f08c3bdfSopenharmony_ci{
90f08c3bdfSopenharmony_ci	struct storage_hash_list *list = storage_hash_table[storage_hash(bb,pseudo,inout)];
91f08c3bdfSopenharmony_ci	struct storage_hash *hash;
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_ci	FOR_EACH_PTR(list, hash) {
94f08c3bdfSopenharmony_ci		if (hash->bb == bb && hash->pseudo == pseudo && hash->inout == inout)
95f08c3bdfSopenharmony_ci			return hash->storage;
96f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(hash);
97f08c3bdfSopenharmony_ci	return NULL;
98f08c3bdfSopenharmony_ci}
99f08c3bdfSopenharmony_ci
100f08c3bdfSopenharmony_civoid add_storage(struct storage *storage, struct basic_block *bb, pseudo_t pseudo, enum inout_enum inout)
101f08c3bdfSopenharmony_ci{
102f08c3bdfSopenharmony_ci	struct storage_hash_list **listp = storage_hash_table + storage_hash(bb,pseudo,inout);
103f08c3bdfSopenharmony_ci	struct storage_hash *hash = alloc_storage_hash(storage);
104f08c3bdfSopenharmony_ci
105f08c3bdfSopenharmony_ci	hash->bb = bb;
106f08c3bdfSopenharmony_ci	hash->pseudo = pseudo;
107f08c3bdfSopenharmony_ci	hash->inout = inout;
108f08c3bdfSopenharmony_ci
109f08c3bdfSopenharmony_ci	add_ptr_list(listp, hash);
110f08c3bdfSopenharmony_ci}
111f08c3bdfSopenharmony_ci
112f08c3bdfSopenharmony_ci
113f08c3bdfSopenharmony_cistatic int storage_hash_cmp(const void *_a, const void *_b)
114f08c3bdfSopenharmony_ci{
115f08c3bdfSopenharmony_ci	const struct storage_hash *a = _a;
116f08c3bdfSopenharmony_ci	const struct storage_hash *b = _b;
117f08c3bdfSopenharmony_ci	struct storage *aa = a->storage;
118f08c3bdfSopenharmony_ci	struct storage *bb = b->storage;
119f08c3bdfSopenharmony_ci
120f08c3bdfSopenharmony_ci	if (a->bb != b->bb)
121f08c3bdfSopenharmony_ci		return a->bb < b->bb ? -1 : 1;
122f08c3bdfSopenharmony_ci	if (a->inout != b->inout)
123f08c3bdfSopenharmony_ci		return a->inout < b->inout ? -1 : 1;
124f08c3bdfSopenharmony_ci	if (aa->type != bb->type)
125f08c3bdfSopenharmony_ci		return aa->type < bb->type ? -1 : 1;
126f08c3bdfSopenharmony_ci	if (aa->regno != bb->regno)
127f08c3bdfSopenharmony_ci		return aa->regno < bb->regno ? -1 : 1;
128f08c3bdfSopenharmony_ci	return 0;
129f08c3bdfSopenharmony_ci}
130f08c3bdfSopenharmony_ci
131f08c3bdfSopenharmony_cistatic void vrfy_storage(struct storage_hash_list **listp)
132f08c3bdfSopenharmony_ci{
133f08c3bdfSopenharmony_ci	struct storage_hash *entry, *last;
134f08c3bdfSopenharmony_ci
135f08c3bdfSopenharmony_ci	sort_list((struct ptr_list **)listp, storage_hash_cmp);
136f08c3bdfSopenharmony_ci	last = NULL;
137f08c3bdfSopenharmony_ci	FOR_EACH_PTR(*listp, entry) {
138f08c3bdfSopenharmony_ci		if (last) {
139f08c3bdfSopenharmony_ci			struct storage *a = last->storage;
140f08c3bdfSopenharmony_ci			struct storage *b = entry->storage;
141f08c3bdfSopenharmony_ci			if (a == b)
142f08c3bdfSopenharmony_ci				continue;
143f08c3bdfSopenharmony_ci			if (last->bb == entry->bb
144f08c3bdfSopenharmony_ci			    && last->inout == entry->inout
145f08c3bdfSopenharmony_ci			    && a->type != REG_UDEF
146f08c3bdfSopenharmony_ci			    && a->type == b->type
147f08c3bdfSopenharmony_ci			    && a->regno == b->regno) {
148f08c3bdfSopenharmony_ci				printf("\t BAD: same storage as %s in %p: %s (%s and %s)\n",
149f08c3bdfSopenharmony_ci					last->inout == STOR_IN ? "input" : "output",
150f08c3bdfSopenharmony_ci					last->bb,
151f08c3bdfSopenharmony_ci					show_storage(a),
152f08c3bdfSopenharmony_ci					show_pseudo(last->pseudo),
153f08c3bdfSopenharmony_ci					show_pseudo(entry->pseudo));
154f08c3bdfSopenharmony_ci			}
155f08c3bdfSopenharmony_ci		}
156f08c3bdfSopenharmony_ci		last = entry;
157f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(entry);
158f08c3bdfSopenharmony_ci}
159f08c3bdfSopenharmony_ci
160f08c3bdfSopenharmony_civoid free_storage(void)
161f08c3bdfSopenharmony_ci{
162f08c3bdfSopenharmony_ci	int i;
163f08c3bdfSopenharmony_ci
164f08c3bdfSopenharmony_ci	for (i = 0; i < MAX_STORAGE_HASH; i++) {
165f08c3bdfSopenharmony_ci		vrfy_storage(storage_hash_table + i);
166f08c3bdfSopenharmony_ci		free_ptr_list(storage_hash_table + i);
167f08c3bdfSopenharmony_ci	}
168f08c3bdfSopenharmony_ci}
169f08c3bdfSopenharmony_ci
170f08c3bdfSopenharmony_ciconst char *show_storage(struct storage *s)
171f08c3bdfSopenharmony_ci{
172f08c3bdfSopenharmony_ci	static char buffer[1024];
173f08c3bdfSopenharmony_ci	if (!s)
174f08c3bdfSopenharmony_ci		return "none";
175f08c3bdfSopenharmony_ci	switch (s->type) {
176f08c3bdfSopenharmony_ci	case REG_REG:
177f08c3bdfSopenharmony_ci		sprintf(buffer, "reg%d (%d)", s->regno, s->name);
178f08c3bdfSopenharmony_ci		break;
179f08c3bdfSopenharmony_ci	case REG_STACK:
180f08c3bdfSopenharmony_ci		sprintf(buffer, "%d(SP) (%d)", s->offset, s->name);
181f08c3bdfSopenharmony_ci		break;
182f08c3bdfSopenharmony_ci	case REG_ARG:
183f08c3bdfSopenharmony_ci		sprintf(buffer, "ARG%d (%d)", s->regno, s->name);
184f08c3bdfSopenharmony_ci		break;
185f08c3bdfSopenharmony_ci	default:
186f08c3bdfSopenharmony_ci		sprintf(buffer, "%d:%d (%d)", s->type, s->regno, s->name);
187f08c3bdfSopenharmony_ci		break;
188f08c3bdfSopenharmony_ci	}
189f08c3bdfSopenharmony_ci	return buffer;
190f08c3bdfSopenharmony_ci}
191f08c3bdfSopenharmony_ci
192f08c3bdfSopenharmony_ci/*
193f08c3bdfSopenharmony_ci * Combine two storage allocations into one.
194f08c3bdfSopenharmony_ci *
195f08c3bdfSopenharmony_ci * We just randomly pick one over the other, and replace
196f08c3bdfSopenharmony_ci * the other uses.
197f08c3bdfSopenharmony_ci */
198f08c3bdfSopenharmony_cistatic struct storage * combine_storage(struct storage *src, struct storage *dst)
199f08c3bdfSopenharmony_ci{
200f08c3bdfSopenharmony_ci	struct storage **usep;
201f08c3bdfSopenharmony_ci
202f08c3bdfSopenharmony_ci	/* Remove uses of "src_storage", replace with "dst" */
203f08c3bdfSopenharmony_ci	FOR_EACH_PTR(src->users, usep) {
204f08c3bdfSopenharmony_ci		assert(*usep == src);
205f08c3bdfSopenharmony_ci		*usep = dst;
206f08c3bdfSopenharmony_ci		add_ptr_list(&dst->users, usep);
207f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(usep);
208f08c3bdfSopenharmony_ci
209f08c3bdfSopenharmony_ci	/* Mark it unused */
210f08c3bdfSopenharmony_ci	src->type = REG_BAD;
211f08c3bdfSopenharmony_ci	src->users = NULL;
212f08c3bdfSopenharmony_ci	return dst;
213f08c3bdfSopenharmony_ci}
214f08c3bdfSopenharmony_ci
215f08c3bdfSopenharmony_cistatic void set_up_bb_storage(struct basic_block *bb)
216f08c3bdfSopenharmony_ci{
217f08c3bdfSopenharmony_ci	struct basic_block *child;
218f08c3bdfSopenharmony_ci
219f08c3bdfSopenharmony_ci	FOR_EACH_PTR(bb->children, child) {
220f08c3bdfSopenharmony_ci		pseudo_t pseudo;
221f08c3bdfSopenharmony_ci		FOR_EACH_PTR(child->needs, pseudo) {
222f08c3bdfSopenharmony_ci			struct storage *child_in, *parent_out;
223f08c3bdfSopenharmony_ci
224f08c3bdfSopenharmony_ci			parent_out = lookup_storage(bb, pseudo, STOR_OUT);
225f08c3bdfSopenharmony_ci			child_in = lookup_storage(child, pseudo, STOR_IN);
226f08c3bdfSopenharmony_ci
227f08c3bdfSopenharmony_ci			if (parent_out) {
228f08c3bdfSopenharmony_ci				if (!child_in) {
229f08c3bdfSopenharmony_ci					add_storage(parent_out, child, pseudo, STOR_IN);
230f08c3bdfSopenharmony_ci					continue;
231f08c3bdfSopenharmony_ci				}
232f08c3bdfSopenharmony_ci				if (parent_out == child_in)
233f08c3bdfSopenharmony_ci					continue;
234f08c3bdfSopenharmony_ci				combine_storage(parent_out, child_in);
235f08c3bdfSopenharmony_ci				continue;
236f08c3bdfSopenharmony_ci			}
237f08c3bdfSopenharmony_ci			if (child_in) {
238f08c3bdfSopenharmony_ci				add_storage(child_in, bb, pseudo, STOR_OUT);
239f08c3bdfSopenharmony_ci				continue;
240f08c3bdfSopenharmony_ci			}
241f08c3bdfSopenharmony_ci			parent_out = alloc_storage();
242f08c3bdfSopenharmony_ci			add_storage(parent_out, bb, pseudo, STOR_OUT);
243f08c3bdfSopenharmony_ci			add_storage(parent_out, child, pseudo, STOR_IN);
244f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(pseudo);
245f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(child);
246f08c3bdfSopenharmony_ci}
247f08c3bdfSopenharmony_ci
248f08c3bdfSopenharmony_cistatic void set_up_argument_storage(struct entrypoint *ep, struct basic_block *bb)
249f08c3bdfSopenharmony_ci{
250f08c3bdfSopenharmony_ci	pseudo_t arg;
251f08c3bdfSopenharmony_ci
252f08c3bdfSopenharmony_ci	FOR_EACH_PTR(bb->needs, arg) {
253f08c3bdfSopenharmony_ci		struct storage *storage = alloc_storage();
254f08c3bdfSopenharmony_ci
255f08c3bdfSopenharmony_ci		/* FIXME! Totally made-up argument passing conventions */
256f08c3bdfSopenharmony_ci		if (arg->type == PSEUDO_ARG) {
257f08c3bdfSopenharmony_ci			storage->type = REG_ARG;
258f08c3bdfSopenharmony_ci			storage->regno = arg->nr;
259f08c3bdfSopenharmony_ci		}
260f08c3bdfSopenharmony_ci		add_storage(storage, bb, arg, STOR_IN);
261f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(arg);
262f08c3bdfSopenharmony_ci}
263f08c3bdfSopenharmony_ci
264f08c3bdfSopenharmony_civoid set_up_storage(struct entrypoint *ep)
265f08c3bdfSopenharmony_ci{
266f08c3bdfSopenharmony_ci	struct basic_block *bb;
267f08c3bdfSopenharmony_ci
268f08c3bdfSopenharmony_ci	/* First set up storage for the incoming arguments */
269f08c3bdfSopenharmony_ci	set_up_argument_storage(ep, ep->entry->bb);
270f08c3bdfSopenharmony_ci
271f08c3bdfSopenharmony_ci	/* Then do a list of all the inter-bb storage */
272f08c3bdfSopenharmony_ci	FOR_EACH_PTR(ep->bbs, bb) {
273f08c3bdfSopenharmony_ci		set_up_bb_storage(bb);
274f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(bb);
275f08c3bdfSopenharmony_ci
276f08c3bdfSopenharmony_ci	name_storage();
277f08c3bdfSopenharmony_ci}
278