2 * memops - try to combine memory ops.
4 * Copyright (C) 2004 Linus Torvalds
15 #include "expression.h"
16 #include "linearize.h"
21 * We should probably sort the phi list just to make it easier to compare
24 static void rewrite_load_instruction(struct instruction
*insn
, struct pseudo_list
*dominators
)
29 * Check for somewhat common case of duplicate
32 new = first_pseudo(dominators
)->def
->phi_src
;
33 FOR_EACH_PTR(dominators
, phi
) {
34 if (new != phi
->def
->phi_src
)
36 new->ident
= new->ident
? : phi
->ident
;
37 } END_FOR_EACH_PTR(phi
);
40 * All the same pseudo - mark the phi-nodes unused
41 * and convert the load into a LNOP and replace the
44 replace_with_pseudo(insn
, new);
45 FOR_EACH_PTR(dominators
, phi
) {
46 kill_instruction(phi
->def
);
47 } END_FOR_EACH_PTR(phi
);
51 /* We leave symbol pseudos with a bogus usage list here */
52 if (insn
->src
->type
!= PSEUDO_SYM
)
54 insn
->opcode
= OP_PHI
;
55 insn
->phi_list
= dominators
;
58 repeat_phase
|= REPEAT_CSE
;
61 static int find_dominating_parents(pseudo_t pseudo
, struct instruction
*insn
,
62 struct basic_block
*bb
, unsigned long generation
, struct pseudo_list
**dominators
,
65 struct basic_block
*parent
;
67 FOR_EACH_PTR(bb
->parents
, parent
) {
68 struct instruction
*one
;
69 struct instruction
*br
;
72 FOR_EACH_PTR_REVERSE(parent
->insns
, one
) {
78 dominance
= dominates(pseudo
, insn
, one
, local
);
80 if (one
->opcode
== OP_LOAD
)
87 } END_FOR_EACH_PTR_REVERSE(one
);
89 if (parent
->generation
== generation
)
91 parent
->generation
= generation
;
93 if (!find_dominating_parents(pseudo
, insn
, parent
, generation
, dominators
, local
))
98 br
= delete_last_instruction(&parent
->insns
);
99 phi
= alloc_phi(parent
, one
->target
, one
->type
);
100 phi
->ident
= phi
->ident
? : one
->target
->ident
;
101 add_instruction(&parent
->insns
, br
);
102 use_pseudo(insn
, phi
, add_pseudo(dominators
, phi
));
103 } END_FOR_EACH_PTR(parent
);
107 static int address_taken(pseudo_t pseudo
)
109 struct pseudo_user
*pu
;
110 FOR_EACH_PTR(pseudo
->users
, pu
) {
111 struct instruction
*insn
= pu
->insn
;
112 if (insn
->bb
&& (insn
->opcode
!= OP_LOAD
&& insn
->opcode
!= OP_STORE
))
114 if (pu
->userp
!= &insn
->src
)
116 } END_FOR_EACH_PTR(pu
);
120 static int local_pseudo(pseudo_t pseudo
)
122 return pseudo
->type
== PSEUDO_SYM
123 && !(pseudo
->sym
->ctype
.modifiers
& (MOD_STATIC
| MOD_NONLOCAL
))
124 && !address_taken(pseudo
);
127 static bool compatible_loads(struct instruction
*a
, struct instruction
*b
)
129 if (is_integral_type(a
->type
) && is_float_type(b
->type
))
131 if (is_float_type(a
->type
) && is_integral_type(b
->type
))
136 static void simplify_loads(struct basic_block
*bb
)
138 struct instruction
*insn
;
140 FOR_EACH_PTR_REVERSE(bb
->insns
, insn
) {
143 if (insn
->opcode
== OP_LOAD
) {
144 struct instruction
*dom
;
145 pseudo_t pseudo
= insn
->src
;
146 int local
= local_pseudo(pseudo
);
147 struct pseudo_list
*dominators
;
148 unsigned long generation
;
150 if (insn
->is_volatile
)
153 if (!has_users(insn
->target
)) {
154 kill_instruction(insn
);
158 RECURSE_PTR_REVERSE(insn
, dom
) {
162 dominance
= dominates(pseudo
, insn
, dom
, local
);
164 /* possible partial dominance? */
166 if (dom
->opcode
== OP_LOAD
)
170 if (!compatible_loads(insn
, dom
))
172 /* Yeehaa! Found one! */
173 replace_with_pseudo(insn
, dom
->target
);
176 } END_FOR_EACH_PTR_REVERSE(dom
);
178 /* OK, go find the parents */
179 generation
= ++bb_generation
;
180 bb
->generation
= generation
;
182 if (find_dominating_parents(pseudo
, insn
, bb
, generation
, &dominators
, local
)) {
183 /* This happens with initial assignments to structures etc.. */
186 assert(pseudo
->type
!= PSEUDO_ARG
);
187 replace_with_pseudo(insn
, value_pseudo(0));
191 rewrite_load_instruction(insn
, dominators
);
192 } else { // cleanup pending phi-sources
193 int repeat
= repeat_phase
;
195 FOR_EACH_PTR(dominators
, phi
) {
196 kill_instruction(phi
->def
);
197 } END_FOR_EACH_PTR(phi
);
198 repeat_phase
= repeat
;
202 /* Do the next one */;
203 } END_FOR_EACH_PTR_REVERSE(insn
);
206 static void kill_dominated_stores(struct basic_block
*bb
)
208 struct instruction
*insn
;
210 FOR_EACH_PTR_REVERSE(bb
->insns
, insn
) {
213 if (insn
->opcode
== OP_STORE
) {
214 struct instruction
*dom
;
215 pseudo_t pseudo
= insn
->src
;
220 if (insn
->is_volatile
)
223 local
= local_pseudo(pseudo
);
224 RECURSE_PTR_REVERSE(insn
, dom
) {
228 dominance
= dominates(pseudo
, insn
, dom
, local
);
230 /* possible partial dominance? */
233 if (dom
->opcode
== OP_LOAD
)
235 /* Yeehaa! Found one! */
236 kill_instruction_force(dom
);
238 } END_FOR_EACH_PTR_REVERSE(dom
);
240 /* OK, we should check the parents now */
243 /* Do the next one */;
244 } END_FOR_EACH_PTR_REVERSE(insn
);
247 void simplify_memops(struct entrypoint
*ep
)
249 struct basic_block
*bb
;
252 FOR_EACH_PTR_REVERSE(ep
->bbs
, bb
) {
254 } END_FOR_EACH_PTR_REVERSE(bb
);
256 FOR_EACH_PTR_REVERSE(ep
->bbs
, bb
) {
257 kill_dominated_stores(bb
);
258 } END_FOR_EACH_PTR_REVERSE(bb
);
260 FOR_EACH_PTR(ep
->accesses
, pseudo
) {
261 struct symbol
*var
= pseudo
->sym
;
265 mod
= var
->ctype
.modifiers
;
266 if (mod
& (MOD_VOLATILE
| MOD_NONLOCAL
| MOD_STATIC
))
268 kill_dead_stores(ep
, pseudo
, local_pseudo(pseudo
));
269 } END_FOR_EACH_PTR(pseudo
);