db/return_states: fix call_id type
[smatch.git] / liveness.c
blob93a7cc3003897589c1fde3d42d984ee41a4cea24
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 "liveness.h"
11 #include "parse.h"
12 #include "expression.h"
13 #include "linearize.h"
14 #include "flow.h"
16 static void phi_defines(struct instruction * phi_node, pseudo_t target,
17 void (*defines)(struct basic_block *, pseudo_t))
19 pseudo_t phi;
20 FOR_EACH_PTR(phi_node->phi_list, phi) {
21 struct instruction *def;
22 if (phi == VOID)
23 continue;
24 def = phi->def;
25 if (!def || !def->bb)
26 continue;
27 defines(def->bb, target);
28 } END_FOR_EACH_PTR(phi);
31 static void asm_liveness(struct basic_block *bb, struct instruction *insn,
32 void (*def)(struct basic_block *, pseudo_t),
33 void (*use)(struct basic_block *, pseudo_t))
35 struct asm_constraint *entry;
37 FOR_EACH_PTR(insn->asm_rules->inputs, entry) {
38 use(bb, entry->pseudo);
39 } END_FOR_EACH_PTR(entry);
41 FOR_EACH_PTR(insn->asm_rules->outputs, entry) {
42 def(bb, entry->pseudo);
43 } END_FOR_EACH_PTR(entry);
46 static void track_instruction_usage(struct basic_block *bb, struct instruction *insn,
47 void (*def)(struct basic_block *, pseudo_t),
48 void (*use)(struct basic_block *, pseudo_t))
50 pseudo_t pseudo;
52 #define USES(x) use(bb, insn->x)
53 #define DEFINES(x) def(bb, insn->x)
55 switch (insn->opcode) {
56 case OP_RET:
57 case OP_COMPUTEDGOTO:
58 USES(src);
59 break;
61 case OP_CBR:
62 case OP_SWITCH:
63 USES(cond);
64 break;
66 /* Binary */
67 case OP_BINARY ... OP_BINARY_END:
68 case OP_FPCMP ... OP_FPCMP_END:
69 case OP_BINCMP ... OP_BINCMP_END:
70 USES(src1); USES(src2); DEFINES(target);
71 break;
73 /* Uni */
74 case OP_UNOP ... OP_UNOP_END:
75 case OP_SYMADDR:
76 USES(src1); DEFINES(target);
77 break;
79 case OP_SEL:
80 USES(src1); USES(src2); USES(src3); DEFINES(target);
81 break;
83 /* Memory */
84 case OP_LOAD:
85 USES(src); DEFINES(target);
86 break;
88 case OP_STORE:
89 USES(src); USES(target);
90 break;
92 case OP_SETVAL:
93 case OP_SETFVAL:
94 DEFINES(target);
95 break;
97 /* Other */
98 case OP_PHI:
99 /* Phi-nodes are "backwards" nodes. Their def doesn't matter */
100 phi_defines(insn, insn->target, def);
101 break;
103 case OP_PHISOURCE:
105 * We don't care about the phi-source define, they get set
106 * up and expanded by the OP_PHI
108 USES(phi_src);
109 break;
111 case OP_CALL:
112 USES(func);
113 if (insn->target != VOID)
114 DEFINES(target);
115 FOR_EACH_PTR(insn->arguments, pseudo) {
116 use(bb, pseudo);
117 } END_FOR_EACH_PTR(pseudo);
118 break;
120 case OP_SLICE:
121 USES(base); DEFINES(target);
122 break;
124 case OP_ASM:
125 asm_liveness(bb, insn, def, use);
126 break;
128 case OP_RANGE:
129 USES(src1); USES(src2); USES(src3);
130 break;
132 case OP_BADOP:
133 case OP_NOP:
134 case OP_CONTEXT:
135 break;
140 static int liveness_changed;
142 static void add_pseudo_exclusive(struct pseudo_list **list, pseudo_t pseudo)
144 if (!pseudo_in_list(*list, pseudo)) {
145 liveness_changed = 1;
146 add_pseudo(list, pseudo);
150 static inline int trackable_pseudo(pseudo_t pseudo)
152 return pseudo && (pseudo->type == PSEUDO_REG || pseudo->type == PSEUDO_ARG);
155 static void insn_uses(struct basic_block *bb, pseudo_t pseudo)
157 if (trackable_pseudo(pseudo)) {
158 struct instruction *def = pseudo->def;
159 if (pseudo->type != PSEUDO_REG || def->bb != bb || def->opcode == OP_PHI)
160 add_pseudo_exclusive(&bb->needs, pseudo);
164 static void insn_defines(struct basic_block *bb, pseudo_t pseudo)
166 assert(trackable_pseudo(pseudo));
167 add_pseudo(&bb->defines, pseudo);
170 static void track_bb_liveness(struct basic_block *bb)
172 pseudo_t needs;
174 FOR_EACH_PTR(bb->needs, needs) {
175 struct basic_block *parent;
176 FOR_EACH_PTR(bb->parents, parent) {
177 if (!pseudo_in_list(parent->defines, needs)) {
178 add_pseudo_exclusive(&parent->needs, needs);
180 } END_FOR_EACH_PTR(parent);
181 } END_FOR_EACH_PTR(needs);
185 * We need to clear the liveness information if we
186 * are going to re-run it.
188 void clear_liveness(struct entrypoint *ep)
190 struct basic_block *bb;
192 FOR_EACH_PTR(ep->bbs, bb) {
193 free_ptr_list(&bb->needs);
194 free_ptr_list(&bb->defines);
195 } END_FOR_EACH_PTR(bb);
199 * Track inter-bb pseudo liveness. The intra-bb case
200 * is purely local information.
202 void track_pseudo_liveness(struct entrypoint *ep)
204 struct basic_block *bb;
206 /* Add all the bb pseudo usage */
207 FOR_EACH_PTR(ep->bbs, bb) {
208 struct instruction *insn;
209 FOR_EACH_PTR(bb->insns, insn) {
210 if (!insn->bb)
211 continue;
212 assert(insn->bb == bb);
213 track_instruction_usage(bb, insn, insn_defines, insn_uses);
214 } END_FOR_EACH_PTR(insn);
215 } END_FOR_EACH_PTR(bb);
217 /* Calculate liveness.. */
218 do {
219 liveness_changed = 0;
220 FOR_EACH_PTR_REVERSE(ep->bbs, bb) {
221 track_bb_liveness(bb);
222 } END_FOR_EACH_PTR_REVERSE(bb);
223 } while (liveness_changed);
225 /* Remove the pseudos from the "defines" list that are used internally */
226 FOR_EACH_PTR(ep->bbs, bb) {
227 pseudo_t def;
228 FOR_EACH_PTR(bb->defines, def) {
229 struct basic_block *child;
230 FOR_EACH_PTR(bb->children, child) {
231 if (pseudo_in_list(child->needs, def))
232 goto is_used;
233 } END_FOR_EACH_PTR(child);
234 DELETE_CURRENT_PTR(def);
235 is_used:
237 } END_FOR_EACH_PTR(def);
238 PACK_PTR_LIST(&bb->defines);
239 } END_FOR_EACH_PTR(bb);
242 static void merge_pseudo_list(struct pseudo_list *src, struct pseudo_list **dest)
244 pseudo_t pseudo;
245 FOR_EACH_PTR(src, pseudo) {
246 add_pseudo_exclusive(dest, pseudo);
247 } END_FOR_EACH_PTR(pseudo);
250 static void track_phi_uses(struct instruction *insn)
252 pseudo_t phi;
253 FOR_EACH_PTR(insn->phi_list, phi) {
254 struct instruction *def;
255 if (phi == VOID || !phi->def)
256 continue;
257 def = phi->def;
258 assert(def->opcode == OP_PHISOURCE);
259 add_ptr_list(&def->phi_users, insn);
260 } END_FOR_EACH_PTR(phi);
263 static void track_bb_phi_uses(struct basic_block *bb)
265 struct instruction *insn;
266 FOR_EACH_PTR(bb->insns, insn) {
267 if (insn->bb && insn->opcode == OP_PHI)
268 track_phi_uses(insn);
269 } END_FOR_EACH_PTR(insn);
272 static struct pseudo_list **live_list;
273 static struct pseudo_list *dead_list;
275 static void death_def(struct basic_block *bb, pseudo_t pseudo)
279 static void death_use(struct basic_block *bb, pseudo_t pseudo)
281 if (trackable_pseudo(pseudo) && !pseudo_in_list(*live_list, pseudo)) {
282 add_pseudo(&dead_list, pseudo);
283 add_pseudo(live_list, pseudo);
287 static void track_pseudo_death_bb(struct basic_block *bb)
289 struct pseudo_list *live = NULL;
290 struct basic_block *child;
291 struct instruction *insn;
293 FOR_EACH_PTR(bb->children, child) {
294 merge_pseudo_list(child->needs, &live);
295 } END_FOR_EACH_PTR(child);
297 live_list = &live;
298 FOR_EACH_PTR_REVERSE(bb->insns, insn) {
299 if (!insn->bb)
300 continue;
302 dead_list = NULL;
303 track_instruction_usage(bb, insn, death_def, death_use);
304 if (dead_list) {
305 pseudo_t dead;
306 FOR_EACH_PTR(dead_list, dead) {
307 struct instruction *deathnote = __alloc_instruction(0);
308 deathnote->bb = bb;
309 deathnote->opcode = OP_DEATHNOTE;
310 deathnote->target = dead;
311 INSERT_CURRENT(deathnote, insn);
312 } END_FOR_EACH_PTR(dead);
313 free_ptr_list(&dead_list);
315 } END_FOR_EACH_PTR_REVERSE(insn);
316 free_ptr_list(&live);
319 void track_pseudo_death(struct entrypoint *ep)
321 struct basic_block *bb;
323 FOR_EACH_PTR(ep->bbs, bb) {
324 track_bb_phi_uses(bb);
325 } END_FOR_EACH_PTR(bb);
327 FOR_EACH_PTR(ep->bbs, bb) {
328 track_pseudo_death_bb(bb);
329 } END_FOR_EACH_PTR(bb);