1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: MIT
2f08c3bdfSopenharmony_ci//
3f08c3bdfSopenharmony_ci// SSA conversion
4f08c3bdfSopenharmony_ci// Copyright (C) 2005 Luc Van Oostenryck
5f08c3bdfSopenharmony_ci//
6f08c3bdfSopenharmony_ci
7f08c3bdfSopenharmony_ci#include <assert.h>
8f08c3bdfSopenharmony_ci#include "ssa.h"
9f08c3bdfSopenharmony_ci#include "lib.h"
10f08c3bdfSopenharmony_ci#include "dominate.h"
11f08c3bdfSopenharmony_ci#include "flowgraph.h"
12f08c3bdfSopenharmony_ci#include "linearize.h"
13f08c3bdfSopenharmony_ci#include "simplify.h"
14f08c3bdfSopenharmony_ci#include "flow.h"
15f08c3bdfSopenharmony_ci
16f08c3bdfSopenharmony_ci
17f08c3bdfSopenharmony_ci// Is it possible and desirable for this to be promoted to a pseudo?
18f08c3bdfSopenharmony_cistatic inline bool is_promotable(struct symbol *type)
19f08c3bdfSopenharmony_ci{
20f08c3bdfSopenharmony_ci	struct symbol *member;
21f08c3bdfSopenharmony_ci	int bf_seen;
22f08c3bdfSopenharmony_ci	int nbr;
23f08c3bdfSopenharmony_ci
24f08c3bdfSopenharmony_ci	if (type->type == SYM_NODE)
25f08c3bdfSopenharmony_ci		type = type->ctype.base_type;
26f08c3bdfSopenharmony_ci	switch (type->type) {
27f08c3bdfSopenharmony_ci	case SYM_ENUM:
28f08c3bdfSopenharmony_ci	case SYM_BITFIELD:
29f08c3bdfSopenharmony_ci	case SYM_PTR:
30f08c3bdfSopenharmony_ci	case SYM_RESTRICT:	// OK, always integer types
31f08c3bdfSopenharmony_ci		return 1;
32f08c3bdfSopenharmony_ci	case SYM_STRUCT:
33f08c3bdfSopenharmony_ci		// we allow a single scalar field
34f08c3bdfSopenharmony_ci		// but a run of bitfields count for 1
35f08c3bdfSopenharmony_ci		// (and packed bifields are excluded).
36f08c3bdfSopenharmony_ci		if (type->packed)
37f08c3bdfSopenharmony_ci			return 0;
38f08c3bdfSopenharmony_ci		nbr = 0;
39f08c3bdfSopenharmony_ci		bf_seen = 0;
40f08c3bdfSopenharmony_ci		FOR_EACH_PTR(type->symbol_list, member) {
41f08c3bdfSopenharmony_ci			if (is_bitfield_type(member)) {
42f08c3bdfSopenharmony_ci				if (bf_seen)
43f08c3bdfSopenharmony_ci					continue;
44f08c3bdfSopenharmony_ci				bf_seen = 1;
45f08c3bdfSopenharmony_ci			} else {
46f08c3bdfSopenharmony_ci				bf_seen = 0;
47f08c3bdfSopenharmony_ci			}
48f08c3bdfSopenharmony_ci			if (!is_scalar_type(member))
49f08c3bdfSopenharmony_ci				return 0;
50f08c3bdfSopenharmony_ci			if (nbr++)
51f08c3bdfSopenharmony_ci				return 0;
52f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(member);
53f08c3bdfSopenharmony_ci		if (bf_seen && (type->bit_size > long_ctype.bit_size))
54f08c3bdfSopenharmony_ci			return 0;
55f08c3bdfSopenharmony_ci		return 1;
56f08c3bdfSopenharmony_ci	case SYM_UNION:
57f08c3bdfSopenharmony_ci		// FIXME: should be like struct but has problem
58f08c3bdfSopenharmony_ci		//        when used with/for type cohercion
59f08c3bdfSopenharmony_ci		// -----> OK if only same sized integral types
60f08c3bdfSopenharmony_ci		FOR_EACH_PTR(type->symbol_list, member) {
61f08c3bdfSopenharmony_ci			if (member->bit_size != type->bit_size)
62f08c3bdfSopenharmony_ci				return 0;
63f08c3bdfSopenharmony_ci			if (!is_integral_type(member))
64f08c3bdfSopenharmony_ci				return 0;
65f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(member);
66f08c3bdfSopenharmony_ci		return 1;
67f08c3bdfSopenharmony_ci	default:
68f08c3bdfSopenharmony_ci		break;
69f08c3bdfSopenharmony_ci	}
70f08c3bdfSopenharmony_ci	if (type->ctype.base_type == &int_type)
71f08c3bdfSopenharmony_ci		return 1;
72f08c3bdfSopenharmony_ci	if (type->ctype.base_type == &fp_type)
73f08c3bdfSopenharmony_ci		return 1;
74f08c3bdfSopenharmony_ci	return 0;
75f08c3bdfSopenharmony_ci}
76f08c3bdfSopenharmony_ci
77f08c3bdfSopenharmony_cistatic void kill_store(struct instruction *insn)
78f08c3bdfSopenharmony_ci{
79f08c3bdfSopenharmony_ci	remove_use(&insn->src);
80f08c3bdfSopenharmony_ci	remove_use(&insn->target);
81f08c3bdfSopenharmony_ci	insn->bb = NULL;
82f08c3bdfSopenharmony_ci}
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_cistatic bool same_memop(struct instruction *a, struct instruction *b)
85f08c3bdfSopenharmony_ci{
86f08c3bdfSopenharmony_ci	if (a->size != b->size || a->offset != b->offset)
87f08c3bdfSopenharmony_ci		return false;
88f08c3bdfSopenharmony_ci	if (is_integral_type(a->type) && is_float_type(b->type))
89f08c3bdfSopenharmony_ci		return false;
90f08c3bdfSopenharmony_ci	if (is_float_type(a->type) && is_integral_type(b->type))
91f08c3bdfSopenharmony_ci		return false;
92f08c3bdfSopenharmony_ci	return true;
93f08c3bdfSopenharmony_ci}
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_cistatic void rewrite_local_var(struct basic_block *bb, pseudo_t addr, int nbr_stores, int nbr_uses)
96f08c3bdfSopenharmony_ci{
97f08c3bdfSopenharmony_ci	struct instruction *store = NULL;
98f08c3bdfSopenharmony_ci	struct instruction *insn;
99f08c3bdfSopenharmony_ci	bool remove = false;
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_ci	if (!bb)
102f08c3bdfSopenharmony_ci		return;
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_ci	FOR_EACH_PTR(bb->insns, insn) {
105f08c3bdfSopenharmony_ci
106f08c3bdfSopenharmony_ci		if (!insn->bb || insn->src != addr)
107f08c3bdfSopenharmony_ci			continue;
108f08c3bdfSopenharmony_ci		switch (insn->opcode) {
109f08c3bdfSopenharmony_ci		case OP_LOAD:
110f08c3bdfSopenharmony_ci			if (!store)
111f08c3bdfSopenharmony_ci				replace_with_pseudo(insn, undef_pseudo());
112f08c3bdfSopenharmony_ci			else if (same_memop(store, insn))
113f08c3bdfSopenharmony_ci				replace_with_pseudo(insn, store->target);
114f08c3bdfSopenharmony_ci			else
115f08c3bdfSopenharmony_ci				remove = false;
116f08c3bdfSopenharmony_ci			break;
117f08c3bdfSopenharmony_ci		case OP_STORE:
118f08c3bdfSopenharmony_ci			store = insn;
119f08c3bdfSopenharmony_ci			remove = true;
120f08c3bdfSopenharmony_ci			break;
121f08c3bdfSopenharmony_ci		}
122f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(insn);
123f08c3bdfSopenharmony_ci	if (remove)
124f08c3bdfSopenharmony_ci		kill_store(store);
125f08c3bdfSopenharmony_ci}
126f08c3bdfSopenharmony_ci
127f08c3bdfSopenharmony_ci// we would like to know:
128f08c3bdfSopenharmony_ci// is there one or more stores?
129f08c3bdfSopenharmony_ci// are all loads & stores local/done in a single block?
130f08c3bdfSopenharmony_cistatic void ssa_convert_one_var(struct entrypoint *ep, struct symbol *var)
131f08c3bdfSopenharmony_ci{
132f08c3bdfSopenharmony_ci	unsigned long generation = ++bb_generation;
133f08c3bdfSopenharmony_ci	struct basic_block_list *alpha = NULL;
134f08c3bdfSopenharmony_ci	struct basic_block_list *idf = NULL;
135f08c3bdfSopenharmony_ci	struct basic_block *samebb = NULL;
136f08c3bdfSopenharmony_ci	struct basic_block *bb;
137f08c3bdfSopenharmony_ci	struct pseudo_user *pu;
138f08c3bdfSopenharmony_ci	unsigned long mod = var->ctype.modifiers;
139f08c3bdfSopenharmony_ci	bool local = true;
140f08c3bdfSopenharmony_ci	int nbr_stores = 0;
141f08c3bdfSopenharmony_ci	int nbr_uses   = 0;
142f08c3bdfSopenharmony_ci	pseudo_t addr;
143f08c3bdfSopenharmony_ci
144f08c3bdfSopenharmony_ci	/* Never used as a symbol? */
145f08c3bdfSopenharmony_ci	addr = var->pseudo;
146f08c3bdfSopenharmony_ci	if (!addr)
147f08c3bdfSopenharmony_ci		return;
148f08c3bdfSopenharmony_ci
149f08c3bdfSopenharmony_ci	/* We don't do coverage analysis of volatiles.. */
150f08c3bdfSopenharmony_ci	if (mod & MOD_VOLATILE)
151f08c3bdfSopenharmony_ci		return;
152f08c3bdfSopenharmony_ci
153f08c3bdfSopenharmony_ci	/* ..and symbols with external visibility need more care */
154f08c3bdfSopenharmony_ci	mod &= (MOD_NONLOCAL | MOD_STATIC | MOD_ADDRESSABLE);
155f08c3bdfSopenharmony_ci	if (mod)
156f08c3bdfSopenharmony_ci		goto external_visibility;
157f08c3bdfSopenharmony_ci
158f08c3bdfSopenharmony_ci	if (!is_promotable(var))
159f08c3bdfSopenharmony_ci		return;
160f08c3bdfSopenharmony_ci
161f08c3bdfSopenharmony_ci	// 1) insert in the worklist all BBs that may modify var
162f08c3bdfSopenharmony_ci	FOR_EACH_PTR(addr->users, pu) {
163f08c3bdfSopenharmony_ci		struct instruction *insn = pu->insn;
164f08c3bdfSopenharmony_ci		struct basic_block *bb = insn->bb;
165f08c3bdfSopenharmony_ci
166f08c3bdfSopenharmony_ci		switch (insn->opcode) {
167f08c3bdfSopenharmony_ci		case OP_STORE:
168f08c3bdfSopenharmony_ci			nbr_stores++;
169f08c3bdfSopenharmony_ci			if (bb->generation != generation) {
170f08c3bdfSopenharmony_ci				bb->generation = generation;
171f08c3bdfSopenharmony_ci				add_bb(&alpha, bb);
172f08c3bdfSopenharmony_ci			}
173f08c3bdfSopenharmony_ci			/* fall through */
174f08c3bdfSopenharmony_ci		case OP_LOAD:
175f08c3bdfSopenharmony_ci			if (local) {
176f08c3bdfSopenharmony_ci				if (!samebb)
177f08c3bdfSopenharmony_ci					samebb = bb;
178f08c3bdfSopenharmony_ci				else if (samebb != bb)
179f08c3bdfSopenharmony_ci					local = false;
180f08c3bdfSopenharmony_ci			}
181f08c3bdfSopenharmony_ci			nbr_uses++;
182f08c3bdfSopenharmony_ci			break;
183f08c3bdfSopenharmony_ci		case OP_SYMADDR:
184f08c3bdfSopenharmony_ci			mod |= MOD_ADDRESSABLE;
185f08c3bdfSopenharmony_ci			goto external_visibility;
186f08c3bdfSopenharmony_ci		default:
187f08c3bdfSopenharmony_ci			warning(var->pos, "symbol '%s' pseudo used in unexpected way",
188f08c3bdfSopenharmony_ci				show_ident(var->ident));
189f08c3bdfSopenharmony_ci		}
190f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(pu);
191f08c3bdfSopenharmony_ci
192f08c3bdfSopenharmony_ci	// if all uses are local to a single block
193f08c3bdfSopenharmony_ci	// they can easily be rewritten and doesn't need phi-nodes
194f08c3bdfSopenharmony_ci	// FIXME: could be done for extended BB too
195f08c3bdfSopenharmony_ci	if (local) {
196f08c3bdfSopenharmony_ci		rewrite_local_var(samebb, addr, nbr_stores, nbr_uses);
197f08c3bdfSopenharmony_ci		return;
198f08c3bdfSopenharmony_ci	}
199f08c3bdfSopenharmony_ci
200f08c3bdfSopenharmony_ci	idf_compute(ep, &idf, alpha);
201f08c3bdfSopenharmony_ci	FOR_EACH_PTR(idf, bb) {
202f08c3bdfSopenharmony_ci		struct instruction *node = insert_phi_node(bb, var);
203f08c3bdfSopenharmony_ci		node->phi_var = var->pseudo;
204f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(bb);
205f08c3bdfSopenharmony_ci	var->torename = 1;
206f08c3bdfSopenharmony_ci
207f08c3bdfSopenharmony_ciexternal_visibility:
208f08c3bdfSopenharmony_ci	if (mod & (MOD_NONLOCAL | MOD_STATIC))
209f08c3bdfSopenharmony_ci		return;
210f08c3bdfSopenharmony_ci	kill_dead_stores(ep, addr, !mod);
211f08c3bdfSopenharmony_ci}
212f08c3bdfSopenharmony_ci
213f08c3bdfSopenharmony_cistatic struct instruction *lookup_var(struct basic_block *bb, struct symbol *var)
214f08c3bdfSopenharmony_ci{
215f08c3bdfSopenharmony_ci	do {
216f08c3bdfSopenharmony_ci		struct instruction *insn = phi_map_lookup(bb->phi_map, var);
217f08c3bdfSopenharmony_ci		if (insn)
218f08c3bdfSopenharmony_ci			return insn;
219f08c3bdfSopenharmony_ci	} while ((bb = bb->idom));
220f08c3bdfSopenharmony_ci	return NULL;
221f08c3bdfSopenharmony_ci}
222f08c3bdfSopenharmony_ci
223f08c3bdfSopenharmony_cistatic struct instruction_list *phis_all;
224f08c3bdfSopenharmony_cistatic struct instruction_list *phis_used;
225f08c3bdfSopenharmony_cistatic struct instruction_list *stores;
226f08c3bdfSopenharmony_ci
227f08c3bdfSopenharmony_cistatic bool matching_load(struct instruction *def, struct instruction *insn)
228f08c3bdfSopenharmony_ci{
229f08c3bdfSopenharmony_ci	if (insn->size != def->size)
230f08c3bdfSopenharmony_ci		return false;
231f08c3bdfSopenharmony_ci	switch (def->opcode) {
232f08c3bdfSopenharmony_ci	case OP_STORE:
233f08c3bdfSopenharmony_ci	case OP_LOAD:
234f08c3bdfSopenharmony_ci		if (insn->offset != def->offset)
235f08c3bdfSopenharmony_ci			return false;
236f08c3bdfSopenharmony_ci	case OP_PHI:
237f08c3bdfSopenharmony_ci		break;
238f08c3bdfSopenharmony_ci	default:
239f08c3bdfSopenharmony_ci		return false;
240f08c3bdfSopenharmony_ci	}
241f08c3bdfSopenharmony_ci	return true;
242f08c3bdfSopenharmony_ci}
243f08c3bdfSopenharmony_ci
244f08c3bdfSopenharmony_cistatic void ssa_rename_insn(struct basic_block *bb, struct instruction *insn)
245f08c3bdfSopenharmony_ci{
246f08c3bdfSopenharmony_ci	struct instruction *def;
247f08c3bdfSopenharmony_ci	struct symbol *var;
248f08c3bdfSopenharmony_ci	pseudo_t addr;
249f08c3bdfSopenharmony_ci	pseudo_t val;
250f08c3bdfSopenharmony_ci
251f08c3bdfSopenharmony_ci	switch (insn->opcode) {
252f08c3bdfSopenharmony_ci	case OP_STORE:
253f08c3bdfSopenharmony_ci		addr = insn->src;
254f08c3bdfSopenharmony_ci		if (addr->type != PSEUDO_SYM)
255f08c3bdfSopenharmony_ci			break;
256f08c3bdfSopenharmony_ci		var = addr->sym;
257f08c3bdfSopenharmony_ci		if (!var || !var->torename)
258f08c3bdfSopenharmony_ci			break;
259f08c3bdfSopenharmony_ci		phi_map_update(&bb->phi_map, var, insn);
260f08c3bdfSopenharmony_ci		add_instruction(&stores, insn);
261f08c3bdfSopenharmony_ci		break;
262f08c3bdfSopenharmony_ci	case OP_LOAD:
263f08c3bdfSopenharmony_ci		addr = insn->src;
264f08c3bdfSopenharmony_ci		if (addr->type != PSEUDO_SYM)
265f08c3bdfSopenharmony_ci			break;
266f08c3bdfSopenharmony_ci		var = addr->sym;
267f08c3bdfSopenharmony_ci		if (!var || !var->torename)
268f08c3bdfSopenharmony_ci			break;
269f08c3bdfSopenharmony_ci		def = lookup_var(bb, var);
270f08c3bdfSopenharmony_ci		if (!def) {
271f08c3bdfSopenharmony_ci			val = undef_pseudo();
272f08c3bdfSopenharmony_ci		} else if (!matching_load(def, insn)) {
273f08c3bdfSopenharmony_ci			var->torename = false;
274f08c3bdfSopenharmony_ci			break;
275f08c3bdfSopenharmony_ci		} else {
276f08c3bdfSopenharmony_ci			val = def->target;
277f08c3bdfSopenharmony_ci		}
278f08c3bdfSopenharmony_ci		replace_with_pseudo(insn, val);
279f08c3bdfSopenharmony_ci		break;
280f08c3bdfSopenharmony_ci	case OP_PHI:
281f08c3bdfSopenharmony_ci		var = insn->type;
282f08c3bdfSopenharmony_ci		if (!var || !var->torename)
283f08c3bdfSopenharmony_ci			break;
284f08c3bdfSopenharmony_ci		phi_map_update(&bb->phi_map, var, insn);
285f08c3bdfSopenharmony_ci		add_instruction(&phis_all, insn);
286f08c3bdfSopenharmony_ci		break;
287f08c3bdfSopenharmony_ci	}
288f08c3bdfSopenharmony_ci}
289f08c3bdfSopenharmony_ci
290f08c3bdfSopenharmony_cistatic void ssa_rename_insns(struct entrypoint *ep)
291f08c3bdfSopenharmony_ci{
292f08c3bdfSopenharmony_ci	struct basic_block *bb;
293f08c3bdfSopenharmony_ci
294f08c3bdfSopenharmony_ci	FOR_EACH_PTR(ep->bbs, bb) {
295f08c3bdfSopenharmony_ci		struct instruction *insn;
296f08c3bdfSopenharmony_ci		FOR_EACH_PTR(bb->insns, insn) {
297f08c3bdfSopenharmony_ci			if (!insn->bb)
298f08c3bdfSopenharmony_ci				continue;
299f08c3bdfSopenharmony_ci			ssa_rename_insn(bb, insn);
300f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(insn);
301f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(bb);
302f08c3bdfSopenharmony_ci}
303f08c3bdfSopenharmony_ci
304f08c3bdfSopenharmony_cistatic void mark_phi_used(pseudo_t val)
305f08c3bdfSopenharmony_ci{
306f08c3bdfSopenharmony_ci	struct instruction *node;
307f08c3bdfSopenharmony_ci
308f08c3bdfSopenharmony_ci	if (val->type != PSEUDO_REG)
309f08c3bdfSopenharmony_ci		return;
310f08c3bdfSopenharmony_ci	node = val->def;
311f08c3bdfSopenharmony_ci	if (node->opcode != OP_PHI)
312f08c3bdfSopenharmony_ci		return;
313f08c3bdfSopenharmony_ci	if (node->used)
314f08c3bdfSopenharmony_ci		return;
315f08c3bdfSopenharmony_ci	node->used = 1;
316f08c3bdfSopenharmony_ci	add_instruction(&phis_used, node);
317f08c3bdfSopenharmony_ci}
318f08c3bdfSopenharmony_ci
319f08c3bdfSopenharmony_cistatic void ssa_rename_phi(struct instruction *insn)
320f08c3bdfSopenharmony_ci{
321f08c3bdfSopenharmony_ci	struct basic_block *par;
322f08c3bdfSopenharmony_ci	struct symbol *var;
323f08c3bdfSopenharmony_ci
324f08c3bdfSopenharmony_ci	if (!insn->phi_var)
325f08c3bdfSopenharmony_ci		return;
326f08c3bdfSopenharmony_ci	var = insn->phi_var->sym;
327f08c3bdfSopenharmony_ci	if (!var->torename)
328f08c3bdfSopenharmony_ci		return;
329f08c3bdfSopenharmony_ci	FOR_EACH_PTR(insn->bb->parents, par) {
330f08c3bdfSopenharmony_ci		struct instruction *def = lookup_var(par, var);
331f08c3bdfSopenharmony_ci		pseudo_t val = def ? def->target : undef_pseudo();
332f08c3bdfSopenharmony_ci		struct instruction *phisrc = alloc_phisrc(val, var);
333f08c3bdfSopenharmony_ci		pseudo_t phi = phisrc->target;
334f08c3bdfSopenharmony_ci		phi->ident = var->ident;
335f08c3bdfSopenharmony_ci		insert_last_instruction(par, phisrc);
336f08c3bdfSopenharmony_ci		link_phi(insn, phi);
337f08c3bdfSopenharmony_ci		mark_phi_used(val);
338f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(par);
339f08c3bdfSopenharmony_ci}
340f08c3bdfSopenharmony_ci
341f08c3bdfSopenharmony_cistatic void ssa_rename_phis(struct entrypoint *ep)
342f08c3bdfSopenharmony_ci{
343f08c3bdfSopenharmony_ci	struct instruction *phi;
344f08c3bdfSopenharmony_ci
345f08c3bdfSopenharmony_ci	phis_used = NULL;
346f08c3bdfSopenharmony_ci	FOR_EACH_PTR(phis_all, phi) {
347f08c3bdfSopenharmony_ci		if (has_users(phi->target)) {
348f08c3bdfSopenharmony_ci			phi->used = 1;
349f08c3bdfSopenharmony_ci			add_instruction(&phis_used, phi);
350f08c3bdfSopenharmony_ci		}
351f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(phi);
352f08c3bdfSopenharmony_ci
353f08c3bdfSopenharmony_ci	FOR_EACH_PTR(phis_used, phi) {
354f08c3bdfSopenharmony_ci		if (!phi->bb)
355f08c3bdfSopenharmony_ci			continue;
356f08c3bdfSopenharmony_ci		ssa_rename_phi(phi);
357f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(phi);
358f08c3bdfSopenharmony_ci}
359f08c3bdfSopenharmony_ci
360f08c3bdfSopenharmony_cistatic void remove_dead_stores(struct instruction_list *stores)
361f08c3bdfSopenharmony_ci{
362f08c3bdfSopenharmony_ci	struct instruction *store;
363f08c3bdfSopenharmony_ci
364f08c3bdfSopenharmony_ci	FOR_EACH_PTR(stores, store) {
365f08c3bdfSopenharmony_ci		struct symbol *var = store->addr->sym;
366f08c3bdfSopenharmony_ci
367f08c3bdfSopenharmony_ci		if (var->torename)
368f08c3bdfSopenharmony_ci			kill_store(store);
369f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(store);
370f08c3bdfSopenharmony_ci}
371f08c3bdfSopenharmony_ci
372f08c3bdfSopenharmony_civoid ssa_convert(struct entrypoint *ep)
373f08c3bdfSopenharmony_ci{
374f08c3bdfSopenharmony_ci	struct basic_block *bb;
375f08c3bdfSopenharmony_ci	pseudo_t pseudo;
376f08c3bdfSopenharmony_ci	int first, last;
377f08c3bdfSopenharmony_ci
378f08c3bdfSopenharmony_ci	// calculate the number of BBs
379f08c3bdfSopenharmony_ci	first = ep->entry->bb->nr;
380f08c3bdfSopenharmony_ci	last = first;
381f08c3bdfSopenharmony_ci	FOR_EACH_PTR(ep->bbs, bb) {
382f08c3bdfSopenharmony_ci		int nr = bb->nr;
383f08c3bdfSopenharmony_ci		if (nr > last)
384f08c3bdfSopenharmony_ci			last = nr;
385f08c3bdfSopenharmony_ci		bb->phi_map = NULL;
386f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(bb);
387f08c3bdfSopenharmony_ci
388f08c3bdfSopenharmony_ci	// try to promote memory accesses to pseudos
389f08c3bdfSopenharmony_ci	stores = NULL;
390f08c3bdfSopenharmony_ci	FOR_EACH_PTR(ep->accesses, pseudo) {
391f08c3bdfSopenharmony_ci		ssa_convert_one_var(ep, pseudo->sym);
392f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(pseudo);
393f08c3bdfSopenharmony_ci
394f08c3bdfSopenharmony_ci	// rename the converted accesses
395f08c3bdfSopenharmony_ci	phis_all = phis_used = NULL;
396f08c3bdfSopenharmony_ci	ssa_rename_insns(ep);
397f08c3bdfSopenharmony_ci	ssa_rename_phis(ep);
398f08c3bdfSopenharmony_ci
399f08c3bdfSopenharmony_ci	// remove now dead stores
400f08c3bdfSopenharmony_ci	remove_dead_stores(stores);
401f08c3bdfSopenharmony_ci}
402