also walk dependencie edges in outedges verifier
[libfirm] / ir / be / beverify.c
1 /*
2  * Author:    Matthias Braun
3  * Date:      05.05.2006
4  * Copyright: (c) Universitaet Karlsruhe
5  * License:   This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
6  * CVS-Id:    $Id$
7  */
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include "bitset.h"
13 #include "set.h"
14 #include "array.h"
15
16 #include "irnode.h"
17 #include "irgraph.h"
18 #include "irgwalk.h"
19 #include "irprintf.h"
20 #include "irdump_t.h"
21 #include "iredges.h"
22
23 #include "beverify.h"
24 #include "belive.h"
25 #include "besched_t.h"
26 #include "benode_t.h"
27
28 static int my_values_interfere(const ir_node *a, const ir_node *b);
29
30 typedef struct be_verify_register_pressure_env_t_ {
31         ir_graph                    *irg;                 /**< the irg to verify */
32          be_lv_t                    *lv;                  /**< Liveness information. */
33         const arch_env_t            *arch_env;            /**< an architecture environment */
34         const arch_register_class_t *cls;                 /**< the register class to check for */
35         int                         registers_available;  /**< number of available registers */
36         int                         problem_found;        /**< flag indicating if a problem was found */
37 } be_verify_register_pressure_env_t;
38
39 /**
40  * Print all nodes of a pset into a file.
41  */
42 static void print_living_values(FILE *F, pset *live_nodes) {
43         ir_node *node;
44
45         ir_fprintf(F, "\t");
46         foreach_pset(live_nodes, node) {
47                 ir_fprintf(F, "%+F ", node);
48         }
49         ir_fprintf(F, "\n");
50 }
51
52 /**
53  * Check if number of live nodes never exceeds the number of available registers.
54  */
55 static void verify_liveness_walker(ir_node *block, void *data) {
56         be_verify_register_pressure_env_t *env = (be_verify_register_pressure_env_t *)data;
57         pset    *live_nodes = pset_new_ptr_default();
58         ir_node *irn;
59         int pressure;
60
61         /* collect register pressure info, start with end of a block */
62         be_liveness_end_of_block(env->lv, env->arch_env, env->cls, block, live_nodes);
63
64         pressure = pset_count(live_nodes);
65         if(pressure > env->registers_available) {
66                 ir_fprintf(stderr, "Verify Warning: Register pressure too high at end of block %+F(%s) (%d/%d):\n",
67                         block, get_irg_dump_name(env->irg), pressure, env->registers_available);
68                 print_living_values(stderr, live_nodes);
69                 env->problem_found = 1;
70         }
71
72         sched_foreach_reverse(block, irn) {
73                 if (is_Phi(irn))
74                         break;
75
76                 be_liveness_transfer(env->arch_env, env->cls, irn, live_nodes);
77
78                 pressure = pset_count(live_nodes);
79
80                 if(pressure > env->registers_available) {
81                         ir_fprintf(stderr, "Verify Warning: Register pressure too high before node %+F in %+F(%s) (%d/%d):\n",
82                                 irn, block, get_irg_dump_name(env->irg), pressure, env->registers_available);
83                         print_living_values(stderr, live_nodes);
84                         env->problem_found = 1;
85                 }
86         }
87         del_pset(live_nodes);
88 }
89
90 /**
91  * Start a walk over the irg and check the register pressure.
92  */
93 int be_verify_register_pressure(const be_irg_t *birg, const arch_register_class_t *cls, ir_graph *irg) {
94         be_verify_register_pressure_env_t env;
95
96         env.lv                  = be_liveness(irg);
97         env.irg                 = irg;
98         env.arch_env            = birg->main_env->arch_env;
99         env.cls                 = cls;
100         env.registers_available = env.cls->n_regs - be_put_ignore_regs(birg, env.cls, NULL);
101         env.problem_found       = 0;
102
103         irg_block_walk_graph(irg, verify_liveness_walker, NULL, &env);
104         be_liveness_free(env.lv);
105
106         return ! env.problem_found;
107 }
108
109 typedef struct be_verify_schedule_env_t_ {
110         int      problem_found;    /**< flags indicating if there was a problem */
111         ir_graph *irg;             /**< the irg to check */
112 } be_verify_schedule_env_t;
113
114 /**
115  * Simple schedule checker.
116  */
117 static void verify_schedule_walker(ir_node *block, void *data) {
118         be_verify_schedule_env_t *env = (be_verify_schedule_env_t*) data;
119         ir_node *node;
120         int non_phi_found  = 0;
121         int cfchange_found = 0;
122         // TODO ask arch about delay branches
123         int delay_branches = 0;
124
125         /*
126          * Tests for the following things:
127          *   1. Make sure that all phi nodes are scheduled at the beginning of the block
128          *   2. There is 1 or no control flow changing node scheduled and exactly delay_branches operations after it.
129          *   3. No value is defined after it has been used
130          */
131         sched_foreach(block, node) {
132                 int i, arity;
133
134                 // 1. Check for phis
135                 if (is_Phi(node)) {
136                         if (non_phi_found) {
137                                 ir_fprintf(stderr, "Verify Warning: Phi node %+F scheduled after non-Phi nodes in block %+F (%s)\n",
138                                         node, block, get_irg_dump_name(env->irg));
139                                 env->problem_found = 1;
140                         }
141                 } else {
142                         non_phi_found = 1;
143                 }
144
145                 // 2. Check for control flow changing nodes
146                 if (is_cfop(node) && get_irn_opcode(node) != iro_Start) {
147                         /* check, that only one CF operation is scheduled */
148                         if (cfchange_found == 1) {
149                                 ir_fprintf(stderr, "Verify Warning: More than 1 control flow changing node (%+F) scheduled in block %+F (%s)\n",
150                                         node, block, get_irg_dump_name(env->irg));
151                                 env->problem_found = 1;
152                         }
153                         cfchange_found = 1;
154                 } else if (cfchange_found) {
155                         // proj and keepany aren't real instructions...
156                         if(!is_Proj(node) && !be_is_Keep(node)) {
157                                 /* check for delay branches */
158                                 if (delay_branches == 0) {
159                                         ir_fprintf(stderr, "Verify Warning: Node %+F scheduled after control flow changing node (+delay branches) in block %+F (%s)\n",
160                                                 node, block, get_irg_dump_name(env->irg));
161                                         env->problem_found = 1;
162                                 } else {
163                                         delay_branches--;
164                                 }
165                         }
166                 }
167
168                 // 3. Check for uses
169                 if(!is_Phi(node)) {
170                         int nodetime = sched_get_time_step(node);
171                         for(i = 0, arity = get_irn_arity(node); i < arity; ++i) {
172                                 ir_node *arg = get_irn_n(node, i);
173                                 if(get_nodes_block(arg) != block
174                                    || !sched_is_scheduled(arg))
175                                         continue;
176
177                                 if(sched_get_time_step(arg) >= nodetime) {
178                                         ir_fprintf(stderr, "Verify Warning: Value %+F used by %+F before it was defined in block %+F (%s)\n",
179                                                    arg, node, block, get_irg_dump_name(env->irg));
180                                         env->problem_found = 1;
181                                 }
182                         }
183                 }
184
185                 // 4. check for dead nodes
186                 if(get_irn_n_edges(node) == 0) {
187                         ir_fprintf(stderr, "Verify warning: Node %+F is dead but scheduled in block %+F (%s)\n",
188                                    node, block, get_irg_dump_name(env->irg));
189                         env->problem_found = 1;
190                 }
191         }
192
193         /* check that all delay branches are filled (at least with NOPs) */
194         if (cfchange_found && delay_branches != 0) {
195                 ir_fprintf(stderr, "Verify warning: Not all delay slots filled after jump (%d/%d) in block %+F (%s)\n",
196                         block, get_irg_dump_name(env->irg));
197                 env->problem_found = 1;
198         }
199 }
200
201 static int should_be_scheduled(ir_node *node) {
202         if(is_Block(node))
203                 return -1;
204
205         if(get_irn_mode(node) == mode_M) {
206                 if(is_Proj(node))
207                         return -1;
208                 if(is_Phi(node) || is_Sync(node) || is_Pin(node))
209                         return 0;
210         }
211         if(is_Proj(node) && get_irn_mode(node) == mode_X)
212                 return 0;
213         if(be_is_Keep(node) && get_irn_opcode(get_nodes_block(node)) == iro_Bad)
214                 return 0;
215
216         switch(get_irn_opcode(node)) {
217         case iro_End:
218         case iro_NoMem:
219         case iro_Bad:
220         case iro_Unknown:
221                 return 0;
222         default:
223                 break;
224         }
225
226         return 1;
227 }
228
229 static void check_schedule(ir_node *node, void *data) {
230         be_verify_schedule_env_t *env = data;
231         int should_be;
232
233         should_be = should_be_scheduled(node);
234         if(should_be == -1)
235                 return;
236
237         if(should_be ? !sched_is_scheduled(node) : sched_is_scheduled(node)) {
238                 ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) should%s be scheduled\n",
239                         node, get_nodes_block(node), get_irg_dump_name(env->irg), should_be ? "" : " not");
240                 env->problem_found = 1;
241         }
242 }
243
244 /**
245  * Start a walk over the irg and check schedule.
246  */
247 int be_verify_schedule(ir_graph *irg)
248 {
249         be_verify_schedule_env_t env;
250
251         env.problem_found = 0;
252         env.irg           = irg;
253
254         irg_block_walk_graph(irg, verify_schedule_walker, NULL, &env);
255         // check if all nodes are scheduled
256         irg_walk_graph(irg, check_schedule, NULL, &env);
257
258         return ! env.problem_found;
259 }
260
261
262
263 //---------------------------------------------------------------------------
264
265
266
267 typedef struct _spill_t {
268         ir_node *spill;
269         ir_entity *ent;
270 } spill_t;
271
272 typedef struct {
273         const arch_env_t *arch_env;
274         ir_graph *irg;
275         set *spills;
276         ir_node **reloads;
277         int problem_found;
278 } be_verify_spillslots_env_t;
279
280 static int cmp_spill(const void* d1, const void* d2, size_t size) {
281         const spill_t* s1 = d1;
282         const spill_t* s2 = d2;
283         return s1->spill != s2->spill;
284 }
285
286 static spill_t *find_spill(be_verify_spillslots_env_t *env, ir_node *node) {
287         spill_t spill;
288
289         spill.spill = node;
290         return set_find(env->spills, &spill, sizeof(spill), HASH_PTR(node));
291 }
292
293 static spill_t *get_spill(be_verify_spillslots_env_t *env, ir_node *node, ir_entity *ent) {
294         spill_t spill, *res;
295         int hash = HASH_PTR(node);
296
297         spill.spill = node;
298         res = set_find(env->spills, &spill, sizeof(spill), hash);
299
300         if(res == NULL) {
301                 spill.ent = ent;
302                 res = set_insert(env->spills, &spill, sizeof(spill), hash);
303         }
304
305         return res;
306 }
307
308 static ir_node *get_memory_edge(const ir_node *node) {
309         int i, arity;
310         ir_node *result = NULL;
311
312         arity = get_irn_arity(node);
313         for(i = arity - 1; i >= 0; --i) {
314                 ir_node *arg = get_irn_n(node, i);
315                 if(get_irn_mode(arg) == mode_M) {
316                         assert(result == NULL);
317                         result = arg;
318                 }
319         }
320
321         return result;
322 }
323
324 static void collect(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity* ent);
325
326 static void check_entity(be_verify_spillslots_env_t *env, ir_node *node, ir_entity *ent) {
327         if(ent == NULL) {
328                 ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) should have an entity assigned\n",
329                            node, get_nodes_block(node), get_irg_dump_name(env->irg));
330         }
331 }
332
333 static void collect_spill(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity* ent) {
334         ir_entity *spillent = arch_get_frame_entity(env->arch_env, node);
335         check_entity(env, node, spillent);
336         get_spill(env, node, ent);
337
338         if(spillent != ent) {
339                 ir_fprintf(stderr, "Verify warning: Spill %+F has different entity than reload %+F in block %+F(%s)\n",
340                         node, reload, get_nodes_block(node), get_irg_dump_name(env->irg));
341                 env->problem_found = 1;
342         }
343 }
344
345 static void collect_memperm(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity* ent) {
346         int i, arity;
347         spill_t spill, *res;
348         int hash = HASH_PTR(node);
349         int out;
350         ir_node* memperm;
351         ir_entity *spillent;
352
353         assert(is_Proj(node));
354
355         memperm = get_Proj_pred(node);
356         out = get_Proj_proj(node);
357
358         spillent = be_get_MemPerm_out_entity(memperm, out);
359         check_entity(env, memperm, spillent);
360         if(spillent != ent) {
361                 ir_fprintf(stderr, "Verify warning: MemPerm %+F has different entity than reload %+F in block %+F(%s)\n",
362                         node, reload, get_nodes_block(node), get_irg_dump_name(env->irg));
363                 env->problem_found = 1;
364         }
365
366         spill.spill = node;
367         res = set_find(env->spills, &spill, sizeof(spill), hash);
368         if(res != NULL) {
369                 return;
370         }
371
372         spill.ent = spillent;
373         res = set_insert(env->spills, &spill, sizeof(spill), hash);
374
375         for(i = 0, arity = be_get_MemPerm_entity_arity(memperm); i < arity; ++i) {
376                 ir_node* arg = get_irn_n(memperm, i + 1);
377                 ir_entity* argent = be_get_MemPerm_in_entity(memperm, i);
378
379                 collect(env, arg, memperm, argent);
380         }
381 }
382
383 static void collect_memphi(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity *ent) {
384         int i, arity;
385         spill_t spill, *res;
386         int hash = HASH_PTR(node);
387
388         assert(is_Phi(node));
389
390         spill.spill = node;
391         res = set_find(env->spills, &spill, sizeof(spill), hash);
392         if(res != NULL) {
393                 return;
394         }
395
396         spill.ent = ent;
397         res = set_insert(env->spills, &spill, sizeof(spill), hash);
398
399         // is 1 of the arguments a spill?
400         for(i = 0, arity = get_irn_arity(node); i < arity; ++i) {
401                 ir_node* arg = get_irn_n(node, i);
402                 collect(env, arg, reload, ent);
403         }
404 }
405
406 static void collect(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity* ent) {
407         if(be_is_Spill(node)) {
408                 collect_spill(env, node, reload, ent);
409         } else if(is_Proj(node)) {
410                 collect_memperm(env, node, reload, ent);
411         } else if(is_Phi(node) && get_irn_mode(node) == mode_M) {
412                 collect_memphi(env, node, reload, ent);
413         } else {
414                 ir_fprintf(stderr, "Verify warning: No spill, memperm or memphi attached to node %+F found from node %+F in block %+F(%s)\n",
415                         node, reload, get_nodes_block(node), get_irg_dump_name(env->irg));
416                 env->problem_found = 1;
417         }
418 }
419
420 /**
421  * This walker function searches for reloads and collects all the spills
422  * and memphis attached to them.
423  */
424 static void collect_spills_walker(ir_node *node, void *data) {
425         be_verify_spillslots_env_t *env = data;
426         const arch_env_t *arch_env = env->arch_env;
427
428         // @@@ ia32_classify returns classification of Proj_pred :-/
429         if(is_Proj(node))
430                 return;
431
432         if(arch_irn_class_is(arch_env, node, reload)) {
433                 ir_node *spill = get_memory_edge(node);
434                 ir_entity *ent;
435
436                 if(spill == NULL) {
437                         ir_fprintf(stderr, "Verify warning: No spill attached to reload %+F in block %+F(%s)\n",
438                                    node, get_nodes_block(node), get_irg_dump_name(env->irg));
439                         env->problem_found = 1;
440                         return;
441                 }
442                 ent = arch_get_frame_entity(env->arch_env, node);
443                 check_entity(env, node, ent);
444
445                 collect(env, spill, node, ent);
446                 ARR_APP1(ir_node*, env->reloads, node);
447         }
448 }
449
450 static void check_spillslot_interference(be_verify_spillslots_env_t *env) {
451         int spillcount = set_count(env->spills);
452         spill_t **spills = alloca(spillcount * sizeof(spills[0]));
453         spill_t *spill;
454         int i;
455
456         for(spill = set_first(env->spills), i = 0; spill != NULL; spill = set_next(env->spills), ++i) {
457                 spills[i] = spill;
458         }
459
460         for(i = 0; i < spillcount; ++i) {
461                 spill_t *sp1 = spills[i];
462                 int i2;
463
464                 for(i2 = i+1; i2 < spillcount; ++i2) {
465                         spill_t *sp2 = spills[i2];
466
467                         if(sp1->ent != sp2->ent)
468                                 continue;
469
470                         if(my_values_interfere(sp1->spill, sp2->spill)) {
471                                 ir_fprintf(stderr, "Verify warning: Spillslots for %+F in block %+F(%s) and %+F in block %+F(%s) interfere\n",
472                                         sp1->spill, get_nodes_block(sp1->spill), get_irg_dump_name(env->irg),
473                                         sp2->spill, get_nodes_block(sp2->spill), get_irg_dump_name(env->irg));
474                                 env->problem_found = 1;
475                                 my_values_interfere(sp1->spill, sp2->spill);
476                         }
477                 }
478         }
479 }
480
481 static void check_lonely_spills(ir_node *node, void *data) {
482         be_verify_spillslots_env_t *env = data;
483
484         if(be_is_Spill(node) || (is_Proj(node) && be_is_MemPerm(get_Proj_pred(node)))) {
485                 spill_t *spill = find_spill(env, node);
486                 if(be_is_Spill(node)) {
487                         ir_entity *ent = arch_get_frame_entity(env->arch_env, node);
488                         check_entity(env, node, ent);
489                 }
490
491                 if(spill == NULL) {
492                         ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) not connected to a reaload\n",
493                                    node, get_nodes_block(node), get_irg_dump_name(env->irg));
494                 }
495         }
496 }
497
498 int be_verify_spillslots(const arch_env_t *arch_env, ir_graph *irg)
499 {
500         be_verify_spillslots_env_t env;
501
502         env.arch_env = arch_env;
503         env.irg = irg;
504         env.spills = new_set(cmp_spill, 10);
505         env.reloads = NEW_ARR_F(ir_node*, 0);
506         env.problem_found = 0;
507
508         irg_walk_graph(irg, collect_spills_walker, NULL, &env);
509         irg_walk_graph(irg, check_lonely_spills, NULL, &env);
510
511         check_spillslot_interference(&env);
512
513         DEL_ARR_F(env.reloads);
514         del_set(env.spills);
515
516         return ! env.problem_found;
517 }
518
519
520
521 //---------------------------------------------------------------------------
522
523
524
525 /**
526  * Check, if two values interfere.
527  * @param a The first value.
528  * @param b The second value.
529  * @return 1, if a and b interfere, 0 if not.
530  */
531 static int my_values_interfere(const ir_node *a, const ir_node *b) {
532         const ir_edge_t *edge;
533         ir_node *bb;
534         int a2b = value_dominates(a, b);
535         int b2a = value_dominates(b, a);
536
537         /* If there is no dominance relation, they do not interfere. */
538         if(!a2b && !b2a)
539                 return 0;
540
541         /*
542          * Adjust a and b so, that a dominates b if
543          * a dominates b or vice versa.
544          */
545         if(b2a) {
546                 const ir_node *t = a;
547                 a = b;
548                 b = t;
549         }
550
551         bb = get_nodes_block(b);
552
553         /*
554          * Look at all usages of a.
555          * If there's one usage of a in the block of b, then
556          * we check, if this use is dominated by b, if that's true
557          * a and b interfere. Note that b must strictly dominate the user,
558          * since if b is the last user of in the block, b and a do not
559          * interfere.
560          * Uses of a not in b's block can be disobeyed, because the
561          * check for a being live at the end of b's block is already
562          * performed.
563          */
564         foreach_out_edge(a, edge) {
565                 const ir_node *user = get_edge_src_irn(edge);
566                 if(b == user)
567                         continue;
568
569                 if(get_irn_opcode(user) == iro_End)
570                         continue;
571
572                 // in case of phi arguments we compare with the block the value comes from
573                 if(is_Phi(user)) {
574                         ir_node *phiblock = get_nodes_block(user);
575                         if(phiblock == bb)
576                                 continue;
577                         user = get_irn_n(phiblock, get_edge_src_pos(edge));
578                 }
579
580                 if(value_dominates(b, user))
581                         return 1;
582         }
583
584         return 0;
585 }
586
587
588
589 //---------------------------------------------------------------------------
590
591
592
593 typedef struct _be_verify_register_allocation_env_t {
594         const arch_env_t *arch_env;
595         ir_graph *irg;
596         be_lv_t *lv;
597         int problem_found;
598 } be_verify_register_allocation_env_t;
599
600 static void check_register_constraints(ir_node *node, be_verify_register_allocation_env_t *env) {
601         const arch_env_t      *arch_env = env->arch_env;
602         const arch_register_t *reg;
603         int                   i, arity;
604
605         /* verify output register */
606         if (arch_get_irn_reg_class(arch_env, node, -1) != NULL) {
607                 reg = arch_get_irn_register(arch_env, node);
608                 if (reg == NULL) {
609                         ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) should have a register assigned\n",
610                                         node, get_nodes_block(node), get_irg_dump_name(env->irg));
611                         env->problem_found = 1;
612                 }
613                 else if (! arch_register_type_is(reg, joker) && !arch_reg_is_allocatable(arch_env, node, -1, reg)) {
614                         ir_fprintf(stderr, "Verify warning: Register %s assigned as output of %+F not allowed (register constraint) in block %+F(%s)\n",
615                                         reg->name, node, get_nodes_block(node), get_irg_dump_name(env->irg));
616                         env->problem_found = 1;
617                 }
618         }
619
620         /* verify input register */
621         arity = get_irn_arity(node);
622         for (i = 0; i < arity; ++i) {
623                 ir_node *pred = get_irn_n(node, i);
624
625                 if (is_Unknown(pred))
626                         continue;
627
628                 if (is_Bad(pred)) {
629                         ir_fprintf(stderr, "Verify warning: %+F in block %+F(%s) has Bad as input %d\n",
630                                 node, get_nodes_block(node), get_irg_dump_name(env->irg), i);
631                         env->problem_found = 1;
632                         continue;
633                 }
634
635                 if (arch_get_irn_reg_class(arch_env, node, i) == NULL)
636                         continue;
637
638                 reg = arch_get_irn_register(arch_env, pred);
639                 if (reg == NULL) {
640                         ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) should have a register assigned\n",
641                                    pred, get_nodes_block(pred), get_irg_dump_name(env->irg));
642                         env->problem_found = 1;
643                         continue;
644                 }
645                 else if (! arch_register_type_is(reg, joker) && ! arch_reg_is_allocatable(arch_env, node, i, reg)) {
646                         ir_fprintf(stderr, "Verify warning: Register %s as input %d of %+F not allowed (register constraint) in block %+F(%s)\n",
647                                    reg->name, i, node, get_nodes_block(node), get_irg_dump_name(env->irg));
648                         env->problem_found = 1;
649                 }
650         }
651 }
652
653 static void check_register_allocation(be_verify_register_allocation_env_t *env,
654                                       const arch_register_class_t *regclass, pset *nodes) {
655         const arch_env_t      *arch_env  = env->arch_env;
656         const arch_register_t *reg       = NULL;
657         int                   fail       = 0;
658         bitset_t              *registers = bitset_alloca(arch_register_class_n_regs(regclass));
659         ir_node               *node;
660
661         foreach_pset(nodes, node) {
662                 if (arch_get_irn_reg_class(arch_env, node, -1) != regclass)
663                         continue;
664
665                 reg = arch_get_irn_register(arch_env, node);
666
667                 /* this problem is already reported in 'check_register_constraints' */
668                 if (! reg)
669                         continue;
670
671                 if (bitset_is_set(registers, reg->index)) {
672                         pset_break(nodes);
673                         fail = 1;
674                         break;
675                 }
676                 bitset_set(registers, reg->index);
677         }
678
679         if (fail) {
680                 ir_fprintf(stderr, "Verify warning: Register %s assigned more than once in block %+F(%s)\n",
681                                reg->name, get_nodes_block(node), get_irg_dump_name(env->irg));
682                 env->problem_found = 1;
683
684                 foreach_pset(nodes, node) {
685                         if (arch_get_irn_register(arch_env, node) == reg) {
686                                 ir_fprintf(stderr, "  at node %+F\n", node);
687                         }
688                 }
689         }
690 }
691
692 static void verify_block_register_allocation(ir_node *block, void *data) {
693         be_verify_register_allocation_env_t *env = data;
694         const arch_env_t *arch_env = env->arch_env;
695         const arch_isa_t *isa = arch_env->isa;
696         int i, nregclasses;
697
698         nregclasses = arch_isa_get_n_reg_class(isa);
699         for (i = 0; i < nregclasses; ++i) {
700                 const arch_register_class_t *regclass = arch_isa_get_reg_class(isa, i);
701                 ir_node *node;
702                 pset *live_nodes = pset_new_ptr_default();
703
704                 be_liveness_end_of_block(env->lv, env->arch_env, regclass, block, live_nodes);
705                 check_register_allocation(env, regclass, live_nodes);
706
707                 sched_foreach_reverse(block, node) {
708                         if (is_Phi(node))
709                                 break;
710
711                         be_liveness_transfer(env->arch_env, regclass, node, live_nodes);
712                         check_register_allocation(env, regclass, live_nodes);
713                         check_register_constraints(node, env);
714                 }
715
716                 del_pset(live_nodes);
717         }
718 }
719
720 int be_verify_register_allocation(const arch_env_t *arch_env, ir_graph *irg) {
721         be_verify_register_allocation_env_t env;
722
723         env.arch_env = arch_env;
724         env.irg = irg;
725         env.lv = be_liveness(irg);
726         env.problem_found = 0;
727
728         irg_block_walk_graph(irg, verify_block_register_allocation, NULL, &env);
729
730         be_liveness_free(env.lv);
731
732         return !env.problem_found;
733 }
734
735
736
737 //---------------------------------------------------------------------------
738
739
740
741 typedef struct _verify_out_dead_nodes_env {
742         ir_graph *irg;
743         bitset_t *reachable;
744         int problem_found;
745 } verify_out_dead_nodes_env;
746
747 static void check_out_edges(ir_node *node, verify_out_dead_nodes_env *env) {
748         ir_graph *irg = env->irg;
749         const ir_edge_t* edge;
750
751         if(irn_visited(node))
752                 return;
753         mark_irn_visited(node);
754
755         foreach_out_edge(node, edge) {
756                 ir_node* src = get_edge_src_irn(edge);
757
758                 if(!bitset_is_set(env->reachable, get_irn_idx(src))) {
759                         if(src != get_irg_globals(irg)
760                                         && src != get_irg_tls(irg)) {
761                                 ir_fprintf(stderr,
762                                            "Verify warning: Node %+F in block %+F(%s) only reachable through out edges from %+F\n",
763                                            src, get_nodes_block(src), get_irg_dump_name(irg), node);
764                                 env->problem_found = 1;
765                         }
766                         continue;
767                 }
768
769                 if(!is_Block(src)) {
770                         check_out_edges(src, env);
771                 }
772         }
773 }
774
775 static void set_reachable(ir_node *node, void* data)
776 {
777         bitset_t* reachable = data;
778         bitset_set(reachable, get_irn_idx(node));
779 }
780
781 int be_verify_out_edges(ir_graph *irg) {
782         verify_out_dead_nodes_env env;
783         env.irg = irg;
784         env.reachable = bitset_alloca(get_irg_last_idx(irg));
785         env.problem_found = 0;
786
787         irg_walk_in_or_dep_graph(irg, set_reachable, NULL, env.reachable);
788         inc_irg_visited(irg);
789         check_out_edges(get_irg_start(irg), &env);
790
791         return !env.problem_found;
792 }