Print this page
11972 resync smatch
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/flow.c
+++ new/usr/src/tools/smatch/src/flow.c
1 1 /*
2 2 * Flow - walk the linearized flowgraph, simplifying it as we
3 3 * go along.
4 4 *
5 5 * Copyright (C) 2004 Linus Torvalds
6 6 */
7 7
8 8 #include <string.h>
9 9 #include <stdarg.h>
10 10 #include <stdlib.h>
11 11 #include <stdio.h>
12 12 #include <stddef.h>
13 13 #include <assert.h>
14 14
15 15 #include "parse.h"
16 16 #include "expression.h"
17 17 #include "linearize.h"
18 18 #include "flow.h"
19 19 #include "target.h"
20 20
21 21 unsigned long bb_generation;
22 22
23 23 /*
24 24 * Dammit, if we have a phi-node followed by a conditional
25 25 * branch on that phi-node, we should damn well be able to
26 26 * do something about the source. Maybe.
27 27 */
28 28 static int rewrite_branch(struct basic_block *bb,
29 29 struct basic_block **ptr,
30 30 struct basic_block *old,
31 31 struct basic_block *new)
32 32 {
33 33 if (*ptr != old || new == old || !bb->ep)
34 34 return 0;
35 35
36 36 /* We might find new if-conversions or non-dominating CSEs */
37 37 /* we may also create new dead cycles */
38 38 repeat_phase |= REPEAT_CSE | REPEAT_CFG_CLEANUP;
39 39 *ptr = new;
40 40 replace_bb_in_list(&bb->children, old, new, 1);
41 41 remove_bb_from_list(&old->parents, bb, 1);
42 42 add_bb(&new->parents, bb);
43 43 return 1;
44 44 }
45 45
46 46 /*
47 47 * Return the known truth value of a pseudo, or -1 if
48 48 * it's not known.
49 49 */
50 50 static int pseudo_truth_value(pseudo_t pseudo)
51 51 {
52 52 switch (pseudo->type) {
53 53 case PSEUDO_VAL:
54 54 return !!pseudo->value;
55 55
56 56 case PSEUDO_REG: {
57 57 struct instruction *insn = pseudo->def;
58 58
59 59 /* A symbol address is always considered true.. */
60 60 if (insn->opcode == OP_SYMADDR && insn->target == pseudo)
61 61 return 1;
62 62 }
63 63 /* Fall through */
64 64 default:
65 65 return -1;
66 66 }
67 67 }
68 68
69 69 /*
70 70 * Does a basic block depend on the pseudos that "src" defines?
71 71 */
72 72 static int bb_depends_on(struct basic_block *target, struct basic_block *src)
73 73 {
74 74 pseudo_t pseudo;
75 75
76 76 FOR_EACH_PTR(src->defines, pseudo) {
77 77 if (pseudo_in_list(target->needs, pseudo))
78 78 return 1;
79 79 } END_FOR_EACH_PTR(pseudo);
80 80 return 0;
81 81 }
82 82
83 83 /*
84 84 * This really should be handled by bb_depends_on()
85 85 * which efficiently check the dependence using the
86 86 * defines - needs liveness info. Problem is that
87 87 * there is no liveness done on OP_PHI & OP_PHISRC.
88 88 *
89 89 * This function add the missing dependency checks.
90 90 */
91 91 static int bb_depends_on_phi(struct basic_block *target, struct basic_block *src)
92 92 {
93 93 struct instruction *insn;
94 94 FOR_EACH_PTR(src->insns, insn) {
95 95 if (!insn->bb)
96 96 continue;
97 97 if (insn->opcode != OP_PHI)
98 98 continue;
99 99 if (pseudo_in_list(target->needs, insn->target))
100 100 return 1;
101 101 } END_FOR_EACH_PTR(insn);
102 102 return 0;
103 103 }
104 104
105 105 /*
106 106 * When we reach here, we have:
107 107 * - a basic block that ends in a conditional branch and
108 108 * that has no side effects apart from the pseudos it
109 109 * may change.
110 110 * - the phi-node that the conditional branch depends on
111 111 * - full pseudo liveness information
112 112 *
113 113 * We need to check if any of the _sources_ of the phi-node
114 114 * may be constant, and not actually need this block at all.
115 115 */
116 116 static int try_to_simplify_bb(struct basic_block *bb, struct instruction *first, struct instruction *second)
117 117 {
118 118 int changed = 0;
119 119 pseudo_t phi;
120 120 int bogus;
121 121
122 122 /*
123 123 * This a due to improper dominance tracking during
↓ open down ↓ |
123 lines elided |
↑ open up ↑ |
124 124 * simplify_symbol_usage()/conversion to SSA form.
125 125 * No sane simplification can be done when we have this.
126 126 */
127 127 bogus = bb_list_size(bb->parents) != pseudo_list_size(first->phi_list);
128 128
129 129 FOR_EACH_PTR(first->phi_list, phi) {
130 130 struct instruction *def = phi->def;
131 131 struct basic_block *source, *target;
132 132 pseudo_t pseudo;
133 133 struct instruction *br;
134 - int true;
134 + int cond;
135 135
136 136 if (!def)
137 137 continue;
138 138 source = def->bb;
139 139 pseudo = def->src1;
140 140 if (!pseudo || !source)
141 141 continue;
142 142 br = last_instruction(source->insns);
143 143 if (!br)
144 144 continue;
145 145 if (br->opcode != OP_CBR && br->opcode != OP_BR)
146 146 continue;
147 - true = pseudo_truth_value(pseudo);
148 - if (true < 0)
147 + cond = pseudo_truth_value(pseudo);
148 + if (cond < 0)
149 149 continue;
150 - target = true ? second->bb_true : second->bb_false;
150 + target = cond ? second->bb_true : second->bb_false;
151 151 if (bb_depends_on(target, bb))
152 152 continue;
153 153 if (bb_depends_on_phi(target, bb))
154 154 continue;
155 155 changed |= rewrite_branch(source, &br->bb_true, bb, target);
156 156 changed |= rewrite_branch(source, &br->bb_false, bb, target);
157 157 if (changed && !bogus)
158 158 kill_use(THIS_ADDRESS(phi));
159 159 } END_FOR_EACH_PTR(phi);
160 160 return changed;
161 161 }
162 162
163 163 static int bb_has_side_effects(struct basic_block *bb)
164 164 {
165 165 struct instruction *insn;
166 166 FOR_EACH_PTR(bb->insns, insn) {
167 + if (!insn->bb)
168 + continue;
167 169 switch (insn->opcode) {
168 170 case OP_CALL:
169 171 /* FIXME! This should take "const" etc into account */
170 172 return 1;
171 173
174 + case OP_LOAD:
175 + if (!insn->type)
176 + return 1;
177 + if (insn->is_volatile)
178 + return 1;
179 + continue;
180 +
172 181 case OP_STORE:
173 182 case OP_CONTEXT:
174 183 return 1;
175 184
176 185 case OP_ASM:
177 186 /* FIXME! This should take "volatile" etc into account */
178 187 return 1;
179 188
180 189 default:
181 190 continue;
182 191 }
183 192 } END_FOR_EACH_PTR(insn);
184 193 return 0;
185 194 }
186 195
187 196 static int simplify_phi_branch(struct basic_block *bb, struct instruction *br)
188 197 {
189 198 pseudo_t cond = br->cond;
190 199 struct instruction *def;
191 200
192 201 if (cond->type != PSEUDO_REG)
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
193 202 return 0;
194 203 def = cond->def;
195 204 if (def->bb != bb || def->opcode != OP_PHI)
196 205 return 0;
197 206 if (bb_has_side_effects(bb))
198 207 return 0;
199 208 return try_to_simplify_bb(bb, def, br);
200 209 }
201 210
202 211 static int simplify_branch_branch(struct basic_block *bb, struct instruction *br,
203 - struct basic_block **target_p, int true)
212 + struct basic_block **target_p, int bb_true)
204 213 {
205 214 struct basic_block *target = *target_p, *final;
206 215 struct instruction *insn;
207 216 int retval;
208 217
209 218 if (target == bb)
210 219 return 0;
211 220 insn = last_instruction(target->insns);
212 221 if (!insn || insn->opcode != OP_CBR || insn->cond != br->cond)
213 222 return 0;
214 223 /*
215 224 * Ahhah! We've found a branch to a branch on the same conditional!
216 225 * Now we just need to see if we can rewrite the branch..
217 226 */
218 227 retval = 0;
219 - final = true ? insn->bb_true : insn->bb_false;
228 + final = bb_true ? insn->bb_true : insn->bb_false;
220 229 if (bb_has_side_effects(target))
221 230 goto try_to_rewrite_target;
222 231 if (bb_depends_on(final, target))
223 232 goto try_to_rewrite_target;
224 233 if (bb_depends_on_phi(final, target))
225 234 return 0;
226 235 return rewrite_branch(bb, target_p, target, final);
227 236
228 237 try_to_rewrite_target:
229 238 /*
230 239 * If we're the only parent, at least we can rewrite the
231 240 * now-known second branch.
232 241 */
233 242 if (bb_list_size(target->parents) != 1)
234 243 return retval;
235 244 insert_branch(target, insn, final);
236 245 return 1;
237 246 }
238 247
239 248 static int simplify_one_branch(struct basic_block *bb, struct instruction *br)
240 249 {
241 250 if (simplify_phi_branch(bb, br))
242 251 return 1;
243 252 return simplify_branch_branch(bb, br, &br->bb_true, 1) |
244 253 simplify_branch_branch(bb, br, &br->bb_false, 0);
245 254 }
246 255
247 256 static int simplify_branch_nodes(struct entrypoint *ep)
248 257 {
249 258 int changed = 0;
250 259 struct basic_block *bb;
251 260
252 261 FOR_EACH_PTR(ep->bbs, bb) {
253 262 struct instruction *br = last_instruction(bb->insns);
254 263
255 264 if (!br || br->opcode != OP_CBR)
256 265 continue;
257 266 changed |= simplify_one_branch(bb, br);
258 267 } END_FOR_EACH_PTR(bb);
259 268 return changed;
260 269 }
261 270
↓ open down ↓ |
32 lines elided |
↑ open up ↑ |
262 271 /*
263 272 * This is called late - when we have intra-bb liveness information..
264 273 */
265 274 int simplify_flow(struct entrypoint *ep)
266 275 {
267 276 return simplify_branch_nodes(ep);
268 277 }
269 278
270 279 static inline void concat_user_list(struct pseudo_user_list *src, struct pseudo_user_list **dst)
271 280 {
272 - concat_ptr_list((struct ptr_list *)src, (struct ptr_list **)dst);
281 + copy_ptr_list((struct ptr_list **)dst, (struct ptr_list *)src);
273 282 }
274 283
275 284 void convert_instruction_target(struct instruction *insn, pseudo_t src)
276 285 {
277 286 pseudo_t target;
278 287 struct pseudo_user *pu;
279 288 /*
280 289 * Go through the "insn->users" list and replace them all..
281 290 */
282 291 target = insn->target;
283 292 if (target == src)
284 293 return;
285 294 FOR_EACH_PTR(target->users, pu) {
286 295 if (*pu->userp != VOID) {
287 296 assert(*pu->userp == target);
288 297 *pu->userp = src;
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
289 298 }
290 299 } END_FOR_EACH_PTR(pu);
291 300 if (has_use_list(src))
292 301 concat_user_list(target->users, &src->users);
293 302 target->users = NULL;
294 303 }
295 304
296 305 void convert_load_instruction(struct instruction *insn, pseudo_t src)
297 306 {
298 307 convert_instruction_target(insn, src);
299 - /* Turn the load into a no-op */
300 - insn->opcode = OP_LNOP;
301 - insn->bb = NULL;
308 + kill_instruction(insn);
309 + repeat_phase |= REPEAT_SYMBOL_CLEANUP;
302 310 }
303 311
304 312 static int overlapping_memop(struct instruction *a, struct instruction *b)
305 313 {
306 314 unsigned int a_start = bytes_to_bits(a->offset);
307 315 unsigned int b_start = bytes_to_bits(b->offset);
308 316 unsigned int a_size = a->size;
309 317 unsigned int b_size = b->size;
310 318
311 319 if (a_size + a_start <= b_start)
312 320 return 0;
313 321 if (b_size + b_start <= a_start)
314 322 return 0;
315 323 return 1;
316 324 }
317 325
318 326 static inline int same_memop(struct instruction *a, struct instruction *b)
319 327 {
320 328 return a->offset == b->offset && a->size == b->size;
321 329 }
322 330
323 331 static inline int distinct_symbols(pseudo_t a, pseudo_t b)
324 332 {
325 333 if (a->type != PSEUDO_SYM)
326 334 return 0;
327 335 if (b->type != PSEUDO_SYM)
328 336 return 0;
329 337 return a->sym != b->sym;
330 338 }
331 339
332 340 /*
333 341 * Return 1 if "dom" dominates the access to "pseudo"
334 342 * in "insn".
335 343 *
336 344 * Return 0 if it doesn't, and -1 if you don't know.
337 345 */
338 346 int dominates(pseudo_t pseudo, struct instruction *insn, struct instruction *dom, int local)
339 347 {
340 348 int opcode = dom->opcode;
341 349
342 350 if (opcode == OP_CALL || opcode == OP_ENTRY)
343 351 return local ? 0 : -1;
344 352 if (opcode != OP_LOAD && opcode != OP_STORE)
345 353 return 0;
346 354 if (dom->src != pseudo) {
347 355 if (local)
348 356 return 0;
349 357 /* We don't think two explicitly different symbols ever alias */
350 358 if (distinct_symbols(insn->src, dom->src))
351 359 return 0;
352 360 /* We could try to do some alias analysis here */
353 361 return -1;
354 362 }
↓ open down ↓ |
43 lines elided |
↑ open up ↑ |
355 363 if (!same_memop(insn, dom)) {
356 364 if (dom->opcode == OP_LOAD)
357 365 return 0;
358 366 if (!overlapping_memop(insn, dom))
359 367 return 0;
360 368 return -1;
361 369 }
362 370 return 1;
363 371 }
364 372
365 -static int phisrc_in_bb(struct pseudo_list *list, struct basic_block *bb)
366 -{
367 - pseudo_t p;
368 - FOR_EACH_PTR(list, p) {
369 - if (p->def->bb == bb)
370 - return 1;
371 - } END_FOR_EACH_PTR(p);
372 -
373 - return 0;
374 -}
375 -
376 -static int find_dominating_parents(pseudo_t pseudo, struct instruction *insn,
377 - struct basic_block *bb, unsigned long generation, struct pseudo_list **dominators,
378 - int local)
379 -{
380 - struct basic_block *parent;
381 -
382 - if (!bb->parents)
383 - return !!local;
384 -
385 - FOR_EACH_PTR(bb->parents, parent) {
386 - struct instruction *one;
387 - struct instruction *br;
388 - pseudo_t phi;
389 -
390 - FOR_EACH_PTR_REVERSE(parent->insns, one) {
391 - int dominance;
392 - if (one == insn)
393 - goto no_dominance;
394 - dominance = dominates(pseudo, insn, one, local);
395 - if (dominance < 0) {
396 - if (one->opcode == OP_LOAD)
397 - continue;
398 - return 0;
399 - }
400 - if (!dominance)
401 - continue;
402 - goto found_dominator;
403 - } END_FOR_EACH_PTR_REVERSE(one);
404 -no_dominance:
405 - if (parent->generation == generation)
406 - continue;
407 - parent->generation = generation;
408 -
409 - if (!find_dominating_parents(pseudo, insn, parent, generation, dominators, local))
410 - return 0;
411 - continue;
412 -
413 -found_dominator:
414 - if (dominators && phisrc_in_bb(*dominators, parent))
415 - continue;
416 - br = delete_last_instruction(&parent->insns);
417 - phi = alloc_phi(parent, one->target, one->size);
418 - phi->ident = phi->ident ? : pseudo->ident;
419 - add_instruction(&parent->insns, br);
420 - use_pseudo(insn, phi, add_pseudo(dominators, phi));
421 - } END_FOR_EACH_PTR(parent);
422 - return 1;
423 -}
424 -
425 373 /*
426 374 * We should probably sort the phi list just to make it easier to compare
427 375 * later for equality.
428 376 */
429 377 void rewrite_load_instruction(struct instruction *insn, struct pseudo_list *dominators)
430 378 {
431 379 pseudo_t new, phi;
432 380
433 381 /*
434 382 * Check for somewhat common case of duplicate
435 383 * phi nodes.
436 384 */
437 - new = first_pseudo(dominators)->def->src1;
385 + new = first_pseudo(dominators)->def->phi_src;
438 386 FOR_EACH_PTR(dominators, phi) {
439 - if (new != phi->def->src1)
387 + if (new != phi->def->phi_src)
440 388 goto complex_phi;
441 389 new->ident = new->ident ? : phi->ident;
442 390 } END_FOR_EACH_PTR(phi);
443 391
444 392 /*
445 393 * All the same pseudo - mark the phi-nodes unused
446 394 * and convert the load into a LNOP and replace the
447 395 * pseudo.
448 396 */
397 + convert_load_instruction(insn, new);
449 398 FOR_EACH_PTR(dominators, phi) {
450 399 kill_instruction(phi->def);
451 400 } END_FOR_EACH_PTR(phi);
452 - convert_load_instruction(insn, new);
453 - return;
401 + goto end;
454 402
455 403 complex_phi:
456 404 /* We leave symbol pseudos with a bogus usage list here */
457 405 if (insn->src->type != PSEUDO_SYM)
458 406 kill_use(&insn->src);
459 407 insn->opcode = OP_PHI;
460 408 insn->phi_list = dominators;
461 -}
462 409
463 -static int find_dominating_stores(pseudo_t pseudo, struct instruction *insn,
464 - unsigned long generation, int local)
465 -{
466 - struct basic_block *bb = insn->bb;
467 - struct instruction *one, *dom = NULL;
468 - struct pseudo_list *dominators;
469 - int partial;
470 -
471 - /* Unreachable load? Undo it */
472 - if (!bb) {
473 - insn->opcode = OP_LNOP;
474 - return 1;
475 - }
476 -
477 - partial = 0;
478 - FOR_EACH_PTR(bb->insns, one) {
479 - int dominance;
480 - if (one == insn)
481 - goto found;
482 - dominance = dominates(pseudo, insn, one, local);
483 - if (dominance < 0) {
484 - /* Ignore partial load dominators */
485 - if (one->opcode == OP_LOAD)
486 - continue;
487 - dom = NULL;
488 - partial = 1;
489 - continue;
490 - }
491 - if (!dominance)
492 - continue;
493 - dom = one;
494 - partial = 0;
495 - } END_FOR_EACH_PTR(one);
496 - /* Whaa? */
497 - warning(pseudo->sym->pos, "unable to find symbol read");
498 - return 0;
499 -found:
500 - if (partial)
501 - return 0;
502 -
503 - if (dom) {
504 - convert_load_instruction(insn, dom->target);
505 - return 1;
506 - }
507 -
508 - /* OK, go find the parents */
509 - bb->generation = generation;
510 -
511 - dominators = NULL;
512 - if (!find_dominating_parents(pseudo, insn, bb, generation, &dominators, local))
513 - return 0;
514 -
515 - /* This happens with initial assignments to structures etc.. */
516 - if (!dominators) {
517 - if (!local)
518 - return 0;
519 - check_access(insn);
520 - convert_load_instruction(insn, value_pseudo(insn->type, 0));
521 - return 1;
522 - }
523 -
524 - /*
525 - * If we find just one dominating instruction, we
526 - * can turn it into a direct thing. Otherwise we'll
527 - * have to turn the load into a phi-node of the
528 - * dominators.
529 - */
530 - rewrite_load_instruction(insn, dominators);
531 - return 1;
410 +end:
411 + repeat_phase |= REPEAT_SYMBOL_CLEANUP;
532 412 }
533 413
534 -static void kill_store(struct instruction *insn)
535 -{
536 - if (insn) {
537 - insn->bb = NULL;
538 - insn->opcode = OP_SNOP;
539 - kill_use(&insn->target);
540 - }
541 -}
542 -
543 414 /* Kill a pseudo that is dead on exit from the bb */
544 -static void kill_dead_stores(pseudo_t pseudo, unsigned long generation, struct basic_block *bb, int local)
415 +// The context is:
416 +// * the variable is not global but may have its address used (local/non-local)
417 +// * the stores are only needed by others functions which would do some
418 +// loads via the escaped address
419 +// We start by the terminating BB (normal exit BB + no-return/unreachable)
420 +// We walkup the BB' intruction backward
421 +// * we're only concerned by loads, stores & calls
422 +// * if we reach a call -> we have to stop if var is non-local
423 +// * if we reach a load of our var -> we have to stop
424 +// * if we reach a store of our var -> we can kill it, it's dead
425 +// * we can ignore other stores & loads if the var is local
426 +// * if we reach another store or load done via non-symbol access
427 +// (so done via some address calculation) -> we have to stop
428 +// If we reach the top of the BB we can recurse into the parents BBs.
429 +static void kill_dead_stores_bb(pseudo_t pseudo, unsigned long generation, struct basic_block *bb, int local)
545 430 {
546 431 struct instruction *insn;
547 432 struct basic_block *parent;
548 433
549 434 if (bb->generation == generation)
550 435 return;
551 436 bb->generation = generation;
552 437 FOR_EACH_PTR_REVERSE(bb->insns, insn) {
553 - int opcode = insn->opcode;
554 -
555 - if (opcode != OP_LOAD && opcode != OP_STORE) {
556 - if (local)
438 + if (!insn->bb)
439 + continue;
440 + switch (insn->opcode) {
441 + case OP_LOAD:
442 + if (insn->src == pseudo)
443 + return;
444 + break;
445 + case OP_STORE:
446 + if (insn->src == pseudo) {
447 + kill_instruction_force(insn);
557 448 continue;
558 - if (opcode == OP_CALL)
449 + }
450 + break;
451 + case OP_CALL:
452 + if (!local)
559 453 return;
454 + default:
560 455 continue;
561 456 }
562 - if (insn->src == pseudo) {
563 - if (opcode == OP_LOAD)
564 - return;
565 - kill_store(insn);
566 - continue;
567 - }
568 - if (local)
569 - continue;
570 - if (insn->src->type != PSEUDO_SYM)
457 + if (!local && insn->src->type != PSEUDO_SYM)
571 458 return;
572 459 } END_FOR_EACH_PTR_REVERSE(insn);
573 460
574 461 FOR_EACH_PTR(bb->parents, parent) {
575 - struct basic_block *child;
576 - FOR_EACH_PTR(parent->children, child) {
577 - if (child && child != bb)
578 - return;
579 - } END_FOR_EACH_PTR(child);
580 - kill_dead_stores(pseudo, generation, parent, local);
581 - } END_FOR_EACH_PTR(parent);
582 -}
583 -
584 -/*
585 - * This should see if the "insn" trivially dominates some previous store, and kill the
586 - * store if unnecessary.
587 - */
588 -static void kill_dominated_stores(pseudo_t pseudo, struct instruction *insn,
589 - unsigned long generation, struct basic_block *bb, int local, int found)
590 -{
591 - struct instruction *one;
592 - struct basic_block *parent;
593 -
594 - /* Unreachable store? Undo it */
595 - if (!bb) {
596 - kill_store(insn);
597 - return;
598 - }
599 - if (bb->generation == generation)
600 - return;
601 - bb->generation = generation;
602 - FOR_EACH_PTR_REVERSE(bb->insns, one) {
603 - int dominance;
604 - if (!found) {
605 - if (one != insn)
606 - continue;
607 - found = 1;
462 + if (bb_list_size(parent->children) > 1)
608 463 continue;
609 - }
610 - dominance = dominates(pseudo, insn, one, local);
611 - if (!dominance)
612 - continue;
613 - if (dominance < 0)
614 - return;
615 - if (one->opcode == OP_LOAD)
616 - return;
617 - kill_store(one);
618 - } END_FOR_EACH_PTR_REVERSE(one);
619 -
620 - if (!found) {
621 - warning(bb->pos, "Unable to find instruction");
622 - return;
623 - }
624 -
625 - FOR_EACH_PTR(bb->parents, parent) {
626 - struct basic_block *child;
627 - FOR_EACH_PTR(parent->children, child) {
628 - if (child && child != bb)
629 - return;
630 - } END_FOR_EACH_PTR(child);
631 - kill_dominated_stores(pseudo, insn, generation, parent, local, found);
464 + kill_dead_stores_bb(pseudo, generation, parent, local);
632 465 } END_FOR_EACH_PTR(parent);
633 466 }
634 467
635 468 void check_access(struct instruction *insn)
636 469 {
637 470 pseudo_t pseudo = insn->src;
638 471
639 472 if (insn->bb && pseudo->type == PSEUDO_SYM) {
640 473 int offset = insn->offset, bit = bytes_to_bits(offset) + insn->size;
641 474 struct symbol *sym = pseudo->sym;
642 475
643 - if (sym->bit_size > 0 && (offset < 0 || bit > sym->bit_size))
476 + if (sym->bit_size > 0 && (offset < 0 || bit > sym->bit_size)) {
477 + if (insn->tainted)
478 + return;
644 479 warning(insn->pos, "invalid access %s '%s' (%d %d)",
645 480 offset < 0 ? "below" : "past the end of",
646 481 show_ident(sym->ident), offset,
647 482 bits_to_bytes(sym->bit_size));
483 + insn->tainted = 1;
484 + }
648 485 }
649 486 }
650 487
651 -static void simplify_one_symbol(struct entrypoint *ep, struct symbol *sym)
488 +static struct pseudo_user *first_user(pseudo_t p)
652 489 {
653 - pseudo_t pseudo;
654 490 struct pseudo_user *pu;
655 - unsigned long mod;
656 - int all;
657 -
658 - /* Never used as a symbol? */
659 - pseudo = sym->pseudo;
660 - if (!pseudo)
661 - return;
662 -
663 - /* We don't do coverage analysis of volatiles.. */
664 - if (sym->ctype.modifiers & MOD_VOLATILE)
665 - return;
666 -
667 - /* ..and symbols with external visibility need more care */
668 - mod = sym->ctype.modifiers & (MOD_NONLOCAL | MOD_STATIC | MOD_ADDRESSABLE);
669 - if (mod)
670 - goto external_visibility;
671 -
672 - FOR_EACH_PTR(pseudo->users, pu) {
673 - /* We know that the symbol-pseudo use is the "src" in the instruction */
674 - struct instruction *insn = pu->insn;
675 -
676 - switch (insn->opcode) {
677 - case OP_STORE:
678 - break;
679 - case OP_LOAD:
680 - break;
681 - case OP_SYMADDR:
682 - if (!insn->bb)
683 - continue;
684 - mod |= MOD_ADDRESSABLE;
685 - goto external_visibility;
686 - case OP_NOP:
687 - case OP_SNOP:
688 - case OP_LNOP:
689 - case OP_PHI:
491 + FOR_EACH_PTR(p->users, pu) {
492 + if (!pu)
690 493 continue;
691 - default:
692 - warning(sym->pos, "symbol '%s' pseudo used in unexpected way", show_ident(sym->ident));
693 - }
494 + return pu;
694 495 } END_FOR_EACH_PTR(pu);
496 + return NULL;
497 +}
695 498
696 -external_visibility:
697 - all = 1;
698 - FOR_EACH_PTR_REVERSE(pseudo->users, pu) {
699 - struct instruction *insn = pu->insn;
700 - if (insn->opcode == OP_LOAD)
701 - all &= find_dominating_stores(pseudo, insn, ++bb_generation, !mod);
702 - } END_FOR_EACH_PTR_REVERSE(pu);
499 +void kill_dead_stores(struct entrypoint *ep, pseudo_t addr, int local)
500 +{
501 + unsigned long generation;
502 + struct basic_block *bb;
703 503
704 - /* If we converted all the loads, remove the stores. They are dead */
705 - if (all && !mod) {
706 - FOR_EACH_PTR(pseudo->users, pu) {
504 + switch (pseudo_user_list_size(addr->users)) {
505 + case 0:
506 + return;
507 + case 1:
508 + if (local) {
509 + struct pseudo_user *pu = first_user(addr);
707 510 struct instruction *insn = pu->insn;
708 - if (insn->opcode == OP_STORE)
709 - kill_store(insn);
710 - } END_FOR_EACH_PTR(pu);
711 - } else {
712 - /*
713 - * If we couldn't take the shortcut, see if we can at least kill some
714 - * of them..
715 - */
716 - FOR_EACH_PTR(pseudo->users, pu) {
717 - struct instruction *insn = pu->insn;
718 - if (insn->opcode == OP_STORE)
719 - kill_dominated_stores(pseudo, insn, ++bb_generation, insn->bb, !mod, 0);
720 - } END_FOR_EACH_PTR(pu);
721 -
722 - if (!(mod & (MOD_NONLOCAL | MOD_STATIC))) {
723 - struct basic_block *bb;
724 - FOR_EACH_PTR(ep->bbs, bb) {
725 - if (!bb->children)
726 - kill_dead_stores(pseudo, ++bb_generation, bb, !mod);
727 - } END_FOR_EACH_PTR(bb);
511 + if (insn->opcode == OP_STORE) {
512 + kill_instruction_force(insn);
513 + return;
514 + }
728 515 }
516 + default:
517 + break;
729 518 }
730 -
731 - return;
732 -}
733 519
734 -void simplify_symbol_usage(struct entrypoint *ep)
735 -{
736 - pseudo_t pseudo;
737 -
738 - FOR_EACH_PTR(ep->accesses, pseudo) {
739 - simplify_one_symbol(ep, pseudo->sym);
740 - } END_FOR_EACH_PTR(pseudo);
520 + generation = ++bb_generation;
521 + FOR_EACH_PTR(ep->bbs, bb) {
522 + if (bb->children)
523 + continue;
524 + kill_dead_stores_bb(addr, generation, bb, local);
525 + } END_FOR_EACH_PTR(bb);
741 526 }
742 527
743 528 static void mark_bb_reachable(struct basic_block *bb, unsigned long generation)
744 529 {
745 530 struct basic_block *child;
746 531
747 532 if (bb->generation == generation)
748 533 return;
749 534 bb->generation = generation;
750 535 FOR_EACH_PTR(bb->children, child) {
751 536 mark_bb_reachable(child, generation);
752 537 } END_FOR_EACH_PTR(child);
753 538 }
754 539
755 540 static void kill_defs(struct instruction *insn)
756 541 {
757 542 pseudo_t target = insn->target;
758 543
759 544 if (!has_use_list(target))
760 545 return;
761 546 if (target->def != insn)
762 547 return;
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
763 548
764 549 convert_instruction_target(insn, VOID);
765 550 }
766 551
767 552 void kill_bb(struct basic_block *bb)
768 553 {
769 554 struct instruction *insn;
770 555 struct basic_block *child, *parent;
771 556
772 557 FOR_EACH_PTR(bb->insns, insn) {
558 + if (!insn->bb)
559 + continue;
773 560 kill_instruction_force(insn);
774 561 kill_defs(insn);
775 562 /*
776 563 * We kill unreachable instructions even if they
777 564 * otherwise aren't "killable" (e.g. volatile loads)
778 565 */
779 566 } END_FOR_EACH_PTR(insn);
780 567 bb->insns = NULL;
781 568
782 569 FOR_EACH_PTR(bb->children, child) {
783 570 remove_bb_from_list(&child->parents, bb, 0);
784 571 } END_FOR_EACH_PTR(child);
785 572 bb->children = NULL;
786 573
787 574 FOR_EACH_PTR(bb->parents, parent) {
788 575 remove_bb_from_list(&parent->children, bb, 0);
789 576 } END_FOR_EACH_PTR(parent);
790 577 bb->parents = NULL;
791 578 }
792 579
793 580 void kill_unreachable_bbs(struct entrypoint *ep)
794 581 {
795 582 struct basic_block *bb;
796 583 unsigned long generation = ++bb_generation;
797 584
798 585 mark_bb_reachable(ep->entry->bb, generation);
799 586 FOR_EACH_PTR(ep->bbs, bb) {
800 587 if (bb->generation == generation)
801 588 continue;
802 589 /* Mark it as being dead */
803 590 kill_bb(bb);
804 591 bb->ep = NULL;
805 592 DELETE_CURRENT_PTR(bb);
806 593 } END_FOR_EACH_PTR(bb);
807 594 PACK_PTR_LIST(&ep->bbs);
808 595 }
809 596
810 597 static int rewrite_parent_branch(struct basic_block *bb, struct basic_block *old, struct basic_block *new)
811 598 {
812 599 int changed = 0;
813 600 struct instruction *insn = last_instruction(bb->insns);
814 601
815 602 if (!insn)
816 603 return 0;
817 604
818 605 /* Infinite loops: let's not "optimize" them.. */
819 606 if (old == new)
820 607 return 0;
821 608
822 609 switch (insn->opcode) {
823 610 case OP_CBR:
824 611 changed |= rewrite_branch(bb, &insn->bb_false, old, new);
825 612 /* fall through */
826 613 case OP_BR:
827 614 changed |= rewrite_branch(bb, &insn->bb_true, old, new);
828 615 assert(changed);
829 616 return changed;
830 617 case OP_SWITCH: {
831 618 struct multijmp *jmp;
832 619 FOR_EACH_PTR(insn->multijmp_list, jmp) {
833 620 changed |= rewrite_branch(bb, &jmp->target, old, new);
834 621 } END_FOR_EACH_PTR(jmp);
835 622 assert(changed);
836 623 return changed;
↓ open down ↓ |
54 lines elided |
↑ open up ↑ |
837 624 }
838 625 default:
839 626 return 0;
840 627 }
841 628 }
842 629
843 630 static struct basic_block * rewrite_branch_bb(struct basic_block *bb, struct instruction *br)
844 631 {
845 632 struct basic_block *parent;
846 633 struct basic_block *target = br->bb_true;
847 - struct basic_block *false = br->bb_false;
848 634
849 635 if (br->opcode == OP_CBR) {
850 636 pseudo_t cond = br->cond;
851 637 if (cond->type != PSEUDO_VAL)
852 638 return NULL;
853 - target = cond->value ? target : false;
639 + target = cond->value ? target : br->bb_false;
854 640 }
855 641
856 642 /*
857 643 * We can't do FOR_EACH_PTR() here, because the parent list
858 644 * may change when we rewrite the parent.
859 645 */
860 646 while ((parent = first_basic_block(bb->parents)) != NULL) {
861 647 if (!rewrite_parent_branch(parent, bb, target))
862 648 return NULL;
863 649 }
864 650 return target;
865 651 }
866 652
867 653 static void vrfy_bb_in_list(struct basic_block *bb, struct basic_block_list *list)
868 654 {
869 655 if (bb) {
870 656 struct basic_block *tmp;
871 657 int no_bb_in_list = 0;
872 658
873 659 FOR_EACH_PTR(list, tmp) {
874 660 if (bb == tmp)
875 661 return;
876 662 } END_FOR_EACH_PTR(tmp);
877 663 assert(no_bb_in_list);
878 664 }
879 665 }
880 666
881 667 static void vrfy_parents(struct basic_block *bb)
882 668 {
883 669 struct basic_block *tmp;
884 670 FOR_EACH_PTR(bb->parents, tmp) {
885 671 vrfy_bb_in_list(bb, tmp->children);
886 672 } END_FOR_EACH_PTR(tmp);
887 673 }
888 674
889 675 static void vrfy_children(struct basic_block *bb)
890 676 {
891 677 struct basic_block *tmp;
892 678 struct instruction *br = last_instruction(bb->insns);
893 679
894 680 if (!br) {
895 681 assert(!bb->children);
896 682 return;
897 683 }
898 684 switch (br->opcode) {
899 685 struct multijmp *jmp;
900 686 case OP_CBR:
901 687 vrfy_bb_in_list(br->bb_false, bb->children);
902 688 /* fall through */
903 689 case OP_BR:
904 690 vrfy_bb_in_list(br->bb_true, bb->children);
905 691 break;
906 692 case OP_SWITCH:
907 693 case OP_COMPUTEDGOTO:
908 694 FOR_EACH_PTR(br->multijmp_list, jmp) {
909 695 vrfy_bb_in_list(jmp->target, bb->children);
910 696 } END_FOR_EACH_PTR(jmp);
911 697 break;
912 698 default:
913 699 break;
914 700 }
915 701
916 702 FOR_EACH_PTR(bb->children, tmp) {
917 703 vrfy_bb_in_list(bb, tmp->parents);
918 704 } END_FOR_EACH_PTR(tmp);
919 705 }
920 706
921 707 static void vrfy_bb_flow(struct basic_block *bb)
922 708 {
923 709 vrfy_children(bb);
924 710 vrfy_parents(bb);
925 711 }
926 712
927 713 void vrfy_flow(struct entrypoint *ep)
928 714 {
929 715 struct basic_block *bb;
930 716 struct basic_block *entry = ep->entry->bb;
931 717
932 718 FOR_EACH_PTR(ep->bbs, bb) {
933 719 if (bb == entry)
934 720 entry = NULL;
935 721 vrfy_bb_flow(bb);
936 722 } END_FOR_EACH_PTR(bb);
937 723 assert(!entry);
938 724 }
939 725
940 726 void pack_basic_blocks(struct entrypoint *ep)
941 727 {
942 728 struct basic_block *bb;
943 729
944 730 /* See if we can merge a bb into another one.. */
945 731 FOR_EACH_PTR(ep->bbs, bb) {
946 732 struct instruction *first, *insn;
947 733 struct basic_block *parent, *child, *last;
948 734
↓ open down ↓ |
85 lines elided |
↑ open up ↑ |
949 735 if (!bb_reachable(bb))
950 736 continue;
951 737
952 738 /*
953 739 * Just a branch?
954 740 */
955 741 FOR_EACH_PTR(bb->insns, first) {
956 742 if (!first->bb)
957 743 continue;
958 744 switch (first->opcode) {
959 - case OP_NOP: case OP_LNOP: case OP_SNOP:
745 + case OP_NOP:
746 + case OP_INLINED_CALL:
960 747 continue;
961 748 case OP_CBR:
962 749 case OP_BR: {
963 750 struct basic_block *replace;
964 751 replace = rewrite_branch_bb(bb, first);
965 752 if (replace) {
966 753 kill_bb(bb);
967 754 goto no_merge;
968 755 }
969 756 }
970 757 /* fallthrough */
971 758 default:
972 759 goto out;
973 760 }
974 761 } END_FOR_EACH_PTR(first);
975 762
976 763 out:
977 764 /*
978 765 * See if we only have one parent..
979 766 */
980 767 last = NULL;
981 768 FOR_EACH_PTR(bb->parents, parent) {
982 769 if (last) {
983 770 if (last != parent)
984 771 goto no_merge;
985 772 continue;
986 773 }
987 774 last = parent;
988 775 } END_FOR_EACH_PTR(parent);
989 776
990 777 parent = last;
991 778 if (!parent || parent == bb)
992 779 continue;
993 780
994 781 /*
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
995 782 * Goodie. See if the parent can merge..
996 783 */
997 784 FOR_EACH_PTR(parent->children, child) {
998 785 if (child != bb)
999 786 goto no_merge;
1000 787 } END_FOR_EACH_PTR(child);
1001 788
1002 789 /*
1003 790 * Merge the two.
1004 791 */
1005 - repeat_phase |= REPEAT_CSE;
792 + repeat_phase |= REPEAT_CFG_CLEANUP;
1006 793
1007 794 parent->children = bb->children;
1008 795 bb->children = NULL;
1009 796 bb->parents = NULL;
1010 797
1011 798 FOR_EACH_PTR(parent->children, child) {
1012 799 replace_bb_in_list(&child->parents, bb, parent, 0);
1013 800 } END_FOR_EACH_PTR(child);
1014 801
1015 802 kill_instruction(delete_last_instruction(&parent->insns));
1016 803 FOR_EACH_PTR(bb->insns, insn) {
1017 - if (insn->bb) {
1018 - assert(insn->bb == bb);
1019 - insn->bb = parent;
1020 - }
804 + if (!insn->bb)
805 + continue;
806 + assert(insn->bb == bb);
807 + insn->bb = parent;
1021 808 add_instruction(&parent->insns, insn);
1022 809 } END_FOR_EACH_PTR(insn);
1023 810 bb->insns = NULL;
1024 811
1025 812 no_merge:
1026 813 /* nothing to do */;
1027 814 } END_FOR_EACH_PTR(bb);
1028 815 }
1029 816
1030 817
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX