2 * memops - try to combine memory ops.
4 * Copyright (C) 2004 Linus Torvalds
15 #include "expression.h"
16 #include "linearize.h"
20 static void rewrite_load_instruction(struct instruction
*insn
, struct pseudo_list
*dominators
)
26 * Check for somewhat common case of duplicate
29 FOR_EACH_PTR(dominators
, phi
) {
31 new = phi
->def
->phi_src
;
32 else if (new != phi
->def
->phi_src
)
34 } END_FOR_EACH_PTR(phi
);
37 * All the same pseudo - mark the phi-nodes unused
38 * and convert the load into a LNOP and replace the
41 replace_with_pseudo(insn
, new);
42 FOR_EACH_PTR(dominators
, phi
) {
43 kill_instruction(phi
->def
);
44 } END_FOR_EACH_PTR(phi
);
49 insn
->opcode
= OP_PHI
;
50 insn
->phi_list
= dominators
;
53 repeat_phase
|= REPEAT_CSE
;
56 static int find_dominating_parents(struct instruction
*insn
,
57 struct basic_block
*bb
, struct pseudo_list
**dominators
,
60 struct basic_block
*parent
;
62 FOR_EACH_PTR(bb
->parents
, parent
) {
63 struct instruction
*phisrc
;
64 struct instruction
*one
;
67 FOR_EACH_PTR_REVERSE(parent
->insns
, one
) {
73 dominance
= dominates(insn
, one
, local
);
75 if (one
->opcode
== OP_LOAD
)
82 } END_FOR_EACH_PTR_REVERSE(one
);
84 if (parent
->generation
== bb
->generation
)
86 parent
->generation
= bb
->generation
;
88 if (!find_dominating_parents(insn
, parent
, dominators
, local
))
93 phisrc
= alloc_phisrc(one
->target
, one
->type
);
94 phisrc
->phi_node
= insn
;
95 insert_last_instruction(parent
, phisrc
);
97 phi
->ident
= phi
->ident
? : one
->target
->ident
;
98 use_pseudo(insn
, phi
, add_pseudo(dominators
, phi
));
99 } END_FOR_EACH_PTR(parent
);
103 static int address_taken(pseudo_t pseudo
)
105 struct pseudo_user
*pu
;
106 FOR_EACH_PTR(pseudo
->users
, pu
) {
107 struct instruction
*insn
= pu
->insn
;
108 if (insn
->bb
&& (insn
->opcode
!= OP_LOAD
&& insn
->opcode
!= OP_STORE
))
110 if (pu
->userp
!= &insn
->src
)
112 } END_FOR_EACH_PTR(pu
);
116 static int local_pseudo(pseudo_t pseudo
)
118 return pseudo
->type
== PSEUDO_SYM
119 && !(pseudo
->sym
->ctype
.modifiers
& (MOD_STATIC
| MOD_NONLOCAL
))
120 && !address_taken(pseudo
);
123 static bool compatible_loads(struct instruction
*a
, struct instruction
*b
)
125 if (is_integral_type(a
->type
) && is_float_type(b
->type
))
127 if (is_float_type(a
->type
) && is_integral_type(b
->type
))
132 static void simplify_loads(struct basic_block
*bb
)
134 struct instruction
*insn
;
136 FOR_EACH_PTR_REVERSE(bb
->insns
, insn
) {
139 if (insn
->opcode
== OP_LOAD
) {
140 struct instruction
*dom
;
141 pseudo_t pseudo
= insn
->src
;
142 int local
= local_pseudo(pseudo
);
143 struct pseudo_list
*dominators
;
145 if (insn
->is_volatile
)
148 if (!has_users(insn
->target
)) {
149 kill_instruction(insn
);
153 RECURSE_PTR_REVERSE(insn
, dom
) {
157 dominance
= dominates(insn
, dom
, local
);
159 /* possible partial dominance? */
161 if (dom
->opcode
== OP_LOAD
)
165 if (!compatible_loads(insn
, dom
))
167 /* Yeehaa! Found one! */
168 replace_with_pseudo(insn
, dom
->target
);
171 } END_FOR_EACH_PTR_REVERSE(dom
);
173 /* OK, go find the parents */
174 bb
->generation
= ++bb_generation
;
176 if (find_dominating_parents(insn
, bb
, &dominators
, local
)) {
177 /* This happens with initial assignments to structures etc.. */
180 assert(pseudo
->type
!= PSEUDO_ARG
);
181 replace_with_pseudo(insn
, value_pseudo(0));
185 rewrite_load_instruction(insn
, dominators
);
186 } else { // cleanup pending phi-sources
187 int repeat
= repeat_phase
;
189 FOR_EACH_PTR(dominators
, phi
) {
190 kill_instruction(phi
->def
);
191 } END_FOR_EACH_PTR(phi
);
192 repeat_phase
= repeat
;
196 /* Do the next one */;
197 } END_FOR_EACH_PTR_REVERSE(insn
);
200 static bool try_to_kill_store(struct instruction
*insn
,
201 struct instruction
*dom
, int local
)
203 int dominance
= dominates(insn
, dom
, local
);
206 /* possible partial dominance? */
209 if (insn
->target
== dom
->target
&& insn
->bb
== dom
->bb
) {
210 // found a memop which makes the store redundant
211 kill_instruction_force(insn
);
214 if (dom
->opcode
== OP_LOAD
)
216 if (dom
->is_volatile
)
218 /* Yeehaa! Found one! */
219 kill_instruction_force(dom
);
224 static void kill_dominated_stores(struct basic_block
*bb
)
226 struct instruction
*insn
;
228 FOR_EACH_PTR_REVERSE(bb
->insns
, insn
) {
231 if (insn
->opcode
== OP_STORE
) {
232 struct basic_block
*par
;
233 struct instruction
*dom
;
234 pseudo_t pseudo
= insn
->src
;
239 if (insn
->is_volatile
)
242 local
= local_pseudo(pseudo
);
243 RECURSE_PTR_REVERSE(insn
, dom
) {
246 if (!try_to_kill_store(insn
, dom
, local
))
248 } END_FOR_EACH_PTR_REVERSE(dom
);
250 /* OK, we should check the parents now */
251 FOR_EACH_PTR(bb
->parents
, par
) {
253 if (bb_list_size(par
->children
) != 1)
255 FOR_EACH_PTR(par
->insns
, dom
) {
260 if (!try_to_kill_store(insn
, dom
, local
))
262 } END_FOR_EACH_PTR(dom
);
265 } END_FOR_EACH_PTR(par
);
268 /* Do the next one */;
269 } END_FOR_EACH_PTR_REVERSE(insn
);
272 void simplify_memops(struct entrypoint
*ep
)
274 struct basic_block
*bb
;
277 FOR_EACH_PTR_REVERSE(ep
->bbs
, bb
) {
279 } END_FOR_EACH_PTR_REVERSE(bb
);
281 FOR_EACH_PTR_REVERSE(ep
->bbs
, bb
) {
282 kill_dominated_stores(bb
);
283 } END_FOR_EACH_PTR_REVERSE(bb
);
285 FOR_EACH_PTR(ep
->accesses
, pseudo
) {
286 struct symbol
*var
= pseudo
->sym
;
290 mod
= var
->ctype
.modifiers
;
291 if (mod
& (MOD_VOLATILE
| MOD_NONLOCAL
| MOD_STATIC
))
293 kill_dead_stores(ep
, pseudo
, local_pseudo(pseudo
));
294 } END_FOR_EACH_PTR(pseudo
);