]>
git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/genextract.c
1 /* Generate code from machine description to extract operands from insn as rtl.
2 Copyright (C) 1987, 1991, 1992, 1993, 1997, 1998, 1999, 2000, 2003,
4 Free Software Foundation, Inc.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING. If not, write to the Free
20 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
26 #include "coretypes.h"
30 #include "gensupport.h"
33 /* This structure contains all the information needed to describe one
34 set of extractions methods. Each method may be used by more than
35 one pattern if the operands are in the same place.
37 The string for each operand describes that path to the operand and
38 contains `0' through `9' when going into an expression and `a' through
39 `z' when going into a vector. We assume here that only the first operand
40 of an rtl expression is a vector. genrecog.c makes the same assumption
41 (and uses the same representation) and it is currently true. */
47 unsigned int op_count
;
48 unsigned int dup_count
;
52 struct code_ptr
*insns
;
53 struct extraction
*next
;
56 /* Holds a single insn code that uses an extraction method. */
60 struct code_ptr
*next
;
63 /* All extractions needed for this machine description. */
64 static struct extraction
*extractions
;
66 /* All insn codes for old-style peepholes. */
67 static struct code_ptr
*peepholes
;
69 /* This structure is used by gen_insn and walk_rtx to accumulate the
70 data that will be used to produce an extractions structure. */
75 DEF_VEC_ALLOC_I(int,heap
);
76 DEF_VEC_ALLOC_I(char,heap
);
77 DEF_VEC_ALLOC_P(locstr
,heap
);
81 VEC(locstr
,heap
) *oplocs
;
82 VEC(locstr
,heap
) *duplocs
;
83 VEC(int,heap
) *dupnums
;
84 VEC(char,heap
) *pathstr
;
87 /* Forward declarations. */
88 static void walk_rtx (rtx
, struct accum_extract
*);
89 static void record_insn_name (int, const char *);
92 gen_insn (rtx insn
, int insn_code_number
)
95 unsigned int op_count
, dup_count
, j
;
97 struct code_ptr
*link
;
98 struct accum_extract acc
;
100 acc
.oplocs
= VEC_alloc (locstr
,heap
, 10);
101 acc
.duplocs
= VEC_alloc (locstr
,heap
, 10);
102 acc
.dupnums
= VEC_alloc (int,heap
, 10);
103 acc
.pathstr
= VEC_alloc (char,heap
, 20);
105 /* Walk the insn's pattern, remembering at all times the path
106 down to the walking point. */
108 if (XVECLEN (insn
, 1) == 1)
109 walk_rtx (XVECEXP (insn
, 1, 0), &acc
);
111 for (i
= XVECLEN (insn
, 1) - 1; i
>= 0; i
--)
113 VEC_safe_push (char,heap
, acc
.pathstr
, 'a' + i
);
114 walk_rtx (XVECEXP (insn
, 1, i
), &acc
);
115 VEC_pop (char, acc
.pathstr
);
118 link
= XNEW (struct code_ptr
);
119 link
->insn_code
= insn_code_number
;
121 /* See if we find something that already had this extraction method. */
123 op_count
= VEC_length (locstr
, acc
.oplocs
);
124 dup_count
= VEC_length (locstr
, acc
.duplocs
);
125 gcc_assert (dup_count
== VEC_length (int, acc
.dupnums
));
127 for (p
= extractions
; p
; p
= p
->next
)
129 if (p
->op_count
!= op_count
|| p
->dup_count
!= dup_count
)
132 for (j
= 0; j
< op_count
; j
++)
134 char *a
= p
->oplocs
[j
];
135 char *b
= VEC_index (locstr
, acc
.oplocs
, j
);
136 if (a
!= b
&& (!a
|| !b
|| strcmp (a
, b
)))
143 for (j
= 0; j
< dup_count
; j
++)
144 if (p
->dupnums
[j
] != VEC_index (int, acc
.dupnums
, j
)
145 || strcmp (p
->duplocs
[j
], VEC_index (locstr
, acc
.duplocs
, j
)))
151 /* This extraction is the same as ours. Just link us in. */
152 link
->next
= p
->insns
;
157 /* Otherwise, make a new extraction method. We stash the arrays
158 after the extraction structure in memory. */
160 p
= xmalloc (sizeof (struct extraction
)
161 + op_count
*sizeof (char *)
162 + dup_count
*sizeof (char *)
163 + dup_count
*sizeof (int));
164 p
->op_count
= op_count
;
165 p
->dup_count
= dup_count
;
166 p
->next
= extractions
;
171 p
->oplocs
= (char **)((char *)p
+ sizeof (struct extraction
));
172 p
->duplocs
= p
->oplocs
+ op_count
;
173 p
->dupnums
= (int *)(p
->duplocs
+ dup_count
);
175 memcpy(p
->oplocs
, VEC_address(locstr
,acc
.oplocs
), op_count
*sizeof(locstr
));
176 memcpy(p
->duplocs
, VEC_address(locstr
,acc
.duplocs
), dup_count
*sizeof(locstr
));
177 memcpy(p
->dupnums
, VEC_address(int, acc
.dupnums
), dup_count
*sizeof(int));
180 VEC_free (locstr
,heap
, acc
.oplocs
);
181 VEC_free (locstr
,heap
, acc
.duplocs
);
182 VEC_free (int,heap
, acc
.dupnums
);
183 VEC_free (char,heap
, acc
.pathstr
);
186 /* Helper subroutine of walk_rtx: given a VEC(locstr), an index, and a
187 string, insert the string at the index, which should either already
188 exist and be NULL, or not yet exist within the vector. In the latter
189 case the vector is enlarged as appropriate. */
191 VEC_safe_set_locstr (VEC(locstr
,heap
) *v
, unsigned int ix
, char *str
)
193 if (ix
< VEC_length (locstr
, v
))
195 gcc_assert (VEC_index (locstr
, v
, ix
) == 0);
196 VEC_replace (locstr
, v
, ix
, str
);
200 while (ix
> VEC_length (locstr
, v
))
201 VEC_safe_push (locstr
,heap
, v
, 0);
202 VEC_safe_push (locstr
,heap
, v
, str
);
206 /* Another helper subroutine of walk_rtx: given a VEC(char), convert it
207 to a NUL-terminated string in malloc memory. */
209 VEC_char_to_string (VEC(char,heap
) *v
)
211 size_t n
= VEC_length (char, v
);
212 char *s
= xmalloc (n
+ 1);
213 memcpy (s
, VEC_address (char, v
), n
);
219 walk_rtx (rtx x
, struct accum_extract
*acc
)
239 VEC_safe_set_locstr (acc
->oplocs
, XINT (x
, 0),
240 VEC_char_to_string (acc
->pathstr
));
245 VEC_safe_set_locstr (acc
->oplocs
, XINT (x
, 0),
246 VEC_char_to_string (acc
->pathstr
));
248 base
= (code
== MATCH_OPERATOR
? '0' : 'a');
249 for (i
= XVECLEN (x
, 2) - 1; i
>= 0; i
--)
251 VEC_safe_push (char,heap
, acc
->pathstr
, base
+ i
);
252 walk_rtx (XVECEXP (x
, 2, i
), acc
);
253 VEC_pop (char, acc
->pathstr
);
260 VEC_safe_push (locstr
,heap
, acc
->duplocs
,
261 VEC_char_to_string (acc
->pathstr
));
262 VEC_safe_push (int,heap
, acc
->dupnums
, XINT (x
, 0));
264 if (code
== MATCH_DUP
)
267 base
= (code
== MATCH_OP_DUP
? '0' : 'a');
268 for (i
= XVECLEN (x
, 1) - 1; i
>= 0; i
--)
270 VEC_safe_push (char,heap
, acc
->pathstr
, base
+ i
);
271 walk_rtx (XVECEXP (x
, 1, i
), acc
);
272 VEC_pop (char, acc
->pathstr
);
280 fmt
= GET_RTX_FORMAT (code
);
281 len
= GET_RTX_LENGTH (code
);
282 for (i
= 0; i
< len
; i
++)
284 if (fmt
[i
] == 'e' || fmt
[i
] == 'u')
286 VEC_safe_push (char,heap
, acc
->pathstr
, '0' + i
);
287 walk_rtx (XEXP (x
, i
), acc
);
288 VEC_pop (char, acc
->pathstr
);
290 else if (fmt
[i
] == 'E')
293 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
295 VEC_safe_push (char,heap
, acc
->pathstr
, 'a' + j
);
296 walk_rtx (XVECEXP (x
, i
, j
), acc
);
297 VEC_pop (char, acc
->pathstr
);
303 /* Given a PATH, representing a path down the instruction's
304 pattern from the root to a certain point, output code to
305 evaluate to the rtx at that point. */
308 print_path (const char *path
)
310 int len
= strlen (path
);
315 /* Don't emit "pat", since we may try to take the address of it,
316 which isn't what is intended. */
317 fputs ("PATTERN (insn)", stdout
);
321 /* We first write out the operations (XEXP or XVECEXP) in reverse
322 order, then write "pat", then the indices in forward order. */
324 for (i
= len
- 1; i
>= 0 ; i
--)
326 if (ISLOWER (path
[i
]))
327 fputs ("XVECEXP (", stdout
);
328 else if (ISDIGIT (path
[i
]))
329 fputs ("XEXP (", stdout
);
334 fputs ("pat", stdout
);
336 for (i
= 0; i
< len
; i
++)
338 if (ISLOWER (path
[i
]))
339 printf (", 0, %d)", path
[i
] - 'a');
340 else if (ISDIGIT(path
[i
]))
341 printf (", %d)", path
[i
] - '0');
350 /* N.B. Code below avoids putting squiggle braces in column 1 inside
351 a string, because this confuses some editors' syntax highlighting
355 /* Generated automatically by the program `genextract'\n\
356 from the machine description file `md'. */\n\
358 #include \"config.h\"\n\
359 #include \"system.h\"\n\
360 #include \"coretypes.h\"\n\
362 #include \"rtl.h\"\n\
363 #include \"insn-config.h\"\n\
364 #include \"recog.h\"\n\
365 #include \"toplev.h\"\n\
367 /* This variable is used as the \"location\" of any missing operand\n\
368 whose numbers are skipped by a given pattern. */\n\
369 static rtx junk ATTRIBUTE_UNUSED;\n");
373 insn_extract (rtx insn)\n{\n\
374 rtx *ro = recog_data.operand;\n\
375 rtx **ro_loc = recog_data.operand_loc;\n\
376 rtx pat = PATTERN (insn);\n\
377 int i ATTRIBUTE_UNUSED; /* only for peepholes */\n\
379 #ifdef ENABLE_CHECKING\n\
380 memset (ro, 0xab, sizeof (*ro) * MAX_RECOG_OPERANDS);\n\
381 memset (ro_loc, 0xab, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n\
385 switch (INSN_CODE (insn))\n\
388 /* Control reaches here if insn_extract has been called with an\n\
389 unrecognizable insn (code -1), or an insn whose INSN_CODE\n\
390 corresponds to a DEFINE_EXPAND in the machine description;\n\
391 either way, a bug. */\n\
392 if (INSN_CODE (insn) < 0)\n\
393 fatal_insn (\"unrecognizable insn:\", insn);\n\
395 fatal_insn (\"insn with invalid code number:\", insn);\n");
399 main (int argc
, char **argv
)
403 struct extraction
*p
;
404 struct code_ptr
*link
;
406 int insn_code_number
;
409 progname
= "genextract";
411 if (init_md_reader_args (argc
, argv
) != SUCCESS_EXIT_CODE
)
412 return (FATAL_EXIT_CODE
);
414 /* Read the machine description. */
416 while ((desc
= read_md_rtx (&line_no
, &insn_code_number
)) != NULL
)
418 if (GET_CODE (desc
) == DEFINE_INSN
)
420 record_insn_name (insn_code_number
, XSTR (desc
, 0));
421 gen_insn (desc
, insn_code_number
);
424 else if (GET_CODE (desc
) == DEFINE_PEEPHOLE
)
426 struct code_ptr
*link
= xmalloc (sizeof (struct code_ptr
));
428 link
->insn_code
= insn_code_number
;
429 link
->next
= peepholes
;
436 /* Write out code to handle peepholes and the insn_codes that it should
440 for (link
= peepholes
; link
; link
= link
->next
)
441 printf (" case %d:\n", link
->insn_code
);
443 /* The vector in the insn says how many operands it has.
444 And all it contains are operands. In fact, the vector was
445 created just for the sake of this function. We need to set the
446 location of the operands for sake of simplifications after
447 extraction, like eliminating subregs. */
448 puts (" for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n"
449 " ro[i] = *(ro_loc[i] = &XVECEXP (pat, 0, i));\n"
453 /* Write out all the ways to extract insn operands. */
454 for (p
= extractions
; p
; p
= p
->next
)
456 for (link
= p
->insns
; link
; link
= link
->next
)
459 name
= get_insn_name (i
);
461 printf (" case %d: /* %s */\n", i
, name
);
463 printf (" case %d:\n", i
);
466 for (i
= 0; i
< p
->op_count
; i
++)
468 if (p
->oplocs
[i
] == 0)
470 printf (" ro[%d] = const0_rtx;\n", i
);
471 printf (" ro_loc[%d] = &junk;\n", i
);
475 printf (" ro[%d] = *(ro_loc[%d] = &", i
, i
);
476 print_path (p
->oplocs
[i
]);
481 for (i
= 0; i
< p
->dup_count
; i
++)
483 printf (" recog_data.dup_loc[%d] = &", i
);
484 print_path (p
->duplocs
[i
]);
486 printf (" recog_data.dup_num[%d] = %d;\n", i
, p
->dupnums
[i
]);
494 return (ferror (stdout
) != 0 ? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
);
497 /* Define this so we can link with print-rtl.o to get debug_rtx function. */
499 /* Holds an array of names indexed by insn_code_number. */
500 static char **insn_name_ptr
= 0;
501 static int insn_name_ptr_size
= 0;
504 get_insn_name (int code ATTRIBUTE_UNUSED
)
506 if (code
< insn_name_ptr_size
)
507 return insn_name_ptr
[code
];
513 record_insn_name (int code
, const char *name
)
515 static const char *last_real_name
= "insn";
516 static int last_real_code
= 0;
519 if (insn_name_ptr_size
<= code
)
522 new_size
= (insn_name_ptr_size
? insn_name_ptr_size
* 2 : 512);
523 insn_name_ptr
= xrealloc (insn_name_ptr
, sizeof(char *) * new_size
);
524 memset (insn_name_ptr
+ insn_name_ptr_size
, 0,
525 sizeof(char *) * (new_size
- insn_name_ptr_size
));
526 insn_name_ptr_size
= new_size
;
529 if (!name
|| name
[0] == '\0')
531 new = xmalloc (strlen (last_real_name
) + 10);
532 sprintf (new, "%s+%d", last_real_name
, code
- last_real_code
);
536 last_real_name
= new = xstrdup (name
);
537 last_real_code
= code
;
540 insn_name_ptr
[code
] = new;