OSDN Git Service

* configure.in: Add *-*-freebsd* configurations.
[pf3gnuchains/gcc-fork.git] / gcc / gensupport.c
1 /* Support routines for the various generation passes.
2    Copyright (C) 2000, 2001 Free Software Foundation, Inc.
3
4    This file is part of GCC.
5
6    GCC is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10
11    GCC is distributed in the hope that it will be useful, but WITHOUT
12    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14    License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with GCC; see the file COPYING.  If not, write to the Free
18    Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19    02111-1307, USA.  */
20
21 #include "hconfig.h"
22 #include "system.h"
23 #include "rtl.h"
24 #include "obstack.h"
25 #include "errors.h"
26 #include "gensupport.h"
27
28
29 /* In case some macros used by files we include need it, define this here.  */
30 int target_flags;
31
32 static struct obstack obstack;
33 struct obstack *rtl_obstack = &obstack;
34
35 #define obstack_chunk_alloc xmalloc
36 #define obstack_chunk_free free
37
38 static int sequence_num;
39 static int errors;
40
41 static int predicable_default;
42 static const char *predicable_true;
43 static const char *predicable_false;
44
45 static char *base_dir = NULL;
46
47 /* We initially queue all patterns, process the define_insn and
48    define_cond_exec patterns, then return them one at a time.  */
49
50 struct queue_elem
51 {
52   rtx data;
53   int lineno;
54   struct queue_elem *next;
55 };
56
57 static struct queue_elem *define_attr_queue;
58 static struct queue_elem **define_attr_tail = &define_attr_queue;
59 static struct queue_elem *define_insn_queue;
60 static struct queue_elem **define_insn_tail = &define_insn_queue;
61 static struct queue_elem *define_cond_exec_queue;
62 static struct queue_elem **define_cond_exec_tail = &define_cond_exec_queue;
63 static struct queue_elem *other_queue;
64 static struct queue_elem **other_tail = &other_queue;
65
66 static void queue_pattern PARAMS ((rtx, struct queue_elem ***, int));
67
68 /* Current maximum length of directory names in the search path
69    for include files.  (Altered as we get more of them.)  */
70
71 size_t max_include_len;
72
73 struct file_name_list
74   {
75     struct file_name_list *next;
76     const char *fname;
77   };
78
79 struct file_name_list *first_dir_md_include = 0;  /* First dir to search */
80         /* First dir to search for <file> */
81 struct file_name_list *first_bracket_include = 0;
82 struct file_name_list *last_dir_md_include = 0;        /* Last in chain */
83
84 static void remove_constraints PARAMS ((rtx));
85 static void process_rtx PARAMS ((rtx, int));
86
87 static int is_predicable PARAMS ((struct queue_elem *));
88 static void identify_predicable_attribute PARAMS ((void));
89 static int n_alternatives PARAMS ((const char *));
90 static void collect_insn_data PARAMS ((rtx, int *, int *));
91 static rtx alter_predicate_for_insn PARAMS ((rtx, int, int, int));
92 static const char *alter_test_for_insn PARAMS ((struct queue_elem *,
93                                                 struct queue_elem *));
94 static char *shift_output_template PARAMS ((char *, const char *, int));
95 static const char *alter_output_for_insn PARAMS ((struct queue_elem *,
96                                                   struct queue_elem *,
97                                                   int, int));
98 static void process_one_cond_exec PARAMS ((struct queue_elem *));
99 static void process_define_cond_exec PARAMS ((void));
100 static int process_include PARAMS ((rtx, int));
101 static char *save_string PARAMS ((const char *, int));
102 static int init_include_reader PARAMS ((FILE  *));
103 \f
104 void
105 message_with_line VPARAMS ((int lineno, const char *msg, ...))
106 {
107   VA_OPEN (ap, msg);
108   VA_FIXEDARG (ap, int, lineno);
109   VA_FIXEDARG (ap, const char *, msg);
110
111   fprintf (stderr, "%s:%d: ", read_rtx_filename, lineno);
112   vfprintf (stderr, msg, ap);
113   fputc ('\n', stderr);
114
115   VA_CLOSE (ap);
116 }
117
118 /* Make a version of gen_rtx_CONST_INT so that GEN_INT can be used in
119    the gensupport programs.  */
120
121 rtx
122 gen_rtx_CONST_INT (mode, arg)
123      enum machine_mode mode ATTRIBUTE_UNUSED;
124      HOST_WIDE_INT arg;
125 {
126   rtx rt = rtx_alloc (CONST_INT);
127
128   XWINT (rt, 0) = arg;
129   return rt;
130 }
131 \f
132 /* Queue PATTERN on LIST_TAIL.  */
133
134 static void
135 queue_pattern (pattern, list_tail, lineno)
136      rtx pattern;
137      struct queue_elem ***list_tail;
138      int lineno;
139 {
140   struct queue_elem *e = (struct queue_elem *) xmalloc (sizeof (*e));
141   e->data = pattern;
142   e->lineno = lineno;
143   e->next = NULL;
144   **list_tail = e;
145   *list_tail = &e->next;
146 }
147
148 /* Recursively remove constraints from an rtx.  */
149
150 static void
151 remove_constraints (part)
152      rtx part;
153 {
154   int i, j;
155   const char *format_ptr;
156
157   if (part == 0)
158     return;
159
160   if (GET_CODE (part) == MATCH_OPERAND)
161     XSTR (part, 2) = "";
162   else if (GET_CODE (part) == MATCH_SCRATCH)
163     XSTR (part, 1) = "";
164
165   format_ptr = GET_RTX_FORMAT (GET_CODE (part));
166
167   for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++)
168     switch (*format_ptr++)
169       {
170       case 'e':
171       case 'u':
172         remove_constraints (XEXP (part, i));
173         break;
174       case 'E':
175         if (XVEC (part, i) != NULL)
176           for (j = 0; j < XVECLEN (part, i); j++)
177             remove_constraints (XVECEXP (part, i, j));
178         break;
179       }
180 }
181
182 /* The entry point for initializing the reader.  */
183
184 static int
185 init_include_reader (inf)
186      FILE *inf;
187 {
188   int c;
189
190   errors = 0;
191
192   /* Read the entire file.  */
193   while (1)
194     {
195       rtx desc;
196       int lineno;
197
198       c = read_skip_spaces (inf);
199       if (c == EOF)
200         break;
201
202       ungetc (c, inf);
203       lineno = read_rtx_lineno;
204       desc = read_rtx (inf);
205       process_rtx (desc, lineno);
206     }
207   fclose (inf);
208
209   /* Process define_cond_exec patterns.  */
210   if (define_cond_exec_queue != NULL)
211     process_define_cond_exec ();
212
213   return errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
214 }
215
216 /* Process an include file assuming that it lives in gcc/config/{target}/ 
217    if the include looks line (include "file" )  */
218 static int
219 process_include (desc, lineno)
220      rtx desc;
221      int lineno;
222 {
223   const char *filename = XSTR (desc, 0);
224   char *pathname = NULL;
225   FILE *input_file;
226   char *fname = NULL;
227   struct file_name_list *stackp;
228   int flen;
229
230   stackp = first_dir_md_include;
231
232   /* If specified file name is absolute, just open it.  */
233   if (IS_ABSOLUTE_PATHNAME (filename) || !stackp)
234     {
235       if (base_dir)
236         {
237           pathname = xmalloc (strlen (base_dir) + strlen (filename) + 1);
238           pathname = strcpy (pathname, base_dir);
239           strcat (pathname, filename);
240           strcat (pathname, "\0");
241         }
242       else
243         {
244           pathname = xstrdup (filename);
245         }
246       read_rtx_filename = pathname;
247       input_file = fopen (pathname, "r");
248
249       if (input_file == 0)
250         {
251           perror (pathname);
252           return FATAL_EXIT_CODE;
253         }
254     }
255   else if (stackp)
256     {
257
258       flen = strlen (filename);
259
260       fname = (char *) xmalloc (max_include_len + flen + 2);
261
262       /* + 2 above for slash and terminating null.  */
263
264       /* Search directory path, trying to open the file.
265          Copy each filename tried into FNAME.  */
266
267       for (; stackp; stackp = stackp->next)
268         {
269           if (stackp->fname)
270             {
271               strcpy (fname, stackp->fname);
272               strcat (fname, "/");
273               fname[strlen (fname) + flen] = 0;
274             }
275           else
276             {
277               fname[0] = 0;
278             }
279           strncat (fname, (const char *) filename, flen);
280           read_rtx_filename = fname;
281           input_file = fopen (fname, "r");
282           if (input_file != NULL) 
283             break;
284         }
285       if (stackp == NULL)
286         {
287           if (strchr (fname, '/') == NULL || strchr (fname, '\\' ) || base_dir)
288             {
289               if (base_dir)
290                 {
291                   pathname =
292                     xmalloc (strlen (base_dir) + strlen (filename) + 1);
293                   pathname = strcpy (pathname, base_dir);
294                   strcat (pathname, filename);
295                   strcat (pathname, "\0");
296                 }
297               else
298                 pathname = xstrdup (filename);
299             }
300           read_rtx_filename = pathname;
301           input_file = fopen (pathname, "r");
302
303           if (input_file == 0)
304             {
305               perror (filename);
306               return FATAL_EXIT_CODE;
307             }
308         }
309
310     }
311
312   if (init_include_reader (input_file) == FATAL_EXIT_CODE)
313     message_with_line (lineno, "read errors found in include file  %s\n", pathname);
314
315   if (fname)
316     free (fname);
317   return SUCCESS_EXIT_CODE;
318 }
319
320 /* Process a top level rtx in some way, queueing as appropriate.  */
321
322 static void
323 process_rtx (desc, lineno)
324      rtx desc;
325      int lineno;
326 {
327   switch (GET_CODE (desc))
328     {
329     case DEFINE_INSN:
330       queue_pattern (desc, &define_insn_tail, lineno);
331       break;
332
333     case DEFINE_COND_EXEC:
334       queue_pattern (desc, &define_cond_exec_tail, lineno);
335       break;
336
337     case DEFINE_ATTR:
338       queue_pattern (desc, &define_attr_tail, lineno);
339       break;
340
341     case INCLUDE:
342       if (process_include (desc, lineno) == FATAL_EXIT_CODE)
343         {
344           const char *filename = XSTR (desc, 0);
345           message_with_line (lineno, "include file at  %s not found\n",
346                              filename);
347         }
348       break;
349
350     case DEFINE_INSN_AND_SPLIT:
351       {
352         const char *split_cond;
353         rtx split;
354         rtvec attr;
355         int i;
356
357         /* Create a split with values from the insn_and_split.  */
358         split = rtx_alloc (DEFINE_SPLIT);
359
360         i = XVECLEN (desc, 1);
361         XVEC (split, 0) = rtvec_alloc (i);
362         while (--i >= 0)
363           {
364             XVECEXP (split, 0, i) = copy_rtx (XVECEXP (desc, 1, i));
365             remove_constraints (XVECEXP (split, 0, i));
366           }
367
368         /* If the split condition starts with "&&", append it to the
369            insn condition to create the new split condition.  */
370         split_cond = XSTR (desc, 4);
371         if (split_cond[0] == '&' && split_cond[1] == '&')
372           {
373             const char *insn_cond = XSTR (desc, 2);
374             size_t insn_cond_len = strlen (insn_cond);
375             size_t split_cond_len = strlen (split_cond);
376             char *combined;
377
378             combined = (char *) xmalloc (insn_cond_len + split_cond_len + 1);
379             memcpy (combined, insn_cond, insn_cond_len);
380             memcpy (combined + insn_cond_len, split_cond, split_cond_len + 1);
381
382             split_cond = combined;
383           }
384         XSTR (split, 1) = split_cond;
385         XVEC (split, 2) = XVEC (desc, 5);
386         XSTR (split, 3) = XSTR (desc, 6);
387
388         /* Fix up the DEFINE_INSN.  */
389         attr = XVEC (desc, 7);
390         PUT_CODE (desc, DEFINE_INSN);
391         XVEC (desc, 4) = attr;
392
393         /* Queue them.  */
394         queue_pattern (desc, &define_insn_tail, lineno);
395         queue_pattern (split, &other_tail, lineno);
396         break;
397       }
398
399     default:
400       queue_pattern (desc, &other_tail, lineno);
401       break;
402     }
403 }
404 \f
405 /* Return true if attribute PREDICABLE is true for ELEM, which holds
406    a DEFINE_INSN.  */
407
408 static int
409 is_predicable (elem)
410      struct queue_elem *elem;
411 {
412   rtvec vec = XVEC (elem->data, 4);
413   const char *value;
414   int i;
415
416   if (! vec)
417     return predicable_default;
418
419   for (i = GET_NUM_ELEM (vec) - 1; i >= 0; --i)
420     {
421       rtx sub = RTVEC_ELT (vec, i);
422       switch (GET_CODE (sub))
423         {
424         case SET_ATTR:
425           if (strcmp (XSTR (sub, 0), "predicable") == 0)
426             {
427               value = XSTR (sub, 1);
428               goto found;
429             }
430           break;
431
432         case SET_ATTR_ALTERNATIVE:
433           if (strcmp (XSTR (sub, 0), "predicable") == 0)
434             {
435               message_with_line (elem->lineno,
436                                  "multiple alternatives for `predicable'");
437               errors = 1;
438               return 0;
439             }
440           break;
441
442         case SET:
443           if (GET_CODE (SET_DEST (sub)) != ATTR
444               || strcmp (XSTR (SET_DEST (sub), 0), "predicable") != 0)
445             break;
446           sub = SET_SRC (sub);
447           if (GET_CODE (sub) == CONST_STRING)
448             {
449               value = XSTR (sub, 0);
450               goto found;
451             }
452
453           /* ??? It would be possible to handle this if we really tried.
454              It's not easy though, and I'm not going to bother until it
455              really proves necessary.  */
456           message_with_line (elem->lineno,
457                              "non-constant value for `predicable'");
458           errors = 1;
459           return 0;
460
461         default:
462           abort ();
463         }
464     }
465
466   return predicable_default;
467
468  found:
469   /* Verify that predicability does not vary on the alternative.  */
470   /* ??? It should be possible to handle this by simply eliminating
471      the non-predicable alternatives from the insn.  FRV would like
472      to do this.  Delay this until we've got the basics solid.  */
473   if (strchr (value, ',') != NULL)
474     {
475       message_with_line (elem->lineno,
476                          "multiple alternatives for `predicable'");
477       errors = 1;
478       return 0;
479     }
480
481   /* Find out which value we're looking at.  */
482   if (strcmp (value, predicable_true) == 0)
483     return 1;
484   if (strcmp (value, predicable_false) == 0)
485     return 0;
486
487   message_with_line (elem->lineno,
488                      "unknown value `%s' for `predicable' attribute",
489                      value);
490   errors = 1;
491   return 0;
492 }
493
494 /* Examine the attribute "predicable"; discover its boolean values
495    and its default.  */
496
497 static void
498 identify_predicable_attribute ()
499 {
500   struct queue_elem *elem;
501   char *p_true, *p_false;
502   const char *value;
503   size_t len;
504
505   /* Look for the DEFINE_ATTR for `predicable', which must exist.  */
506   for (elem = define_attr_queue; elem ; elem = elem->next)
507     if (strcmp (XSTR (elem->data, 0), "predicable") == 0)
508       goto found;
509
510   message_with_line (define_cond_exec_queue->lineno,
511                      "attribute `predicable' not defined");
512   errors = 1;
513   return;
514
515  found:
516   value = XSTR (elem->data, 1);
517   len = strlen (value);
518   p_false = (char *) xmalloc (len + 1);
519   memcpy (p_false, value, len + 1);
520
521   p_true = strchr (p_false, ',');
522   if (p_true == NULL || strchr (++p_true, ',') != NULL)
523     {
524       message_with_line (elem->lineno,
525                          "attribute `predicable' is not a boolean");
526       errors = 1;
527       return;
528     }
529   p_true[-1] = '\0';
530
531   predicable_true = p_true;
532   predicable_false = p_false;
533
534   switch (GET_CODE (XEXP (elem->data, 2)))
535     {
536     case CONST_STRING:
537       value = XSTR (XEXP (elem->data, 2), 0);
538       break;
539
540     case CONST:
541       message_with_line (elem->lineno,
542                          "attribute `predicable' cannot be const");
543       errors = 1;
544       return;
545
546     default:
547       message_with_line (elem->lineno,
548                          "attribute `predicable' must have a constant default");
549       errors = 1;
550       return;
551     }
552
553   if (strcmp (value, p_true) == 0)
554     predicable_default = 1;
555   else if (strcmp (value, p_false) == 0)
556     predicable_default = 0;
557   else
558     {
559       message_with_line (elem->lineno,
560                          "unknown value `%s' for `predicable' attribute",
561                          value);
562       errors = 1;
563     }
564 }
565
566 /* Return the number of alternatives in constraint S.  */
567
568 static int
569 n_alternatives (s)
570      const char *s;
571 {
572   int n = 1;
573
574   if (s)
575     while (*s)
576       n += (*s++ == ',');
577
578   return n;
579 }
580
581 /* Determine how many alternatives there are in INSN, and how many
582    operands.  */
583
584 static void
585 collect_insn_data (pattern, palt, pmax)
586      rtx pattern;
587      int *palt, *pmax;
588 {
589   const char *fmt;
590   enum rtx_code code;
591   int i, j, len;
592
593   code = GET_CODE (pattern);
594   switch (code)
595     {
596     case MATCH_OPERAND:
597       i = n_alternatives (XSTR (pattern, 2));
598       *palt = (i > *palt ? i : *palt);
599       /* FALLTHRU */
600
601     case MATCH_OPERATOR:
602     case MATCH_SCRATCH:
603     case MATCH_PARALLEL:
604     case MATCH_INSN:
605       i = XINT (pattern, 0);
606       if (i > *pmax)
607         *pmax = i;
608       break;
609
610     default:
611       break;
612     }
613
614   fmt = GET_RTX_FORMAT (code);
615   len = GET_RTX_LENGTH (code);
616   for (i = 0; i < len; i++)
617     {
618       switch (fmt[i])
619         {
620         case 'e': case 'u':
621           collect_insn_data (XEXP (pattern, i), palt, pmax);
622           break;
623
624         case 'V':
625           if (XVEC (pattern, i) == NULL)
626             break;
627           /* FALLTHRU */
628         case 'E':
629           for (j = XVECLEN (pattern, i) - 1; j >= 0; --j)
630             collect_insn_data (XVECEXP (pattern, i, j), palt, pmax);
631           break;
632
633         case 'i': case 'w': case '0': case 's': case 'S': case 'T':
634           break;
635
636         default:
637           abort ();
638         }
639     }
640 }
641
642 static rtx
643 alter_predicate_for_insn (pattern, alt, max_op, lineno)
644      rtx pattern;
645      int alt, max_op, lineno;
646 {
647   const char *fmt;
648   enum rtx_code code;
649   int i, j, len;
650
651   code = GET_CODE (pattern);
652   switch (code)
653     {
654     case MATCH_OPERAND:
655       {
656         const char *c = XSTR (pattern, 2);
657
658         if (n_alternatives (c) != 1)
659           {
660             message_with_line (lineno,
661                                "too many alternatives for operand %d",
662                                XINT (pattern, 0));
663             errors = 1;
664             return NULL;
665           }
666
667         /* Replicate C as needed to fill out ALT alternatives.  */
668         if (c && *c && alt > 1)
669           {
670             size_t c_len = strlen (c);
671             size_t len = alt * (c_len + 1);
672             char *new_c = (char *) xmalloc (len);
673
674             memcpy (new_c, c, c_len);
675             for (i = 1; i < alt; ++i)
676               {
677                 new_c[i * (c_len + 1) - 1] = ',';
678                 memcpy (&new_c[i * (c_len + 1)], c, c_len);
679               }
680             new_c[len - 1] = '\0';
681             XSTR (pattern, 2) = new_c;
682           }
683       }
684       /* FALLTHRU */
685
686     case MATCH_OPERATOR:
687     case MATCH_SCRATCH:
688     case MATCH_PARALLEL:
689     case MATCH_INSN:
690       XINT (pattern, 0) += max_op;
691       break;
692
693     default:
694       break;
695     }
696
697   fmt = GET_RTX_FORMAT (code);
698   len = GET_RTX_LENGTH (code);
699   for (i = 0; i < len; i++)
700     {
701       rtx r;
702
703       switch (fmt[i])
704         {
705         case 'e': case 'u':
706           r = alter_predicate_for_insn (XEXP (pattern, i), alt,
707                                         max_op, lineno);
708           if (r == NULL)
709             return r;
710           break;
711
712         case 'E':
713           for (j = XVECLEN (pattern, i) - 1; j >= 0; --j)
714             {
715               r = alter_predicate_for_insn (XVECEXP (pattern, i, j),
716                                             alt, max_op, lineno);
717               if (r == NULL)
718                 return r;
719             }
720           break;
721
722         case 'i': case 'w': case '0': case 's':
723           break;
724
725         default:
726           abort ();
727         }
728     }
729
730   return pattern;
731 }
732
733 static const char *
734 alter_test_for_insn (ce_elem, insn_elem)
735      struct queue_elem *ce_elem, *insn_elem;
736 {
737   const char *ce_test, *insn_test;
738   char *new_test;
739   size_t len, ce_len, insn_len;
740
741   ce_test = XSTR (ce_elem->data, 1);
742   insn_test = XSTR (insn_elem->data, 2);
743   if (!ce_test || *ce_test == '\0')
744     return insn_test;
745   if (!insn_test || *insn_test == '\0')
746     return ce_test;
747
748   ce_len = strlen (ce_test);
749   insn_len = strlen (insn_test);
750   len = 1 + ce_len + 1 + 4 + 1 + insn_len + 1 + 1;
751   new_test = (char *) xmalloc (len);
752
753   sprintf (new_test, "(%s) && (%s)", ce_test, insn_test);
754
755   return new_test;
756 }
757
758 /* Adjust all of the operand numbers in OLD to match the shift they'll
759    get from an operand displacement of DISP.  Return a pointer after the
760    adjusted string.  */
761
762 static char *
763 shift_output_template (new, old, disp)
764      char *new;
765      const char *old;
766      int disp;
767 {
768   while (*old)
769     {
770       char c = *old++;
771       *new++ = c;
772       if (c == '%')
773         {
774           c = *old++;
775           if (ISDIGIT ((unsigned char) c))
776             c += disp;
777           else if (ISALPHA (c))
778             {
779               *new++ = c;
780               c = *old++ + disp;
781             }
782           *new++ = c;
783         }
784     }
785
786   return new;
787 }
788
789 static const char *
790 alter_output_for_insn (ce_elem, insn_elem, alt, max_op)
791      struct queue_elem *ce_elem, *insn_elem;
792      int alt, max_op;
793 {
794   const char *ce_out, *insn_out;
795   char *new, *p;
796   size_t len, ce_len, insn_len;
797
798   /* ??? Could coordinate with genoutput to not duplicate code here.  */
799
800   ce_out = XSTR (ce_elem->data, 2);
801   insn_out = XTMPL (insn_elem->data, 3);
802   if (!ce_out || *ce_out == '\0')
803     return insn_out;
804
805   ce_len = strlen (ce_out);
806   insn_len = strlen (insn_out);
807
808   if (*insn_out == '*')
809     /* You must take care of the predicate yourself.  */
810     return insn_out;
811
812   if (*insn_out == '@')
813     {
814       len = (ce_len + 1) * alt + insn_len + 1;
815       p = new = xmalloc (len);
816
817       do
818         {
819           do
820             *p++ = *insn_out++;
821           while (ISSPACE ((unsigned char) *insn_out));
822
823           if (*insn_out != '#')
824             {
825               p = shift_output_template (p, ce_out, max_op);
826               *p++ = ' ';
827             }
828
829           do
830             *p++ = *insn_out++;
831           while (*insn_out && *insn_out != '\n');
832         }
833       while (*insn_out);
834       *p = '\0';
835     }
836   else
837     {
838       len = ce_len + 1 + insn_len + 1;
839       new = xmalloc (len);
840
841       p = shift_output_template (new, ce_out, max_op);
842       *p++ = ' ';
843       memcpy (p, insn_out, insn_len + 1);
844     }
845
846   return new;
847 }
848
849 /* Replicate insns as appropriate for the given DEFINE_COND_EXEC.  */
850
851 static void
852 process_one_cond_exec (ce_elem)
853      struct queue_elem *ce_elem;
854 {
855   struct queue_elem *insn_elem;
856   for (insn_elem = define_insn_queue; insn_elem ; insn_elem = insn_elem->next)
857     {
858       int alternatives, max_operand;
859       rtx pred, insn, pattern;
860
861       if (! is_predicable (insn_elem))
862         continue;
863
864       alternatives = 1;
865       max_operand = -1;
866       collect_insn_data (insn_elem->data, &alternatives, &max_operand);
867       max_operand += 1;
868
869       if (XVECLEN (ce_elem->data, 0) != 1)
870         {
871           message_with_line (ce_elem->lineno,
872                              "too many patterns in predicate");
873           errors = 1;
874           return;
875         }
876
877       pred = copy_rtx (XVECEXP (ce_elem->data, 0, 0));
878       pred = alter_predicate_for_insn (pred, alternatives, max_operand,
879                                        ce_elem->lineno);
880       if (pred == NULL)
881         return;
882
883       /* Construct a new pattern for the new insn.  */
884       insn = copy_rtx (insn_elem->data);
885       XSTR (insn, 0) = "";
886       pattern = rtx_alloc (COND_EXEC);
887       XEXP (pattern, 0) = pred;
888       if (XVECLEN (insn, 1) == 1)
889         {
890           XEXP (pattern, 1) = XVECEXP (insn, 1, 0);
891           XVECEXP (insn, 1, 0) = pattern;
892           PUT_NUM_ELEM (XVEC (insn, 1), 1);
893         }
894       else
895         {
896           XEXP (pattern, 1) = rtx_alloc (PARALLEL);
897           XVEC (XEXP (pattern, 1), 0) = XVEC (insn, 1);
898           XVEC (insn, 1) = rtvec_alloc (1);
899           XVECEXP (insn, 1, 0) = pattern;
900         }
901
902       XSTR (insn, 2) = alter_test_for_insn (ce_elem, insn_elem);
903       XTMPL (insn, 3) = alter_output_for_insn (ce_elem, insn_elem,
904                                               alternatives, max_operand);
905
906       /* ??? Set `predicable' to false.  Not crucial since it's really
907          only used here, and we won't reprocess this new pattern.  */
908
909       /* Put the new pattern on the `other' list so that it
910          (a) is not reprocessed by other define_cond_exec patterns
911          (b) appears after all normal define_insn patterns.
912
913          ??? B is debatable.  If one has normal insns that match
914          cond_exec patterns, they will be preferred over these
915          generated patterns.  Whether this matters in practice, or if
916          it's a good thing, or whether we should thread these new
917          patterns into the define_insn chain just after their generator
918          is something we'll have to experiment with.  */
919
920       queue_pattern (insn, &other_tail, insn_elem->lineno);
921     }
922 }
923
924 /* If we have any DEFINE_COND_EXEC patterns, expand the DEFINE_INSN
925    patterns appropriately.  */
926
927 static void
928 process_define_cond_exec ()
929 {
930   struct queue_elem *elem;
931
932   identify_predicable_attribute ();
933   if (errors)
934     return;
935
936   for (elem = define_cond_exec_queue; elem ; elem = elem->next)
937     process_one_cond_exec (elem);
938 }
939
940 static char *
941 save_string (s, len)
942      const char *s;
943      int len;
944 {
945   register char *result = xmalloc (len + 1);
946
947   memcpy (result, s, len);
948   result[len] = 0;
949   return result;
950 }
951
952 \f
953 /* The entry point for initializing the reader.  */
954
955 int
956 init_md_reader_args (argc, argv)
957      int argc;
958      char **argv;
959 {
960   int i;
961   const char *in_fname;
962
963   max_include_len = 0;
964   in_fname = NULL;
965   for (i = 1; i < argc; i++)
966     {
967       if (argv[i][0] != '-')
968         {
969           if (in_fname == NULL)
970             in_fname = argv[i];
971         }
972       else
973         {
974           int c = argv[i][1];
975           switch (c)
976             {
977             case 'I':           /* Add directory to path for includes.  */
978               {
979                 struct file_name_list *dirtmp;
980
981                 dirtmp = (struct file_name_list *)
982                   xmalloc (sizeof (struct file_name_list));
983                 dirtmp->next = 0;       /* New one goes on the end */
984                 if (first_dir_md_include == 0)
985                   first_dir_md_include = dirtmp;
986                 else
987                   last_dir_md_include->next = dirtmp;
988                 last_dir_md_include = dirtmp;   /* Tail follows the last one */
989                 if (argv[i][1] == 'I' && argv[i][2] != 0)
990                   dirtmp->fname = argv[i] + 2;
991                 else if (i + 1 == argc)
992                   fatal ("directory name missing after -I option");
993                 else
994                   dirtmp->fname = argv[++i];
995                 if (strlen (dirtmp->fname) > max_include_len)
996                   max_include_len = strlen (dirtmp->fname);
997               }
998               break;
999             default:
1000               fatal ("invalid option `%s'", argv[i]);
1001
1002             }
1003         }
1004     }
1005     return init_md_reader (in_fname);
1006 }
1007 \f
1008 /* The entry point for initializing the reader.  */
1009
1010 int
1011 init_md_reader (filename)
1012      const char *filename;
1013 {
1014   FILE *input_file;
1015   int c;
1016   char *lastsl;
1017
1018   lastsl = strrchr (filename, '/');
1019   if (lastsl != NULL) 
1020     base_dir = save_string (filename, lastsl - filename + 1 );
1021
1022   read_rtx_filename = filename;
1023   input_file = fopen (filename, "r");
1024   if (input_file == 0)
1025     {
1026       perror (filename);
1027       return FATAL_EXIT_CODE;
1028     }
1029
1030   obstack_init (rtl_obstack);
1031   errors = 0;
1032   sequence_num = 0;
1033
1034   /* Read the entire file.  */
1035   while (1)
1036     {
1037       rtx desc;
1038       int lineno;
1039
1040       c = read_skip_spaces (input_file);
1041       if (c == EOF)
1042         break;
1043
1044       ungetc (c, input_file);
1045       lineno = read_rtx_lineno;
1046       desc = read_rtx (input_file);
1047       process_rtx (desc, lineno);
1048     }
1049   fclose (input_file);
1050
1051   /* Process define_cond_exec patterns.  */
1052   if (define_cond_exec_queue != NULL)
1053     process_define_cond_exec ();
1054
1055   return errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
1056 }
1057
1058 /* The entry point for reading a single rtx from an md file.  */
1059
1060 rtx
1061 read_md_rtx (lineno, seqnr)
1062      int *lineno;
1063      int *seqnr;
1064 {
1065   struct queue_elem **queue, *elem;
1066   rtx desc;
1067
1068   /* Read all patterns from a given queue before moving on to the next.  */
1069   if (define_attr_queue != NULL)
1070     queue = &define_attr_queue;
1071   else if (define_insn_queue != NULL)
1072     queue = &define_insn_queue;
1073   else if (other_queue != NULL)
1074     queue = &other_queue;
1075   else
1076     return NULL_RTX;
1077
1078   elem = *queue;
1079   *queue = elem->next;
1080   desc = elem->data;
1081   *lineno = elem->lineno;
1082   *seqnr = sequence_num;
1083
1084   free (elem);
1085
1086   switch (GET_CODE (desc))
1087     {
1088     case DEFINE_INSN:
1089     case DEFINE_EXPAND:
1090     case DEFINE_SPLIT:
1091     case DEFINE_PEEPHOLE:
1092     case DEFINE_PEEPHOLE2:
1093       sequence_num++;
1094       break;
1095
1096     default:
1097       break;
1098     }
1099
1100   return desc;
1101 }