d418c9ba75f2583b4c79bdbddc4d3fd0404752cb
[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) || get_irn_opcode(node) == iro_Pin)
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                 return 0;
221         default:
222                 break;
223         }
224
225         return 1;
226 }
227
228 static void check_schedule(ir_node *node, void *data) {
229         be_verify_schedule_env_t *env = data;
230         int should_be;
231
232         should_be = should_be_scheduled(node);
233         if(should_be == -1)
234                 return;
235
236         if(should_be ? !sched_is_scheduled(node) : sched_is_scheduled(node)) {
237                 ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) should%s be scheduled\n",
238                         node, get_nodes_block(node), get_irg_dump_name(env->irg), should_be ? "" : " not");
239                 env->problem_found = 1;
240         }
241 }
242
243 /**
244  * Start a walk over the irg and check schedule.
245  */
246 int be_verify_schedule(ir_graph *irg)
247 {
248         be_verify_schedule_env_t env;
249
250         env.problem_found = 0;
251         env.irg           = irg;
252
253         irg_block_walk_graph(irg, verify_schedule_walker, NULL, &env);
254         // check if all nodes are scheduled
255         irg_walk_graph(irg, check_schedule, NULL, &env);
256
257         return ! env.problem_found;
258 }
259
260
261
262 //---------------------------------------------------------------------------
263
264
265
266 typedef struct _spill_t {
267         ir_node *spill;
268         entity *ent;
269 } spill_t;
270
271 typedef struct {
272         const arch_env_t *arch_env;
273         ir_graph *irg;
274         set *spills;
275         ir_node **reloads;
276         int problem_found;
277 } be_verify_spillslots_env_t;
278
279 static int cmp_spill(const void* d1, const void* d2, size_t size) {
280         const spill_t* s1 = d1;
281         const spill_t* s2 = d2;
282         return s1->spill != s2->spill;
283 }
284
285 static spill_t *find_spill(be_verify_spillslots_env_t *env, ir_node *node) {
286         spill_t spill;
287
288         spill.spill = node;
289         return set_find(env->spills, &spill, sizeof(spill), HASH_PTR(node));
290 }
291
292 static spill_t *get_spill(be_verify_spillslots_env_t *env, ir_node *node, entity *ent) {
293         spill_t spill, *res;
294         int hash = HASH_PTR(node);
295
296         spill.spill = node;
297         res = set_find(env->spills, &spill, sizeof(spill), hash);
298
299         if(res == NULL) {
300                 spill.ent = ent;
301                 res = set_insert(env->spills, &spill, sizeof(spill), hash);
302         }
303
304         return res;
305 }
306
307 static ir_node *get_memory_edge(const ir_node *node) {
308         int i, arity;
309         ir_node *result = NULL;
310
311         arity = get_irn_arity(node);
312         for(i = arity - 1; i >= 0; --i) {
313                 ir_node *arg = get_irn_n(node, i);
314                 if(get_irn_mode(arg) == mode_M) {
315                         assert(result == NULL);
316                         result = arg;
317                 }
318         }
319
320         return result;
321 }
322
323 static void collect(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, entity* ent);
324
325 static void check_entity(be_verify_spillslots_env_t *env, ir_node *node, entity *ent) {
326         if(ent == NULL) {
327                 ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) should have an entity assigned\n",
328                            node, get_nodes_block(node), get_irg_dump_name(env->irg));
329         }
330 }
331
332 static void collect_spill(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, entity* ent) {
333         entity *spillent = arch_get_frame_entity(env->arch_env, node);
334         check_entity(env, node, spillent);
335         get_spill(env, node, ent);
336
337         if(spillent != ent) {
338                 ir_fprintf(stderr, "Verify warning: Spill %+F has different entity than reload %+F in block %+F(%s)\n",
339                         node, reload, get_nodes_block(node), get_irg_dump_name(env->irg));
340                 env->problem_found = 1;
341         }
342 }
343
344 static void collect_memperm(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, entity* ent) {
345         int i, arity;
346         spill_t spill, *res;
347         int hash = HASH_PTR(node);
348         int out;
349         ir_node* memperm;
350         entity *spillent;
351
352         assert(is_Proj(node));
353
354         memperm = get_Proj_pred(node);
355         out = get_Proj_proj(node);
356
357         spillent = be_get_MemPerm_out_entity(memperm, out);
358         check_entity(env, memperm, spillent);
359         if(spillent != ent) {
360                 ir_fprintf(stderr, "Verify warning: MemPerm %+F has different entity than reload %+F in block %+F(%s)\n",
361                         node, reload, get_nodes_block(node), get_irg_dump_name(env->irg));
362                 env->problem_found = 1;
363         }
364
365         spill.spill = node;
366         res = set_find(env->spills, &spill, sizeof(spill), hash);
367         if(res != NULL) {
368                 return;
369         }
370
371         spill.ent = spillent;
372         res = set_insert(env->spills, &spill, sizeof(spill), hash);
373
374         for(i = 0, arity = be_get_MemPerm_entity_arity(memperm); i < arity; ++i) {
375                 ir_node* arg = get_irn_n(memperm, i + 1);
376                 entity* argent = be_get_MemPerm_in_entity(memperm, i);
377
378                 collect(env, arg, memperm, argent);
379         }
380 }
381
382 static void collect_memphi(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, entity *ent) {
383         int i, arity;
384         spill_t spill, *res;
385         int hash = HASH_PTR(node);
386
387         assert(is_Phi(node));
388
389         spill.spill = node;
390         res = set_find(env->spills, &spill, sizeof(spill), hash);
391         if(res != NULL) {
392                 return;
393         }
394
395         spill.ent = ent;
396         res = set_insert(env->spills, &spill, sizeof(spill), hash);
397
398         // is 1 of the arguments a spill?
399         for(i = 0, arity = get_irn_arity(node); i < arity; ++i) {
400                 ir_node* arg = get_irn_n(node, i);
401                 collect(env, arg, reload, ent);
402         }
403 }
404
405 static void collect(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, entity* ent) {
406         if(be_is_Spill(node)) {
407                 collect_spill(env, node, reload, ent);
408         } else if(is_Proj(node)) {
409                 collect_memperm(env, node, reload, ent);
410         } else if(is_Phi(node) && get_irn_mode(node) == mode_M) {
411                 collect_memphi(env, node, reload, ent);
412         } else {
413                 ir_fprintf(stderr, "Verify warning: No spill, memperm or memphi attached to node %+F found from node %+F in block %+F(%s)\n",
414                         node, reload, get_nodes_block(node), get_irg_dump_name(env->irg));
415                 env->problem_found = 1;
416         }
417 }
418
419 /**
420  * This walker function searches for reloads and collects all the spills
421  * and memphis attached to them.
422  */
423 static void collect_spills_walker(ir_node *node, void *data) {
424         be_verify_spillslots_env_t *env = data;
425         const arch_env_t *arch_env = env->arch_env;
426
427         // @@@ ia32_classify returns classification of Proj_pred :-/
428         if(is_Proj(node))
429                 return;
430
431         if(arch_irn_class_is(arch_env, node, reload)) {
432                 ir_node *spill = get_memory_edge(node);
433                 entity *ent;
434
435                 if(spill == NULL) {
436                         ir_fprintf(stderr, "Verify warning: No spill attached to reload %+F in block %+F(%s)\n",
437                                    node, get_nodes_block(node), get_irg_dump_name(env->irg));
438                         env->problem_found = 1;
439                         return;
440                 }
441                 ent = arch_get_frame_entity(env->arch_env, node);
442                 check_entity(env, node, ent);
443
444                 collect(env, spill, node, ent);
445                 ARR_APP1(ir_node*, env->reloads, node);
446         }
447 }
448
449 static void check_spillslot_interference(be_verify_spillslots_env_t *env) {
450         int spillcount = set_count(env->spills);
451         spill_t **spills = alloca(spillcount * sizeof(spills[0]));
452         spill_t *spill;
453         int i;
454
455         for(spill = set_first(env->spills), i = 0; spill != NULL; spill = set_next(env->spills), ++i) {
456                 spills[i] = spill;
457         }
458
459         for(i = 0; i < spillcount; ++i) {
460                 spill_t *sp1 = spills[i];
461                 int i2;
462
463                 for(i2 = i+1; i2 < spillcount; ++i2) {
464                         spill_t *sp2 = spills[i2];
465
466                         if(sp1->ent != sp2->ent)
467                                 continue;
468
469                         if(my_values_interfere(sp1->spill, sp2->spill)) {
470                                 ir_fprintf(stderr, "Verify warning: Spillslots for %+F in block %+F(%s) and %+F in block %+F(%s) interfere\n",
471                                         sp1->spill, get_nodes_block(sp1->spill), get_irg_dump_name(env->irg),
472                                         sp2->spill, get_nodes_block(sp2->spill), get_irg_dump_name(env->irg));
473                                 env->problem_found = 1;
474                                 my_values_interfere(sp1->spill, sp2->spill);
475                         }
476                 }
477         }
478 }
479
480 static void check_lonely_spills(ir_node *node, void *data) {
481         be_verify_spillslots_env_t *env = data;
482
483         if(be_is_Spill(node) || (is_Proj(node) && be_is_MemPerm(get_Proj_pred(node)))) {
484                 spill_t *spill = find_spill(env, node);
485                 if(be_is_Spill(node)) {
486                         entity *ent = arch_get_frame_entity(env->arch_env, node);
487                         check_entity(env, node, ent);
488                 }
489
490                 if(spill == NULL) {
491                         ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) not connected to a reaload\n",
492                                    node, get_nodes_block(node), get_irg_dump_name(env->irg));
493                 }
494         }
495 }
496
497 int be_verify_spillslots(const arch_env_t *arch_env, ir_graph *irg)
498 {
499         be_verify_spillslots_env_t env;
500
501         env.arch_env = arch_env;
502         env.irg = irg;
503         env.spills = new_set(cmp_spill, 10);
504         env.reloads = NEW_ARR_F(ir_node*, 0);
505         env.problem_found = 0;
506
507         irg_walk_graph(irg, collect_spills_walker, NULL, &env);
508         irg_walk_graph(irg, check_lonely_spills, NULL, &env);
509
510         check_spillslot_interference(&env);
511
512         DEL_ARR_F(env.reloads);
513         del_set(env.spills);
514
515         return ! env.problem_found;
516 }
517
518
519
520 //---------------------------------------------------------------------------
521
522
523
524 /**
525  * Check, if two values interfere.
526  * @param a The first value.
527  * @param b The second value.
528  * @return 1, if a and b interfere, 0 if not.
529  */
530 static int my_values_interfere(const ir_node *a, const ir_node *b) {
531         const ir_edge_t *edge;
532         ir_node *bb;
533         int a2b = value_dominates(a, b);
534         int b2a = value_dominates(b, a);
535
536         /* If there is no dominance relation, they do not interfere. */
537         if(!a2b && !b2a)
538                 return 0;
539
540         /*
541          * Adjust a and b so, that a dominates b if
542          * a dominates b or vice versa.
543          */
544         if(b2a) {
545                 const ir_node *t = a;
546                 a = b;
547                 b = t;
548         }
549
550         bb = get_nodes_block(b);
551
552         /*
553          * Look at all usages of a.
554          * If there's one usage of a in the block of b, then
555          * we check, if this use is dominated by b, if that's true
556          * a and b interfere. Note that b must strictly dominate the user,
557          * since if b is the last user of in the block, b and a do not
558          * interfere.
559          * Uses of a not in b's block can be disobeyed, because the
560          * check for a being live at the end of b's block is already
561          * performed.
562          */
563         foreach_out_edge(a, edge) {
564                 const ir_node *user = get_edge_src_irn(edge);
565                 if(b == user)
566                         continue;
567
568                 if(get_irn_opcode(user) == iro_End)
569                         continue;
570
571                 // in case of phi arguments we compare with the block the value comes from
572                 if(is_Phi(user)) {
573                         ir_node *phiblock = get_nodes_block(user);
574                         if(phiblock == bb)
575                                 continue;
576                         user = get_irn_n(phiblock, get_edge_src_pos(edge));
577                 }
578
579                 if(value_dominates(b, user))
580                         return 1;
581         }
582
583         return 0;
584 }
585
586
587
588 //---------------------------------------------------------------------------
589
590
591
592 typedef struct _be_verify_register_allocation_env_t {
593         const arch_env_t *arch_env;
594         ir_graph *irg;
595         be_lv_t *lv;
596         int problem_found;
597 } be_verify_register_allocation_env_t;
598
599 static void check_register_allocation(be_verify_register_allocation_env_t *env,
600                                       const arch_register_class_t *regclass, pset *nodes) {
601         const arch_env_t *arch_env = env->arch_env;
602         ir_node *node;
603         const arch_register_t *reg;
604         int fail = 0;
605
606         bitset_t *registers = bitset_alloca(arch_register_class_n_regs(regclass));
607
608         foreach_pset(nodes, node) {
609                 if(arch_get_irn_reg_class(arch_env, node, -1) != regclass)
610                         continue;
611
612                 reg = arch_get_irn_register(arch_env, node);
613                 if(reg == NULL) {
614                         ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) should have a register assigned\n",
615                                    node, get_nodes_block(node), get_irg_dump_name(env->irg));
616                         env->problem_found = 1;
617                         continue;
618                 }
619                 if(bitset_is_set(registers, reg->index)) {
620                         pset_break(nodes);
621                         fail = 1;
622                         break;
623                 }
624                 bitset_set(registers, reg->index);
625         }
626         if (fail) {
627                 ir_fprintf(stderr, "Verify warning: Register %s assigned more than once in block %+F(%s)\n",
628                                reg->name, get_nodes_block(node), get_irg_dump_name(env->irg));
629                 env->problem_found = 1;
630
631                 foreach_pset(nodes, node) {
632                         if (arch_get_irn_register(arch_env, node) == reg) {
633                                 ir_fprintf(stderr, "  at node %+F\n", node);
634                         }
635                 }
636         }
637 }
638
639 static void verify_block_register_allocation(ir_node *block, void *data) {
640         be_verify_register_allocation_env_t *env = data;
641         const arch_env_t *arch_env = env->arch_env;
642         const arch_isa_t *isa = arch_env->isa;
643         int i, nregclasses;
644
645         nregclasses = arch_isa_get_n_reg_class(isa);
646         for (i = 0; i < nregclasses; ++i) {
647                 const arch_register_class_t *regclass = arch_isa_get_reg_class(isa, i);
648                 ir_node *node;
649                 pset *live_nodes = pset_new_ptr_default();
650
651                 be_liveness_end_of_block(env->lv, env->arch_env, regclass, block, live_nodes);
652                 check_register_allocation(env, regclass, live_nodes);
653
654                 sched_foreach_reverse(block, node) {
655                         if (is_Phi(node))
656                                 break;
657
658                         be_liveness_transfer(env->arch_env, regclass, node, live_nodes);
659                         check_register_allocation(env, regclass, live_nodes);
660                 }
661
662                 del_pset(live_nodes);
663         }
664 }
665
666 int be_verify_register_allocation(const arch_env_t *arch_env, ir_graph *irg) {
667         be_verify_register_allocation_env_t env;
668
669         env.arch_env = arch_env;
670         env.irg = irg;
671         env.lv = be_liveness(irg);
672         env.problem_found = 0;
673
674         irg_block_walk_graph(irg, verify_block_register_allocation, NULL, &env);
675
676         be_liveness_free(env.lv);
677
678         return !env.problem_found;
679 }