1 // SPDX-License-Identifier: MIT
4 // Copyright (C) 2005 Luc Van Oostenryck
11 #include "flowgraph.h"
12 #include "linearize.h"
17 // Is it possible and desirable for this to be promoted to a pseudo?
18 static inline bool is_promotable(struct symbol
*type
)
20 struct symbol
*member
;
24 if (type
->type
== SYM_NODE
)
25 type
= type
->ctype
.base_type
;
30 case SYM_RESTRICT
: // OK, always integer types
33 // we allow a single scalar field
34 // but a run of bitfields count for 1
35 // (and packed bifields are excluded).
40 FOR_EACH_PTR(type
->symbol_list
, member
) {
41 if (is_bitfield_type(member
)) {
48 if (!is_scalar_type(member
))
52 } END_FOR_EACH_PTR(member
);
53 if (bf_seen
&& (type
->bit_size
> long_ctype
.bit_size
))
57 // FIXME: should be like struct but has problem
58 // when used with/for type cohercion
59 // -----> OK if only same sized integral types
60 FOR_EACH_PTR(type
->symbol_list
, member
) {
61 if (member
->bit_size
!= type
->bit_size
)
63 if (!is_integral_type(member
))
65 } END_FOR_EACH_PTR(member
);
70 if (type
->ctype
.base_type
== &int_type
)
72 if (type
->ctype
.base_type
== &fp_type
)
77 static void kill_store(struct instruction
*insn
)
79 remove_use(&insn
->src
);
80 remove_use(&insn
->target
);
84 static bool same_memop(struct instruction
*a
, struct instruction
*b
)
86 if (a
->size
!= b
->size
|| a
->offset
!= b
->offset
)
88 if (is_integral_type(a
->type
) && is_float_type(b
->type
))
90 if (is_float_type(a
->type
) && is_integral_type(b
->type
))
95 static void rewrite_local_var(struct basic_block
*bb
, pseudo_t addr
, int nbr_stores
, int nbr_uses
)
97 struct instruction
*store
= NULL
;
98 struct instruction
*insn
;
104 FOR_EACH_PTR(bb
->insns
, insn
) {
106 if (!insn
->bb
|| insn
->src
!= addr
)
108 switch (insn
->opcode
) {
111 replace_with_pseudo(insn
, undef_pseudo());
112 else if (same_memop(store
, insn
))
113 replace_with_pseudo(insn
, store
->target
);
122 } END_FOR_EACH_PTR(insn
);
127 // we would like to know:
128 // is there one or more stores?
129 // are all loads & stores local/done in a single block?
130 static void ssa_convert_one_var(struct entrypoint
*ep
, struct symbol
*var
)
132 unsigned long generation
= ++bb_generation
;
133 struct basic_block_list
*alpha
= NULL
;
134 struct basic_block_list
*idf
= NULL
;
135 struct basic_block
*samebb
= NULL
;
136 struct basic_block
*bb
;
137 struct pseudo_user
*pu
;
138 unsigned long mod
= var
->ctype
.modifiers
;
144 /* Never used as a symbol? */
149 /* We don't do coverage analysis of volatiles.. */
150 if (mod
& MOD_VOLATILE
)
153 /* ..and symbols with external visibility need more care */
154 mod
&= (MOD_NONLOCAL
| MOD_STATIC
| MOD_ADDRESSABLE
);
156 goto external_visibility
;
158 if (!is_promotable(var
))
161 // 1) insert in the worklist all BBs that may modify var
162 FOR_EACH_PTR(addr
->users
, pu
) {
163 struct instruction
*insn
= pu
->insn
;
164 struct basic_block
*bb
= insn
->bb
;
166 switch (insn
->opcode
) {
169 if (bb
->generation
!= generation
) {
170 bb
->generation
= generation
;
178 else if (samebb
!= bb
)
184 mod
|= MOD_ADDRESSABLE
;
185 goto external_visibility
;
187 warning(var
->pos
, "symbol '%s' pseudo used in unexpected way",
188 show_ident(var
->ident
));
190 } END_FOR_EACH_PTR(pu
);
192 // if all uses are local to a single block
193 // they can easily be rewritten and doesn't need phi-nodes
194 // FIXME: could be done for extended BB too
196 rewrite_local_var(samebb
, addr
, nbr_stores
, nbr_uses
);
200 idf_compute(ep
, &idf
, alpha
);
201 FOR_EACH_PTR(idf
, bb
) {
202 struct instruction
*node
= insert_phi_node(bb
, var
);
203 node
->phi_var
= var
->pseudo
;
204 } END_FOR_EACH_PTR(bb
);
208 if (mod
& (MOD_NONLOCAL
| MOD_STATIC
))
210 kill_dead_stores(ep
, addr
, !mod
);
213 static struct instruction
*lookup_var(struct basic_block
*bb
, struct symbol
*var
)
216 struct instruction
*insn
= phi_map_lookup(bb
->phi_map
, var
);
219 } while ((bb
= bb
->idom
));
223 static struct instruction_list
*phis_all
;
224 static struct instruction_list
*phis_used
;
225 static struct instruction_list
*stores
;
227 static bool matching_load(struct instruction
*def
, struct instruction
*insn
)
229 if (insn
->size
!= def
->size
)
231 switch (def
->opcode
) {
234 if (insn
->offset
!= def
->offset
)
244 static void ssa_rename_insn(struct basic_block
*bb
, struct instruction
*insn
)
246 struct instruction
*def
;
251 switch (insn
->opcode
) {
254 if (addr
->type
!= PSEUDO_SYM
)
257 if (!var
|| !var
->torename
)
259 phi_map_update(&bb
->phi_map
, var
, insn
);
260 add_instruction(&stores
, insn
);
264 if (addr
->type
!= PSEUDO_SYM
)
267 if (!var
|| !var
->torename
)
269 def
= lookup_var(bb
, var
);
271 val
= undef_pseudo();
272 } else if (!matching_load(def
, insn
)) {
273 var
->torename
= false;
278 replace_with_pseudo(insn
, val
);
282 if (!var
|| !var
->torename
)
284 phi_map_update(&bb
->phi_map
, var
, insn
);
285 add_instruction(&phis_all
, insn
);
290 static void ssa_rename_insns(struct entrypoint
*ep
)
292 struct basic_block
*bb
;
294 FOR_EACH_PTR(ep
->bbs
, bb
) {
295 struct instruction
*insn
;
296 FOR_EACH_PTR(bb
->insns
, insn
) {
299 ssa_rename_insn(bb
, insn
);
300 } END_FOR_EACH_PTR(insn
);
301 } END_FOR_EACH_PTR(bb
);
304 static void mark_phi_used(pseudo_t val
)
306 struct instruction
*node
;
308 if (val
->type
!= PSEUDO_REG
)
311 if (node
->opcode
!= OP_PHI
)
316 add_instruction(&phis_used
, node
);
319 static void ssa_rename_phi(struct instruction
*insn
)
321 struct basic_block
*par
;
326 var
= insn
->phi_var
->sym
;
329 FOR_EACH_PTR(insn
->bb
->parents
, par
) {
330 struct instruction
*def
= lookup_var(par
, var
);
331 pseudo_t val
= def
? def
->target
: undef_pseudo();
332 struct instruction
*phisrc
= alloc_phisrc(val
, var
);
333 pseudo_t phi
= phisrc
->target
;
334 phi
->ident
= var
->ident
;
335 insert_last_instruction(par
, phisrc
);
338 } END_FOR_EACH_PTR(par
);
341 static void ssa_rename_phis(struct entrypoint
*ep
)
343 struct instruction
*phi
;
346 FOR_EACH_PTR(phis_all
, phi
) {
347 if (has_users(phi
->target
)) {
349 add_instruction(&phis_used
, phi
);
351 } END_FOR_EACH_PTR(phi
);
353 FOR_EACH_PTR(phis_used
, phi
) {
357 } END_FOR_EACH_PTR(phi
);
360 static void remove_dead_stores(struct instruction_list
*stores
)
362 struct instruction
*store
;
364 FOR_EACH_PTR(stores
, store
) {
365 struct symbol
*var
= store
->addr
->sym
;
369 } END_FOR_EACH_PTR(store
);
372 void ssa_convert(struct entrypoint
*ep
)
374 struct basic_block
*bb
;
378 // calculate the number of BBs
379 first
= ep
->entry
->bb
->nr
;
381 FOR_EACH_PTR(ep
->bbs
, bb
) {
386 } END_FOR_EACH_PTR(bb
);
388 // try to promote memory accesses to pseudos
390 FOR_EACH_PTR(ep
->accesses
, pseudo
) {
391 ssa_convert_one_var(ep
, pseudo
->sym
);
392 } END_FOR_EACH_PTR(pseudo
);
394 // rename the converted accesses
395 phis_all
= phis_used
= NULL
;
396 ssa_rename_insns(ep
);
399 // remove now dead stores
400 remove_dead_stores(stores
);