2 * memops - try to combine memory ops.
4 * Copyright (C) 2004 Linus Torvalds
15 #include "expression.h"
16 #include "linearize.h"
19 static int find_dominating_parents(pseudo_t pseudo
, struct instruction
*insn
,
20 struct basic_block
*bb
, unsigned long generation
, struct pseudo_list
**dominators
,
23 struct basic_block
*parent
;
25 FOR_EACH_PTR(bb
->parents
, parent
) {
26 struct instruction
*one
;
27 struct instruction
*br
;
30 FOR_EACH_PTR_REVERSE(parent
->insns
, one
) {
36 dominance
= dominates(pseudo
, insn
, one
, local
);
38 if (one
->opcode
== OP_LOAD
)
45 } END_FOR_EACH_PTR_REVERSE(one
);
47 if (parent
->generation
== generation
)
49 parent
->generation
= generation
;
51 if (!find_dominating_parents(pseudo
, insn
, parent
, generation
, dominators
, local
))
56 br
= delete_last_instruction(&parent
->insns
);
57 phi
= alloc_phi(parent
, one
->target
, one
->type
);
58 phi
->ident
= phi
->ident
? : one
->target
->ident
;
59 add_instruction(&parent
->insns
, br
);
60 use_pseudo(insn
, phi
, add_pseudo(dominators
, phi
));
61 } END_FOR_EACH_PTR(parent
);
65 static int address_taken(pseudo_t pseudo
)
67 struct pseudo_user
*pu
;
68 FOR_EACH_PTR(pseudo
->users
, pu
) {
69 struct instruction
*insn
= pu
->insn
;
70 if (insn
->bb
&& (insn
->opcode
!= OP_LOAD
&& insn
->opcode
!= OP_STORE
))
72 if (pu
->userp
!= &insn
->src
)
74 } END_FOR_EACH_PTR(pu
);
78 static int local_pseudo(pseudo_t pseudo
)
80 return pseudo
->type
== PSEUDO_SYM
81 && !(pseudo
->sym
->ctype
.modifiers
& (MOD_STATIC
| MOD_NONLOCAL
))
82 && !address_taken(pseudo
);
85 static bool compatible_loads(struct instruction
*a
, struct instruction
*b
)
87 if (is_integral_type(a
->type
) && is_float_type(b
->type
))
89 if (is_float_type(a
->type
) && is_integral_type(b
->type
))
94 static void simplify_loads(struct basic_block
*bb
)
96 struct instruction
*insn
;
98 FOR_EACH_PTR_REVERSE(bb
->insns
, insn
) {
101 if (insn
->opcode
== OP_LOAD
) {
102 struct instruction
*dom
;
103 pseudo_t pseudo
= insn
->src
;
104 int local
= local_pseudo(pseudo
);
105 struct pseudo_list
*dominators
;
106 unsigned long generation
;
108 /* Check for illegal offsets.. */
111 if (insn
->is_volatile
)
114 RECURSE_PTR_REVERSE(insn
, dom
) {
118 dominance
= dominates(pseudo
, insn
, dom
, local
);
120 /* possible partial dominance? */
122 if (dom
->opcode
== OP_LOAD
)
126 if (!compatible_loads(insn
, dom
))
128 /* Yeehaa! Found one! */
129 convert_load_instruction(insn
, dom
->target
);
132 } END_FOR_EACH_PTR_REVERSE(dom
);
134 /* OK, go find the parents */
135 generation
= ++bb_generation
;
136 bb
->generation
= generation
;
138 if (find_dominating_parents(pseudo
, insn
, bb
, generation
, &dominators
, local
)) {
139 /* This happens with initial assignments to structures etc.. */
142 assert(pseudo
->type
!= PSEUDO_ARG
);
143 convert_load_instruction(insn
, value_pseudo(0));
147 rewrite_load_instruction(insn
, dominators
);
148 } else { // cleanup pending phi-sources
150 FOR_EACH_PTR(dominators
, phi
) {
151 kill_instruction(phi
->def
);
152 } END_FOR_EACH_PTR(phi
);
156 /* Do the next one */;
157 } END_FOR_EACH_PTR_REVERSE(insn
);
160 static void kill_dominated_stores(struct basic_block
*bb
)
162 struct instruction
*insn
;
164 FOR_EACH_PTR_REVERSE(bb
->insns
, insn
) {
167 if (insn
->opcode
== OP_STORE
) {
168 struct instruction
*dom
;
169 pseudo_t pseudo
= insn
->src
;
174 if (insn
->is_volatile
)
177 local
= local_pseudo(pseudo
);
178 RECURSE_PTR_REVERSE(insn
, dom
) {
182 dominance
= dominates(pseudo
, insn
, dom
, local
);
184 /* possible partial dominance? */
187 if (dom
->opcode
== OP_LOAD
)
189 /* Yeehaa! Found one! */
190 kill_instruction_force(dom
);
192 } END_FOR_EACH_PTR_REVERSE(dom
);
194 /* OK, we should check the parents now */
197 /* Do the next one */;
198 } END_FOR_EACH_PTR_REVERSE(insn
);
201 void simplify_memops(struct entrypoint
*ep
)
203 struct basic_block
*bb
;
206 FOR_EACH_PTR_REVERSE(ep
->bbs
, bb
) {
208 } END_FOR_EACH_PTR_REVERSE(bb
);
210 FOR_EACH_PTR_REVERSE(ep
->bbs
, bb
) {
211 kill_dominated_stores(bb
);
212 } END_FOR_EACH_PTR_REVERSE(bb
);
214 FOR_EACH_PTR(ep
->accesses
, pseudo
) {
215 struct symbol
*var
= pseudo
->sym
;
219 mod
= var
->ctype
.modifiers
;
220 if (mod
& (MOD_VOLATILE
| MOD_NONLOCAL
| MOD_STATIC
))
222 kill_dead_stores(ep
, pseudo
, local_pseudo(pseudo
));
223 } END_FOR_EACH_PTR(pseudo
);