Verify functions now returns a result (and can run in release mode)
[libfirm] / ir / ir / irvrfy.c
1 /* Copyright (C) 1998 - 2000 by Universitaet Karlsruhe
2 * All rights reserved.
3 *
4 * Authors: Christian Schaefer
5 *
6 *
7 */
8
9 /* $Id$ */
10
11 #ifdef HAVE_CONFIG_H
12 # include <config.h>
13 #endif
14
15 # include "irgraph_t.h"
16 # include "irvrfy.h"
17 # include "irgwalk.h"
18
19 #ifdef NDEBUG
20 #define ASSERT_AND_RET(expr, string, ret)       if (!(expr)) return (ret)
21 #else
22 #define ASSERT_AND_RET(expr, string, ret)       do { assert((expr) && string); if (!(expr)) return (ret); } while(0)
23 #endif
24
25 /* @@@ replace use of array "in" by access functions. */
26 ir_node **get_irn_in(ir_node *node);
27
28 INLINE static int
29 vrfy_Proj_proj(ir_node *p, ir_graph *irg) {
30   ir_node *pred;
31   ir_mode *mode;
32   int proj;
33
34   pred = skip_nop(get_Proj_pred(p));
35   assert(get_irn_mode(pred) == mode_T);
36   mode = get_irn_mode(p);
37   proj = get_Proj_proj(p);
38
39   switch (get_irn_opcode(pred)) {
40   case iro_Start:
41     ASSERT_AND_RET(
42       ((proj == 0 && mode == mode_X) ||
43        (proj == 1 && mode == mode_M) ||
44        (proj == 2 && mode == mode_P) ||
45        (proj == 3 && mode == mode_P) ||
46        (proj == 4 && mode == mode_T)),
47       "wrong Proj from Start", 0);
48     break;
49   case iro_Cond:
50     ASSERT_AND_RET( (proj >= 0 && mode == mode_X), "wrong Proj from Cond", 0);
51     break;
52   case iro_Raise:
53     ASSERT_AND_RET( ((proj == 0 && mode == mode_X) || (proj == 1 && mode == mode_M)),
54             "wrong Proj from Raise", 0);
55     break;
56   case iro_InstOf:
57     ASSERT_AND_RET( (proj >= 0 && mode == mode_X), "wrong Proj from InstOf", 0);
58     break;
59   case iro_Call:
60     ASSERT_AND_RET(
61       ((proj == 0 && mode == mode_M) ||
62        (proj == 1 && mode == mode_X) ||
63        (proj == 2 && mode == mode_T) ||
64        (proj == 3 && mode == mode_M)),
65       "wrong Proj from Call", 0);
66     break;
67   case iro_Quot:
68     ASSERT_AND_RET(
69       ((proj == 0 && mode == mode_M) ||
70        (proj == 1 && mode == mode_X) ||
71        (proj == 2 && mode_is_float(mode))),
72       "wrong Proj from Quot", 0);
73     break;
74   case iro_DivMod:
75     ASSERT_AND_RET(
76       ((proj == 0 && mode == mode_M) ||
77        (proj == 1 && mode == mode_X) ||
78        (proj == 2 && mode == mode_Is) ||
79        (proj == 3 && mode == mode_Is)),
80       "wrong Proj from DivMod", 0);
81     break;
82   case iro_Div:
83   case iro_Mod:
84     ASSERT_AND_RET(
85       ((proj == 0 && mode == mode_M) ||
86        (proj == 1 && mode == mode_X) ||
87        (proj == 2 && mode == mode_Is)),
88       "wrong Proj from Div or Mod", 0);
89     break;
90   case iro_Cmp:
91     ASSERT_AND_RET(
92       (proj >= 0 && proj <= 15 && mode == mode_b),
93       "wrong Proj from Cmp", 0);
94     break;
95   case iro_Load:
96     ASSERT_AND_RET(
97       ((proj == 0 && mode == mode_M) ||
98        (proj == 1 && mode == mode_X) ||
99        (proj == 2 && mode_is_data(mode))),
100       "wrong Proj from Load", 0);
101     break;
102   case iro_Store:
103     ASSERT_AND_RET(
104       ((proj == 0 && mode == mode_M) ||
105        (proj == 1 && mode == mode_X)),
106       "wrong Proj from Store", 0);
107     break;
108   case iro_Alloc:
109     ASSERT_AND_RET(
110       ((proj == 0 && mode == mode_M) ||
111        (proj == 1 /* && mode == mode_X*/) ||
112        (proj == 2 && mode == mode_P)),
113       "wrong Proj from Alloc", 0);
114     break;
115   case iro_Proj: {
116     type *mt; /* A method type */
117     pred = skip_nop(get_Proj_pred(pred));
118     ASSERT_AND_RET((get_irn_mode(pred) == mode_T), "Proj from something not a tuple", 0);
119     switch (get_irn_opcode(pred)) {
120     case iro_Start: {
121       ASSERT_AND_RET(
122         (proj >= 0 && mode_is_data(mode)),
123         "wrong Proj from Proj from Start", 0);
124       mt = get_entity_type(get_irg_ent(irg));
125       ASSERT_AND_RET(
126         (proj < get_method_n_params(mt)),
127         "More Projs for args than args in type", 0);
128       if ((mode == mode_P) && is_compound_type(get_method_param_type(mt, proj)))
129         /* value argument */ break;
130       ASSERT_AND_RET(
131         (mode == get_type_mode(get_method_param_type(mt, proj))),
132         "Mode of Proj from Start doesn't match mode of param type.", 0);
133     } break;
134     case iro_Call: {
135       ASSERT_AND_RET(
136         (proj >= 0 && mode_is_data(mode)),
137         "wrong Proj from Proj from Call", 0);
138       mt = get_Call_type(pred);
139       ASSERT_AND_RET(
140         (proj < get_method_n_ress(mt)),
141         "More Projs for results than results in type.", 0);
142       if ((mode == mode_P) && is_compound_type(get_method_res_type(mt, proj)))
143         /* value result */ break;
144       ASSERT_AND_RET(
145         (mode == get_type_mode(get_method_res_type(mt, proj))),
146         "Mode of Proj from Call doesn't match mode of result type.", 0);
147     } break;
148     case iro_Tuple: ;
149       /* We don't test */
150       break;
151     default:
152       ASSERT_AND_RET(0, "Unknown opcode", 0);
153     } break;
154   }
155   case iro_Tuple:
156     /* We don't test */
157     break;
158   case iro_CallBegin:
159     break;
160   case iro_EndReg:
161     break;
162   case iro_EndExcept:
163     break;
164   default:
165     ASSERT_AND_RET(0, "Unknown opcode", 0);
166   }
167
168   /* all went ok */
169   return 1;
170 }
171
172 int irn_vrfy_irg(ir_node *n, ir_graph *irg)
173 {
174   int i;
175   int opcode, opcode1;
176   ir_mode *mymode, *op1mode = NULL, *op2mode, *op3mode;
177   int op_is_symmetric = 1;      /* 0: asymmetric
178                                    1: operands have identical modes
179                                    2: modes of operands == mode of this node */
180   type *mt; /* A method type */
181
182   ir_node **in;
183
184   if (! interprocedural_view) {
185     /*
186      * do NOT check placement in interprocedural view, as we don't always know
187      * the "right" graph ...
188      */
189     ASSERT_AND_RET(node_is_in_irgs_storage(irg, n), "Node is not stored on proper IR graph!", 0);
190   }
191
192   opcode = get_irn_opcode (n);
193
194   /* We don't want to test nodes whose predecessors are Bad or Unknown,
195      as we would have to special case that for each operation. */
196   if (opcode != iro_Phi && opcode != iro_Block)
197     for (i = 0; i < get_irn_arity(n); i++) {
198       opcode1 = get_irn_opcode(get_irn_n(n, i));
199       if (opcode1 == iro_Bad || opcode1 == iro_Unknown)
200         return 1;
201     }
202
203   mymode = get_irn_mode (n);
204   in = get_irn_in (n);
205
206   switch (opcode) {
207
208   case iro_Start:
209     ASSERT_AND_RET(
210             /* Start: BB --> X x M x P x data1 x ... x datan */
211             mymode == mode_T, "Start node", 0
212            );
213     break;
214   case iro_Jmp:
215     ASSERT_AND_RET(
216             /* Jmp: BB --> X */
217             mymode == mode_X, "Jmp node", 0
218            );
219     break;
220   case iro_Break:
221     ASSERT_AND_RET(
222             /* Jmp: BB --> X */
223             mymode == mode_X, "Jmp node", 0
224            );
225     break;
226   case iro_Cond:
227     op1mode = get_irn_mode(in[1]);
228     ASSERT_AND_RET(
229             /* Cond: BB x b --> X x X */
230             (op1mode == mode_b
231             /* Cond: BB x Iu --> X^n */
232             || op1mode == mode_Iu), "Cond node", 0
233            );
234     ASSERT_AND_RET(mymode == mode_T, "Cond mode is not a tuple", 0);
235     break;
236   case iro_Return:
237     op1mode = get_irn_mode(in[1]);
238     /* Return: BB x M x data1 x ... x datan --> X */
239     /* printf("mode: %s, code %s\n", ID_TO_STR(n->mode->name), ID_TO_STR(n->op->name));*/
240     ASSERT_AND_RET( op1mode == mode_M, "Return node", 0 );  /* operand M */
241     for (i=2; i < get_irn_arity(n); i++) {
242       ASSERT_AND_RET( mode_is_data(get_irn_mode(in[i])), "Return node", 0 );  /* operand datai */
243     };
244     ASSERT_AND_RET( mymode == mode_X, "Result X", 0 );   /* result X */
245     /* Compare returned results with result types of method type */
246     mt = get_entity_type(get_irg_ent(irg));
247     ASSERT_AND_RET( get_Return_n_ress(n) == get_method_n_ress(mt),
248       "Number of results for Return doesn't match number of results in type.", 0 );
249     for (i = 0; i < get_Return_n_ress(n); i++)
250       ASSERT_AND_RET(
251         get_irn_mode(get_Return_res(n, i)) == get_type_mode(get_method_res_type(mt, i)),
252         "Mode of result for Return doesn't match mode of result type.", 0);
253     break;
254   case iro_Raise:
255     op1mode = get_irn_mode(in[1]);
256     op2mode = get_irn_mode(in[2]);
257     ASSERT_AND_RET(
258             /* Sel: BB x M x P --> X x M */
259             op1mode == mode_M && op2mode == mode_P
260             && mymode == mode_T, "Raise node", 0
261            );
262     break;
263   case iro_Const:
264     ASSERT_AND_RET(
265             /* Const: BB --> data */
266             (mode_is_data (mymode) ||
267              mymode == mode_b)      /* we want boolean constants for static evaluation */
268             ,"Const node", 0        /* of Cmp. */
269            );
270     break;
271   case iro_SymConst:
272     ASSERT_AND_RET(
273             /* SymConst: BB --> Iu or
274                          BB --> P */
275             ((mymode == mode_Iu) || (mymode == mode_P)), "SymConst node", 0
276            );
277     break;
278   case iro_Sel:
279     op1mode = get_irn_mode(in[1]);
280     op2mode = get_irn_mode(in[2]);
281     ASSERT_AND_RET(
282             /* Sel: BB x M x P x Iu^n --> P */
283             op1mode == mode_M && op2mode == mode_P
284             && mymode == mode_P, "Sel node", 0
285            );
286     for (i=3; i < get_irn_arity(n); i++) {
287       ASSERT_AND_RET(get_irn_mode(in[i]) == mode_Iu, "Sel node", 0);
288     }
289     break;
290   case iro_InstOf:
291         ASSERT_AND_RET(mode_T == mymode, "mode of Instof is not a tuple", 0);
292         ASSERT_AND_RET(mode_is_data(op1mode), "Instof not on data", 0);
293         break;
294   case iro_Call:
295     op1mode = get_irn_mode(in[1]);
296     op2mode = get_irn_mode(in[2]);
297       /* Call: BB x M x P x data1 x ... x datan
298                  --> M x datan+1 x ... x data n+m */
299     ASSERT_AND_RET( op1mode == mode_M && op2mode == mode_P, "Call node", 0 );  /* operand M x P */
300     for (i=3; i < get_irn_arity(n); i++) {
301       ASSERT_AND_RET( mode_is_data(get_irn_mode(in[i])), "Call node", 0 );  /* operand datai */
302     };
303     ASSERT_AND_RET( mymode == mode_T, "Call result not a tuple", 0 );   /* result T */
304     /* Compare arguments of node with those of type */
305     mt = get_Call_type(n);
306
307     if (get_method_variadicity(mt) == variadic) {
308       ASSERT_AND_RET(
309         get_Call_n_params(n) >= get_method_n_params(mt),
310         "Number of args for Call doesn't match number of args in variadic type.",
311         0);
312       }
313     else {
314       ASSERT_AND_RET(
315         get_Call_n_params(n) == get_method_n_params(mt),
316         "Number of args for Call doesn't match number of args in non variadic type.",
317         0);
318       }
319
320     for (i = 0; i < get_method_n_params(mt); i++) {
321       ASSERT_AND_RET(
322         get_irn_mode(get_Call_param(n, i)) == get_type_mode(get_method_param_type(mt, i)),
323        "Mode of arg for Call doesn't match mode of arg type.", 0);
324     }
325     break;
326   case iro_Add:
327     op1mode = get_irn_mode(in[1]);
328     op2mode = get_irn_mode(in[2]);
329     ASSERT_AND_RET(
330             /* common Add: BB x num x num --> num */
331             ((mymode == op1mode && mymode == op2mode
332               && (mode_is_num(mymode) || mymode == mode_P))
333              ||  /* Pointer Add: BB x P x Is --> P */
334              (op1mode == mode_P && op2mode == mode_Is && mymode == mode_P)
335              ||  /* Pointer Add: BB x Is x P --> P */
336              (op1mode == mode_Is && op2mode == mode_P && mymode == mode_P)),
337             "Add node", 0
338            );
339       if (op1mode == mode_P || op2mode == mode_P) {
340         /* BB x P x Is --> P or BB x Is x P --> P */
341         op_is_symmetric = 0; /* ArmRoq */
342       } else {
343         /* BB x num x num --> num */
344         op_is_symmetric = 2;
345       }
346     break;
347   case iro_Sub:
348     op1mode = get_irn_mode(in[1]);
349     op2mode = get_irn_mode(in[2]);
350     ASSERT_AND_RET(
351             /* common Sub: BB x num x num --> num */
352             ((mymode ==op1mode && mymode == op2mode
353               && mode_is_num(op1mode))
354              ||  /* Pointer Sub: BB x P x Is --> P */
355              (op1mode == mode_P && op2mode == mode_Is && mymode == mode_P)
356              ||  /* Pointer Sub: BB x Is x P --> P */
357              (op1mode == mode_Is && op2mode == mode_P && mymode == mode_P)
358              ||  /* Pointer Sub: BB x P x P --> Is */
359              (op1mode == mode_P && op2mode == mode_P && mymode == mode_Is)),
360             "Sub node", 0
361            );
362       if (op1mode == mode_P && op2mode == mode_P) {
363         op_is_symmetric = 1; /* ArmRoq */
364       } else if (op1mode == mode_P || op2mode == mode_P) {
365         op_is_symmetric = 0; /* ArmRoq */
366       } else {
367         op_is_symmetric = 2;
368       }
369     break;
370   case iro_Minus:
371     op1mode = get_irn_mode(in[1]);
372     ASSERT_AND_RET(
373             /* Minus: BB x float --> float */
374             op1mode == mymode && mode_is_float(op1mode), "Minus node", 0
375            );
376     op_is_symmetric = 2;
377     break;
378   case iro_Mul:
379     op1mode = get_irn_mode(in[1]);
380     op2mode = get_irn_mode(in[2]);
381     ASSERT_AND_RET(
382             /* Mul: BB x num x num --> num */
383             mymode == op1mode && mymode == op2mode && mode_is_num(op1mode),
384             "Mul node", 0
385            );
386     op_is_symmetric = 2;
387     break;
388   case iro_Quot:
389     op1mode = get_irn_mode(in[1]);
390     op2mode = get_irn_mode(in[2]);
391     op3mode = get_irn_mode(in[3]);
392     ASSERT_AND_RET(
393             /* Quot: BB x M x float x float --> M x X x float */
394             op1mode == mode_M && op2mode == op3mode
395             && mode_is_float(op2mode) && mymode == mode_T,
396             "Quot node", 0
397            );
398     op_is_symmetric = 2;
399     break;
400   case iro_DivMod:;
401     op1mode = get_irn_mode(in[1]);
402     op2mode = get_irn_mode(in[2]);
403     op3mode = get_irn_mode(in[3]);
404     ASSERT_AND_RET(
405             /* DivMod: BB x M x num x num --> M x X x Is x Is */
406             op1mode == mode_M && op2mode == op3mode
407             && mode_is_num (op2mode) && mymode == mode_T,
408             "DivMod node", 0
409            );
410     op_is_symmetric = 1;
411     break;
412   case iro_Div:
413   case iro_Mod:
414     op1mode = get_irn_mode(in[1]);
415     op2mode = get_irn_mode(in[2]);
416     op3mode = get_irn_mode(in[3]);
417     ASSERT_AND_RET(
418             /* Div or Mod: BB x M x num x num --> M x X x Is */
419             op1mode == mode_M && op2mode == op3mode &&
420             mode_is_num (op2mode) && mymode == mode_T,
421             "Div or Mod node", 0
422            );
423     op_is_symmetric = 1;
424     break;
425   case iro_Abs:
426     op1mode = get_irn_mode(in[1]);
427     ASSERT_AND_RET(
428             /* Abs: BB x num --> num */
429             op1mode == mymode && mode_is_num (op1mode), "Abs node", 0
430            );
431     op_is_symmetric = 2;
432     break;
433   case iro_And:
434   case iro_Or:
435   case iro_Eor:
436     op1mode = get_irn_mode(in[1]);
437     op2mode = get_irn_mode(in[2]);
438     ASSERT_AND_RET(
439            /* And or Or or Eor: BB x int x int --> int */
440            mymode == op1mode && mymode == op2mode && mode_is_int(mymode),
441            "And, Or or Eor node", 0
442           );
443     op_is_symmetric = 2;
444     break;
445   case iro_Not:
446     op1mode = get_irn_mode(in[1]);
447     ASSERT_AND_RET(
448            /* Not: BB x int --> int */
449            mymode == op1mode && mode_is_int(mymode),
450            "Not node", 0
451           );
452     op_is_symmetric = 2;
453     break;
454
455   case iro_Cmp:
456     op1mode = get_irn_mode(in[1]);
457     op2mode = get_irn_mode(in[2]);
458     ASSERT_AND_RET(
459            /* Cmp: BB x datab x datab --> b16 */
460            op1mode == op2mode && mode_is_data(op1mode) && mymode == mode_T,
461            "Cmp node", 0
462           );
463     break;
464   case iro_Shl:
465   case iro_Shr:
466   case iro_Shrs:
467   case iro_Rot:
468     op1mode = get_irn_mode(in[1]);
469     op2mode = get_irn_mode(in[2]);
470     ASSERT_AND_RET(
471            /* Shl, Shr, Shrs or Rot: BB x int x Iu --> int */
472            mode_is_int(op1mode) && op2mode == mode_Iu && op1mode == mymode,
473            "Shl, Shr, Shr or Rot node", 0
474           );
475     break;
476   case iro_Conv:
477     op1mode = get_irn_mode(in[1]);
478     ASSERT_AND_RET(
479            /* Conv: BB x datab1 --> datab2 */
480            mode_is_datab(op1mode) && mode_is_data(mymode),
481            "Conv node", 0
482           );
483     break;
484   case iro_Phi:
485     /* Phi: BB x dataM^n --> dataM */
486     /* for some reason "<=" aborts. Is there a problem with get_store? */
487     for (i=1; i < get_irn_arity(n); i++) {
488       if (!is_Bad(in[i]) && (get_irn_op(in[i]) != op_Unknown))
489         ASSERT_AND_RET( get_irn_mode(in[i]) == mymode, "Phi node", 0);
490     };
491     ASSERT_AND_RET( mode_is_dataM(mymode), "Phi node", 0 );
492     break;
493   case iro_Load:
494     op1mode = get_irn_mode(in[1]);
495     op2mode = get_irn_mode(in[2]);
496     ASSERT_AND_RET(
497            /* Load: BB x M x P --> M x X x data */
498            op1mode == mode_M && op2mode == mode_P,
499            "Load node", 0
500           );
501     ASSERT_AND_RET( mymode == mode_T, "Load node", 0 );
502     break;
503   case iro_Store:
504     op1mode = get_irn_mode(in[1]);
505     op2mode = get_irn_mode(in[2]);
506     op3mode = get_irn_mode(in[3]);
507     ASSERT_AND_RET(
508            /* Load: BB x M x P x data --> M x X */
509            op1mode == mode_M && op2mode == mode_P && mode_is_data(op3mode),
510            "Store node", 0
511           );
512     ASSERT_AND_RET(mymode == mode_T, "Store node", 0);
513     break;
514   case iro_Alloc:
515     op1mode = get_irn_mode(in[1]);
516     op2mode = get_irn_mode(in[2]);
517     ASSERT_AND_RET(
518            /* Alloc: BB x M x Iu --> M x X x P */
519            op1mode == mode_M && op2mode == mode_Iu && mymode == mode_T,
520            "Alloc node", 0
521           );
522     break;
523   case iro_Free:
524     op1mode = get_irn_mode(in[1]);
525     op2mode = get_irn_mode(in[2]);
526     op3mode = get_irn_mode(in[3]);
527     ASSERT_AND_RET(
528            /* Free: BB x M x P x Iu --> M */
529            op1mode == mode_M && op2mode == mode_P && op3mode == mode_Iu && mymode == mode_M,
530            "Free node", 0
531           );
532     break;
533   case iro_Sync:
534            /* Sync: BB x M^n --> M */
535     for (i=1; i < get_irn_arity(n); i++) {
536       ASSERT_AND_RET( get_irn_mode(in[i]) == mode_M, "Sync node", 0 );
537     };
538     ASSERT_AND_RET( mymode == mode_M, "Sync node", 0 );
539     break;
540   case iro_Proj:
541     return vrfy_Proj_proj(n, irg);
542     break;
543   default: ;
544   }
545
546   /* All went ok */
547   return 1;
548 }
549
550 int irn_vrfy(ir_node *n)
551 {
552   return irn_vrfy_irg(n, current_ir_graph);
553 }
554
555 /*******************************************************************/
556 /* Verify the whole graph.                                         */
557 /*******************************************************************/
558
559 static void vrfy_wrap(ir_node *node, void *env)
560 {
561   int *res = env;
562
563   *res = irn_vrfy(node);
564 }
565
566 int irg_vrfy(ir_graph *irg)
567 {
568   int res = 1;
569   ir_graph *rem;
570
571   rem = current_ir_graph;
572   current_ir_graph = irg;
573
574   assert(get_irg_pinned(irg) == pinned);
575
576   irg_walk(irg->end, vrfy_wrap, NULL, &res);
577
578   current_ir_graph = rem;
579
580   return res;
581 }