Get comparison sizes right.
[smatch.git] / liveness.c
blobd21b3f179fb0f70fb9959fc292765ae2db218b0d
1 /*
2 * Register - track pseudo usage, maybe eventually try to do register
3 * allocation.
5 * Copyright (C) 2004 Linus Torvalds
6 */
8 #include <assert.h>
10 #include "parse.h"
11 #include "expression.h"
12 #include "linearize.h"
13 #include "flow.h"
15 static void phi_defines(struct instruction * phi_node, pseudo_t target,
16 void (*defines)(struct basic_block *, struct instruction *, pseudo_t))
18 pseudo_t phi;
19 FOR_EACH_PTR(phi_node->phi_list, phi) {
20 struct instruction *def;
21 if (phi == VOID)
22 continue;
23 def = phi->def;
24 if (!def || !def->bb)
25 continue;
26 if (def->opcode == OP_PHI) {
27 phi_defines(def, target, defines);
28 continue;
30 defines(def->bb, phi->def, target);
31 } END_FOR_EACH_PTR(phi);
34 static void asm_liveness(struct basic_block *bb, struct instruction *insn,
35 void (*def)(struct basic_block *, struct instruction *, pseudo_t),
36 void (*use)(struct basic_block *, struct instruction *, pseudo_t))
38 struct asm_constraint *entry;
40 FOR_EACH_PTR(insn->asm_rules->inputs, entry) {
41 use(bb, insn, entry->pseudo);
42 } END_FOR_EACH_PTR(entry);
44 FOR_EACH_PTR(insn->asm_rules->outputs, entry) {
45 def(bb, insn, entry->pseudo);
46 } END_FOR_EACH_PTR(entry);
49 static void track_instruction_usage(struct basic_block *bb, struct instruction *insn,
50 void (*def)(struct basic_block *, struct instruction *, pseudo_t),
51 void (*use)(struct basic_block *, struct instruction *, pseudo_t))
53 pseudo_t pseudo;
55 #define USES(x) use(bb, insn, insn->x)
56 #define DEFINES(x) def(bb, insn, insn->x)
58 switch (insn->opcode) {
59 case OP_RET:
60 USES(src);
61 break;
63 case OP_BR: case OP_SWITCH:
64 USES(cond);
65 break;
67 case OP_COMPUTEDGOTO:
68 USES(target);
69 break;
71 /* Binary */
72 case OP_BINARY ... OP_BINARY_END:
73 case OP_BINCMP ... OP_BINCMP_END:
74 USES(src1); USES(src2); DEFINES(target);
75 break;
77 /* Uni */
78 case OP_NOT: case OP_NEG:
79 USES(src1); DEFINES(target);
80 break;
82 case OP_SEL:
83 USES(src1); USES(src2); USES(src3); DEFINES(target);
84 break;
86 /* Memory */
87 case OP_LOAD:
88 USES(src); DEFINES(target);
89 break;
91 case OP_STORE:
92 USES(src); USES(target);
93 break;
95 case OP_SETVAL:
96 DEFINES(target);
97 break;
99 case OP_SYMADDR:
100 USES(symbol); DEFINES(target);
101 break;
103 /* Other */
104 case OP_PHI:
105 /* Phi-nodes are "backwards" nodes. Their def doesn't matter */
106 phi_defines(insn, insn->target, def);
107 break;
109 case OP_PHISOURCE:
111 * We don't care about the phi-source define, they get set
112 * up and expanded by the OP_PHI
114 USES(phi_src);
115 break;
117 case OP_CAST:
118 case OP_PTRCAST:
119 USES(src); DEFINES(target);
120 break;
122 case OP_CALL:
123 USES(func);
124 if (insn->target != VOID)
125 DEFINES(target);
126 FOR_EACH_PTR(insn->arguments, pseudo) {
127 use(bb, insn, pseudo);
128 } END_FOR_EACH_PTR(pseudo);
129 break;
131 case OP_SLICE:
132 USES(base); DEFINES(target);
133 break;
135 case OP_ASM:
136 asm_liveness(bb, insn, def, use);
137 break;
139 case OP_BADOP:
140 case OP_INVOKE:
141 case OP_UNWIND:
142 case OP_MALLOC:
143 case OP_FREE:
144 case OP_ALLOCA:
145 case OP_GET_ELEMENT_PTR:
146 case OP_VANEXT:
147 case OP_VAARG:
148 case OP_SNOP:
149 case OP_LNOP:
150 case OP_NOP:
151 case OP_CONTEXT:
152 break;
156 int pseudo_in_list(struct pseudo_list *list, pseudo_t pseudo)
158 pseudo_t old;
159 FOR_EACH_PTR(list,old) {
160 if (old == pseudo)
161 return 1;
162 } END_FOR_EACH_PTR(old);
163 return 0;
166 static int liveness_changed;
168 static void add_pseudo_exclusive(struct pseudo_list **list, pseudo_t pseudo)
170 if (!pseudo_in_list(*list, pseudo)) {
171 liveness_changed = 1;
172 add_pseudo(list, pseudo);
176 static inline int trackable_pseudo(pseudo_t pseudo)
178 return pseudo && (pseudo->type == PSEUDO_REG || pseudo->type == PSEUDO_ARG);
181 static void insn_uses(struct basic_block *bb, struct instruction *insn, pseudo_t pseudo)
183 if (trackable_pseudo(pseudo)) {
184 struct instruction *def = pseudo->def;
185 if (pseudo->type != PSEUDO_REG || def->bb != bb || def->opcode == OP_PHI)
186 add_pseudo_exclusive(&bb->needs, pseudo);
190 static void insn_defines(struct basic_block *bb, struct instruction *insn, pseudo_t pseudo)
192 assert(trackable_pseudo(pseudo));
193 add_pseudo(&bb->defines, pseudo);
196 static void track_bb_liveness(struct basic_block *bb)
198 pseudo_t needs;
200 FOR_EACH_PTR(bb->needs, needs) {
201 struct basic_block *parent;
202 FOR_EACH_PTR(bb->parents, parent) {
203 if (!pseudo_in_list(parent->defines, needs)) {
204 add_pseudo_exclusive(&parent->needs, needs);
206 } END_FOR_EACH_PTR(parent);
207 } END_FOR_EACH_PTR(needs);
211 * We need to clear the liveness information if we
212 * are going to re-run it.
214 void clear_liveness(struct entrypoint *ep)
216 struct basic_block *bb;
218 FOR_EACH_PTR(ep->bbs, bb) {
219 free_ptr_list(&bb->needs);
220 free_ptr_list(&bb->defines);
221 } END_FOR_EACH_PTR(bb);
225 * Track inter-bb pseudo liveness. The intra-bb case
226 * is purely local information.
228 void track_pseudo_liveness(struct entrypoint *ep)
230 struct basic_block *bb;
232 /* Add all the bb pseudo usage */
233 FOR_EACH_PTR(ep->bbs, bb) {
234 struct instruction *insn;
235 FOR_EACH_PTR(bb->insns, insn) {
236 if (!insn->bb)
237 continue;
238 assert(insn->bb == bb);
239 track_instruction_usage(bb, insn, insn_defines, insn_uses);
240 } END_FOR_EACH_PTR(insn);
241 } END_FOR_EACH_PTR(bb);
243 /* Calculate liveness.. */
244 do {
245 liveness_changed = 0;
246 FOR_EACH_PTR_REVERSE(ep->bbs, bb) {
247 track_bb_liveness(bb);
248 } END_FOR_EACH_PTR_REVERSE(bb);
249 } while (liveness_changed);
251 /* Remove the pseudos from the "defines" list that are used internally */
252 FOR_EACH_PTR(ep->bbs, bb) {
253 pseudo_t def;
254 FOR_EACH_PTR(bb->defines, def) {
255 struct basic_block *child;
256 FOR_EACH_PTR(bb->children, child) {
257 if (pseudo_in_list(child->needs, def))
258 goto is_used;
259 } END_FOR_EACH_PTR(child);
260 DELETE_CURRENT_PTR(def);
261 is_used:
263 } END_FOR_EACH_PTR(def);
264 PACK_PTR_LIST(&bb->defines);
265 } END_FOR_EACH_PTR(bb);
268 static void merge_pseudo_list(struct pseudo_list *src, struct pseudo_list **dest)
270 pseudo_t pseudo;
271 FOR_EACH_PTR(src, pseudo) {
272 add_pseudo_exclusive(dest, pseudo);
273 } END_FOR_EACH_PTR(pseudo);
276 static void track_phi_uses(struct instruction *insn)
278 pseudo_t phi;
279 FOR_EACH_PTR(insn->phi_list, phi) {
280 struct instruction *def;
281 if (phi == VOID || !phi->def)
282 continue;
283 def = phi->def;
284 assert(def->opcode == OP_PHISOURCE);
285 add_ptr_list(&def->phi_users, insn);
286 } END_FOR_EACH_PTR(phi);
289 static void track_bb_phi_uses(struct basic_block *bb)
291 struct instruction *insn;
292 FOR_EACH_PTR(bb->insns, insn) {
293 if (insn->bb && insn->opcode == OP_PHI)
294 track_phi_uses(insn);
295 } END_FOR_EACH_PTR(insn);
298 static struct pseudo_list **live_list;
299 static struct pseudo_list *dead_list;
301 static void death_def(struct basic_block *bb, struct instruction *insn, pseudo_t pseudo)
305 static void death_use(struct basic_block *bb, struct instruction *insn, pseudo_t pseudo)
307 if (trackable_pseudo(pseudo) && !pseudo_in_list(*live_list, pseudo)) {
308 add_pseudo(&dead_list, pseudo);
309 add_pseudo(live_list, pseudo);
313 static void track_pseudo_death_bb(struct basic_block *bb)
315 struct pseudo_list *live = NULL;
316 struct basic_block *child;
317 struct instruction *insn;
319 FOR_EACH_PTR(bb->children, child) {
320 merge_pseudo_list(child->needs, &live);
321 } END_FOR_EACH_PTR(child);
323 live_list = &live;
324 FOR_EACH_PTR_REVERSE(bb->insns, insn) {
325 if (!insn->bb)
326 continue;
329 * A "def" of a pseudo removes it from the liveness
330 * list. However, we only bother doing that for
331 * phi-nodes, since no other pseudos should ever
332 * be even used before they are def'ed.
334 if (insn->opcode == OP_PHISOURCE) {
335 struct instruction *phi;
336 FOR_EACH_PTR(insn->phi_users, phi) {
337 remove_pseudo(live_list, phi->target);
338 } END_FOR_EACH_PTR(phi);
341 dead_list = NULL;
342 track_instruction_usage(bb, insn, death_def, death_use);
343 if (dead_list) {
344 pseudo_t dead;
345 FOR_EACH_PTR(dead_list, dead) {
346 struct instruction *deathnote = __alloc_instruction(0);
347 deathnote->bb = bb;
348 deathnote->opcode = OP_DEATHNOTE;
349 deathnote->target = dead;
350 INSERT_CURRENT(deathnote, insn);
351 } END_FOR_EACH_PTR(dead);
352 free_ptr_list(&dead_list);
354 } END_FOR_EACH_PTR_REVERSE(insn);
355 free_ptr_list(&live);
358 void track_pseudo_death(struct entrypoint *ep)
360 struct basic_block *bb;
362 FOR_EACH_PTR(ep->bbs, bb) {
363 track_bb_phi_uses(bb);
364 } END_FOR_EACH_PTR(bb);
366 FOR_EACH_PTR(ep->bbs, bb) {
367 track_pseudo_death_bb(bb);
368 } END_FOR_EACH_PTR(bb);