1 | /* Support routines for the various generation passes. |
2 | Copyright (C) 2000-2023 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 3, 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 COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ |
19 | |
20 | #include "bconfig.h" |
21 | #define INCLUDE_STRING |
22 | #define INCLUDE_VECTOR |
23 | #include "system.h" |
24 | #include "coretypes.h" |
25 | #include "tm.h" |
26 | #include "rtl.h" |
27 | #include "obstack.h" |
28 | #include "errors.h" |
29 | #include "read-md.h" |
30 | #include "gensupport.h" |
31 | #include "vec.h" |
32 | |
33 | #define MAX_OPERANDS 40 |
34 | |
35 | static rtx operand_data[MAX_OPERANDS]; |
36 | static rtx match_operand_entries_in_pattern[MAX_OPERANDS]; |
37 | static char used_operands_numbers[MAX_OPERANDS]; |
38 | /* List of entries which are part of the new syntax. */ |
39 | hash_set<rtx> compact_syntax; |
40 | |
41 | |
42 | /* In case some macros used by files we include need it, define this here. */ |
43 | int target_flags; |
44 | |
45 | int insn_elision = 1; |
46 | |
47 | static struct obstack obstack; |
48 | struct obstack *rtl_obstack = &obstack; |
49 | |
50 | /* Counter for named patterns and INSN_CODEs. */ |
51 | static int insn_sequence_num; |
52 | |
53 | /* Counter for define_splits. */ |
54 | static int split_sequence_num; |
55 | |
56 | /* Counter for define_peephole2s. */ |
57 | static int peephole2_sequence_num; |
58 | |
59 | static int predicable_default; |
60 | static const char *predicable_true; |
61 | static const char *predicable_false; |
62 | |
63 | static const char *subst_true = "yes" ; |
64 | static const char *subst_false = "no" ; |
65 | |
66 | static htab_t condition_table; |
67 | |
68 | /* We initially queue all patterns, process the define_insn, |
69 | define_cond_exec and define_subst patterns, then return |
70 | them one at a time. */ |
71 | |
72 | class queue_elem |
73 | { |
74 | public: |
75 | rtx data; |
76 | file_location loc; |
77 | class queue_elem *next; |
78 | /* In a DEFINE_INSN that came from a DEFINE_INSN_AND_SPLIT or |
79 | DEFINE_INSN_AND_REWRITE, SPLIT points to the generated DEFINE_SPLIT. */ |
80 | class queue_elem *split; |
81 | }; |
82 | |
83 | #define MNEMONIC_ATTR_NAME "mnemonic" |
84 | #define MNEMONIC_HTAB_SIZE 1024 |
85 | |
86 | static class queue_elem *define_attr_queue; |
87 | static class queue_elem **define_attr_tail = &define_attr_queue; |
88 | static class queue_elem *define_pred_queue; |
89 | static class queue_elem **define_pred_tail = &define_pred_queue; |
90 | static class queue_elem *define_insn_queue; |
91 | static class queue_elem **define_insn_tail = &define_insn_queue; |
92 | static class queue_elem *define_cond_exec_queue; |
93 | static class queue_elem **define_cond_exec_tail = &define_cond_exec_queue; |
94 | static class queue_elem *define_subst_queue; |
95 | static class queue_elem **define_subst_tail = &define_subst_queue; |
96 | static class queue_elem *other_queue; |
97 | static class queue_elem **other_tail = &other_queue; |
98 | static class queue_elem *define_subst_attr_queue; |
99 | static class queue_elem **define_subst_attr_tail = &define_subst_attr_queue; |
100 | |
101 | /* Mapping from DEFINE_* rtxes to their location in the source file. */ |
102 | static hash_map <rtx, file_location> *rtx_locs; |
103 | |
104 | static void remove_constraints (rtx); |
105 | |
106 | static int is_predicable (class queue_elem *); |
107 | static void identify_predicable_attribute (void); |
108 | static int n_alternatives (const char *); |
109 | static void collect_insn_data (rtx, int *, int *); |
110 | static const char *alter_test_for_insn (class queue_elem *, |
111 | class queue_elem *); |
112 | static char *shift_output_template (char *, const char *, int); |
113 | static const char *alter_output_for_insn (class queue_elem *, |
114 | class queue_elem *, |
115 | int, int); |
116 | static void process_one_cond_exec (class queue_elem *); |
117 | static void process_define_cond_exec (void); |
118 | static void init_predicate_table (void); |
119 | static void record_insn_name (int, const char *); |
120 | |
121 | static bool has_subst_attribute (class queue_elem *, class queue_elem *); |
122 | static const char * alter_output_for_subst_insn (rtx, int); |
123 | static void alter_attrs_for_subst_insn (class queue_elem *, int); |
124 | static void process_substs_on_one_elem (class queue_elem *, |
125 | class queue_elem *); |
126 | static rtx subst_dup (rtx, int, int); |
127 | static void process_define_subst (void); |
128 | |
129 | static const char * duplicate_alternatives (const char *, int); |
130 | static const char * duplicate_each_alternative (const char * str, int n_dup); |
131 | |
132 | typedef const char * (*constraints_handler_t) (const char *, int); |
133 | static rtx alter_constraints (rtx, int, constraints_handler_t); |
134 | static rtx adjust_operands_numbers (rtx); |
135 | static rtx replace_duplicating_operands_in_pattern (rtx); |
136 | |
137 | /* Make a version of gen_rtx_CONST_INT so that GEN_INT can be used in |
138 | the gensupport programs. */ |
139 | |
140 | rtx |
141 | gen_rtx_CONST_INT (machine_mode ARG_UNUSED (mode), |
142 | HOST_WIDE_INT arg) |
143 | { |
144 | rtx rt = rtx_alloc (CONST_INT); |
145 | |
146 | XWINT (rt, 0) = arg; |
147 | return rt; |
148 | } |
149 | |
150 | /* Return the rtx pattern specified by the list of rtxes in a |
151 | define_insn or define_split. */ |
152 | |
153 | rtx |
154 | add_implicit_parallel (rtvec vec) |
155 | { |
156 | if (GET_NUM_ELEM (vec) == 1) |
157 | return RTVEC_ELT (vec, 0); |
158 | else |
159 | { |
160 | rtx pattern = rtx_alloc (PARALLEL); |
161 | XVEC (pattern, 0) = vec; |
162 | return pattern; |
163 | } |
164 | } |
165 | |
166 | /* Predicate handling. |
167 | |
168 | We construct from the machine description a table mapping each |
169 | predicate to a list of the rtl codes it can possibly match. The |
170 | function 'maybe_both_true' uses it to deduce that there are no |
171 | expressions that can be matches by certain pairs of tree nodes. |
172 | Also, if a predicate can match only one code, we can hardwire that |
173 | code into the node testing the predicate. |
174 | |
175 | Some predicates are flagged as special. validate_pattern will not |
176 | warn about modeless match_operand expressions if they have a |
177 | special predicate. Predicates that allow only constants are also |
178 | treated as special, for this purpose. |
179 | |
180 | validate_pattern will warn about predicates that allow non-lvalues |
181 | when they appear in destination operands. |
182 | |
183 | Calculating the set of rtx codes that can possibly be accepted by a |
184 | predicate expression EXP requires a three-state logic: any given |
185 | subexpression may definitively accept a code C (Y), definitively |
186 | reject a code C (N), or may have an indeterminate effect (I). N |
187 | and I is N; Y or I is Y; Y and I, N or I are both I. Here are full |
188 | truth tables. |
189 | |
190 | a b a&b a|b |
191 | Y Y Y Y |
192 | N Y N Y |
193 | N N N N |
194 | I Y I Y |
195 | I N N I |
196 | I I I I |
197 | |
198 | We represent Y with 1, N with 0, I with 2. If any code is left in |
199 | an I state by the complete expression, we must assume that that |
200 | code can be accepted. */ |
201 | |
202 | #define N 0 |
203 | #define Y 1 |
204 | #define I 2 |
205 | |
206 | #define TRISTATE_AND(a,b) \ |
207 | ((a) == I ? ((b) == N ? N : I) : \ |
208 | (b) == I ? ((a) == N ? N : I) : \ |
209 | (a) && (b)) |
210 | |
211 | #define TRISTATE_OR(a,b) \ |
212 | ((a) == I ? ((b) == Y ? Y : I) : \ |
213 | (b) == I ? ((a) == Y ? Y : I) : \ |
214 | (a) || (b)) |
215 | |
216 | #define TRISTATE_NOT(a) \ |
217 | ((a) == I ? I : !(a)) |
218 | |
219 | /* 0 means no warning about that code yet, 1 means warned. */ |
220 | static char did_you_mean_codes[NUM_RTX_CODE]; |
221 | |
222 | /* Recursively calculate the set of rtx codes accepted by the |
223 | predicate expression EXP, writing the result to CODES. LOC is |
224 | the .md file location of the directive containing EXP. */ |
225 | |
226 | void |
227 | compute_test_codes (rtx exp, file_location loc, char *codes) |
228 | { |
229 | char op0_codes[NUM_RTX_CODE]; |
230 | char op1_codes[NUM_RTX_CODE]; |
231 | char op2_codes[NUM_RTX_CODE]; |
232 | int i; |
233 | |
234 | switch (GET_CODE (exp)) |
235 | { |
236 | case AND: |
237 | compute_test_codes (XEXP (exp, 0), loc, codes: op0_codes); |
238 | compute_test_codes (XEXP (exp, 1), loc, codes: op1_codes); |
239 | for (i = 0; i < NUM_RTX_CODE; i++) |
240 | codes[i] = TRISTATE_AND (op0_codes[i], op1_codes[i]); |
241 | break; |
242 | |
243 | case IOR: |
244 | compute_test_codes (XEXP (exp, 0), loc, codes: op0_codes); |
245 | compute_test_codes (XEXP (exp, 1), loc, codes: op1_codes); |
246 | for (i = 0; i < NUM_RTX_CODE; i++) |
247 | codes[i] = TRISTATE_OR (op0_codes[i], op1_codes[i]); |
248 | break; |
249 | case NOT: |
250 | compute_test_codes (XEXP (exp, 0), loc, codes: op0_codes); |
251 | for (i = 0; i < NUM_RTX_CODE; i++) |
252 | codes[i] = TRISTATE_NOT (op0_codes[i]); |
253 | break; |
254 | |
255 | case IF_THEN_ELSE: |
256 | /* a ? b : c accepts the same codes as (a & b) | (!a & c). */ |
257 | compute_test_codes (XEXP (exp, 0), loc, codes: op0_codes); |
258 | compute_test_codes (XEXP (exp, 1), loc, codes: op1_codes); |
259 | compute_test_codes (XEXP (exp, 2), loc, codes: op2_codes); |
260 | for (i = 0; i < NUM_RTX_CODE; i++) |
261 | codes[i] = TRISTATE_OR (TRISTATE_AND (op0_codes[i], op1_codes[i]), |
262 | TRISTATE_AND (TRISTATE_NOT (op0_codes[i]), |
263 | op2_codes[i])); |
264 | break; |
265 | |
266 | case MATCH_CODE: |
267 | /* MATCH_CODE allows a specified list of codes. However, if it |
268 | does not apply to the top level of the expression, it does not |
269 | constrain the set of codes for the top level. */ |
270 | if (XSTR (exp, 1)[0] != '\0') |
271 | { |
272 | memset (s: codes, Y, NUM_RTX_CODE); |
273 | break; |
274 | } |
275 | |
276 | memset (s: codes, N, NUM_RTX_CODE); |
277 | { |
278 | const char *next_code = XSTR (exp, 0); |
279 | const char *code; |
280 | |
281 | if (*next_code == '\0') |
282 | { |
283 | error_at (loc, "empty match_code expression" ); |
284 | break; |
285 | } |
286 | |
287 | while ((code = scan_comma_elt (&next_code)) != 0) |
288 | { |
289 | size_t n = next_code - code; |
290 | int found_it = 0; |
291 | |
292 | for (i = 0; i < NUM_RTX_CODE; i++) |
293 | if (!strncmp (s1: code, GET_RTX_NAME (i), n: n) |
294 | && GET_RTX_NAME (i)[n] == '\0') |
295 | { |
296 | codes[i] = Y; |
297 | found_it = 1; |
298 | break; |
299 | } |
300 | if (!found_it) |
301 | { |
302 | error_at (loc, "match_code \"%.*s\" matches nothing" , |
303 | (int) n, code); |
304 | for (i = 0; i < NUM_RTX_CODE; i++) |
305 | if (!strncasecmp (s1: code, GET_RTX_NAME (i), n: n) |
306 | && GET_RTX_NAME (i)[n] == '\0' |
307 | && !did_you_mean_codes[i]) |
308 | { |
309 | did_you_mean_codes[i] = 1; |
310 | message_at (loc, "(did you mean \"%s\"?)" , |
311 | GET_RTX_NAME (i)); |
312 | } |
313 | } |
314 | } |
315 | } |
316 | break; |
317 | |
318 | case MATCH_OPERAND: |
319 | /* MATCH_OPERAND disallows the set of codes that the named predicate |
320 | disallows, and is indeterminate for the codes that it does allow. */ |
321 | { |
322 | struct pred_data *p = lookup_predicate (XSTR (exp, 1)); |
323 | if (!p) |
324 | { |
325 | error_at (loc, "reference to unknown predicate '%s'" , |
326 | XSTR (exp, 1)); |
327 | break; |
328 | } |
329 | for (i = 0; i < NUM_RTX_CODE; i++) |
330 | codes[i] = p->codes[i] ? I : N; |
331 | } |
332 | break; |
333 | |
334 | |
335 | case MATCH_TEST: |
336 | /* (match_test WHATEVER) is completely indeterminate. */ |
337 | memset (s: codes, I, NUM_RTX_CODE); |
338 | break; |
339 | |
340 | default: |
341 | error_at (loc, "'%s' cannot be used in predicates or constraints" , |
342 | GET_RTX_NAME (GET_CODE (exp))); |
343 | memset (s: codes, I, NUM_RTX_CODE); |
344 | break; |
345 | } |
346 | } |
347 | |
348 | #undef TRISTATE_OR |
349 | #undef TRISTATE_AND |
350 | #undef TRISTATE_NOT |
351 | |
352 | /* Return true if NAME is a valid predicate name. */ |
353 | |
354 | static bool |
355 | valid_predicate_name_p (const char *name) |
356 | { |
357 | const char *p; |
358 | |
359 | if (!ISALPHA (name[0]) && name[0] != '_') |
360 | return false; |
361 | for (p = name + 1; *p; p++) |
362 | if (!ISALNUM (*p) && *p != '_') |
363 | return false; |
364 | return true; |
365 | } |
366 | |
367 | /* Process define_predicate directive DESC, which appears at location LOC. |
368 | Compute the set of codes that can be matched, and record this as a known |
369 | predicate. */ |
370 | |
371 | static void |
372 | process_define_predicate (rtx desc, file_location loc) |
373 | { |
374 | struct pred_data *pred; |
375 | char codes[NUM_RTX_CODE]; |
376 | int i; |
377 | |
378 | if (!valid_predicate_name_p (XSTR (desc, 0))) |
379 | { |
380 | error_at (loc, "%s: predicate name must be a valid C function name" , |
381 | XSTR (desc, 0)); |
382 | return; |
383 | } |
384 | |
385 | pred = XCNEW (struct pred_data); |
386 | pred->name = XSTR (desc, 0); |
387 | pred->exp = XEXP (desc, 1); |
388 | pred->c_block = XSTR (desc, 2); |
389 | if (GET_CODE (desc) == DEFINE_SPECIAL_PREDICATE) |
390 | pred->special = true; |
391 | |
392 | compute_test_codes (XEXP (desc, 1), loc, codes); |
393 | |
394 | for (i = 0; i < NUM_RTX_CODE; i++) |
395 | if (codes[i] != N) |
396 | add_predicate_code (pred, (enum rtx_code) i); |
397 | |
398 | add_predicate (pred); |
399 | } |
400 | #undef I |
401 | #undef N |
402 | #undef Y |
403 | |
404 | /* Queue PATTERN on LIST_TAIL. Return the address of the new queue |
405 | element. */ |
406 | |
407 | static class queue_elem * |
408 | queue_pattern (rtx pattern, class queue_elem ***list_tail, |
409 | file_location loc) |
410 | { |
411 | class queue_elem *e = XNEW (class queue_elem); |
412 | e->data = pattern; |
413 | e->loc = loc; |
414 | e->next = NULL; |
415 | e->split = NULL; |
416 | **list_tail = e; |
417 | *list_tail = &e->next; |
418 | return e; |
419 | } |
420 | |
421 | /* Remove element ELEM from QUEUE. */ |
422 | static void |
423 | remove_from_queue (class queue_elem *elem, class queue_elem **queue) |
424 | { |
425 | class queue_elem *prev, *e; |
426 | prev = NULL; |
427 | for (e = *queue; e ; e = e->next) |
428 | { |
429 | if (e == elem) |
430 | break; |
431 | prev = e; |
432 | } |
433 | if (e == NULL) |
434 | return; |
435 | |
436 | if (prev) |
437 | prev->next = elem->next; |
438 | else |
439 | *queue = elem->next; |
440 | } |
441 | |
442 | /* Build a define_attr for an binary attribute with name NAME and |
443 | possible values "yes" and "no", and queue it. */ |
444 | static void |
445 | add_define_attr (const char *name) |
446 | { |
447 | class queue_elem *e = XNEW (class queue_elem); |
448 | rtx t1 = rtx_alloc (DEFINE_ATTR); |
449 | XSTR (t1, 0) = name; |
450 | XSTR (t1, 1) = "no,yes" ; |
451 | XEXP (t1, 2) = rtx_alloc (CONST_STRING); |
452 | XSTR (XEXP (t1, 2), 0) = "yes" ; |
453 | e->data = t1; |
454 | e->loc = file_location ("built-in" , -1, -1); |
455 | e->next = define_attr_queue; |
456 | define_attr_queue = e; |
457 | |
458 | } |
459 | |
460 | /* Recursively remove constraints from an rtx. */ |
461 | |
462 | static void |
463 | remove_constraints (rtx part) |
464 | { |
465 | int i, j; |
466 | const char *format_ptr; |
467 | |
468 | if (part == 0) |
469 | return; |
470 | |
471 | if (GET_CODE (part) == MATCH_OPERAND) |
472 | XSTR (part, 2) = "" ; |
473 | else if (GET_CODE (part) == MATCH_SCRATCH) |
474 | XSTR (part, 1) = "" ; |
475 | |
476 | format_ptr = GET_RTX_FORMAT (GET_CODE (part)); |
477 | |
478 | for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++) |
479 | switch (*format_ptr++) |
480 | { |
481 | case 'e': |
482 | case 'u': |
483 | remove_constraints (XEXP (part, i)); |
484 | break; |
485 | case 'E': |
486 | if (XVEC (part, i) != NULL) |
487 | for (j = 0; j < XVECLEN (part, i); j++) |
488 | remove_constraints (XVECEXP (part, i, j)); |
489 | break; |
490 | } |
491 | } |
492 | |
493 | /* Recursively replace MATCH_OPERANDs with MATCH_DUPs and MATCH_OPERATORs |
494 | with MATCH_OP_DUPs in X. */ |
495 | |
496 | static rtx |
497 | replace_operands_with_dups (rtx x) |
498 | { |
499 | if (x == 0) |
500 | return x; |
501 | |
502 | rtx newx; |
503 | if (GET_CODE (x) == MATCH_OPERAND) |
504 | { |
505 | newx = rtx_alloc (MATCH_DUP); |
506 | XINT (newx, 0) = XINT (x, 0); |
507 | x = newx; |
508 | } |
509 | else if (GET_CODE (x) == MATCH_OPERATOR) |
510 | { |
511 | newx = rtx_alloc (MATCH_OP_DUP); |
512 | XINT (newx, 0) = XINT (x, 0); |
513 | XVEC (newx, 1) = XVEC (x, 2); |
514 | x = newx; |
515 | } |
516 | else |
517 | newx = shallow_copy_rtx (x); |
518 | |
519 | const char *format_ptr = GET_RTX_FORMAT (GET_CODE (x)); |
520 | for (int i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++) |
521 | switch (*format_ptr++) |
522 | { |
523 | case 'e': |
524 | case 'u': |
525 | XEXP (newx, i) = replace_operands_with_dups (XEXP (x, i)); |
526 | break; |
527 | case 'E': |
528 | if (XVEC (x, i) != NULL) |
529 | { |
530 | XVEC (newx, i) = rtvec_alloc (XVECLEN (x, i)); |
531 | for (int j = 0; j < XVECLEN (x, i); j++) |
532 | XVECEXP (newx, i, j) |
533 | = replace_operands_with_dups (XVECEXP (x, i, j)); |
534 | } |
535 | break; |
536 | } |
537 | return newx; |
538 | } |
539 | |
540 | /* Convert matching pattern VEC from a DEFINE_INSN_AND_REWRITE into |
541 | a sequence that should be generated by the splitter. */ |
542 | |
543 | static rtvec |
544 | gen_rewrite_sequence (rtvec vec) |
545 | { |
546 | rtvec new_vec = rtvec_alloc (1); |
547 | rtx x = add_implicit_parallel (vec); |
548 | RTVEC_ELT (new_vec, 0) = replace_operands_with_dups (x); |
549 | return new_vec; |
550 | } |
551 | |
552 | /* The following is for handling the compact syntax for constraints and |
553 | attributes. |
554 | |
555 | The normal syntax looks like this: |
556 | |
557 | ... |
558 | (match_operand: 0 "s_register_operand" "r,I,k") |
559 | (match_operand: 2 "s_register_operand" "r,k,I") |
560 | ... |
561 | "@ |
562 | <asm> |
563 | <asm> |
564 | <asm>" |
565 | ... |
566 | (set_attr "length" "4,8,8") |
567 | |
568 | The compact syntax looks like this: |
569 | |
570 | ... |
571 | (match_operand: 0 "s_register_operand") |
572 | (match_operand: 2 "s_register_operand") |
573 | ... |
574 | {@ [cons: 0, 2; attrs: length] |
575 | [r,r; 4] <asm> |
576 | [I,k; 8] <asm> |
577 | [k,I; 8] <asm> |
578 | } |
579 | ... |
580 | [<other attributes>] |
581 | |
582 | This is the only place where this syntax needs to be handled. Relevant |
583 | patterns are transformed from compact to the normal syntax before they are |
584 | queued, so none of the gen* programs need to know about this syntax at all. |
585 | |
586 | Conversion process (convert_syntax): |
587 | |
588 | 0) Check that pattern actually uses new syntax (check for {@ ... }). |
589 | |
590 | 1) Get the "layout", i.e. the "[cons: 0 2; attrs: length]" from the above |
591 | example. cons must come first; both are optional. Set up two vecs, |
592 | convec and attrvec, for holding the results of the transformation. |
593 | |
594 | 2) For each alternative: parse the list of constraints and/or attributes, |
595 | and enqueue them in the relevant lists in convec and attrvec. By the end |
596 | of this process, convec[N].con and attrvec[N].con should contain regular |
597 | syntax constraint/attribute lists like "r,I,k". Copy the asm to a string |
598 | as we go. |
599 | |
600 | 3) Search the rtx and write the constraint and attribute lists into the |
601 | correct places. Write the asm back into the template. */ |
602 | |
603 | /* Helper class for shuffling constraints/attributes in convert_syntax and |
604 | add_constraints/add_attributes. This includes commas but not whitespace. */ |
605 | |
606 | class conlist { |
607 | private: |
608 | std::string con; |
609 | |
610 | public: |
611 | std::string name; |
612 | int idx = -1; |
613 | |
614 | conlist () = default; |
615 | |
616 | /* [ns..ns + len) should be a string with the id of the rtx to match |
617 | i.e. if rtx is the relevant match_operand or match_scratch then |
618 | [ns..ns + len) should equal itoa (XINT (rtx, 0)), and if set_attr then |
619 | [ns..ns + len) should equal XSTR (rtx, 0). */ |
620 | conlist (const char *ns, unsigned int len, bool numeric) |
621 | { |
622 | /* Trim leading whitespaces. */ |
623 | while (len > 0 && ISBLANK (*ns)) |
624 | { |
625 | ns++; |
626 | len--; |
627 | } |
628 | |
629 | /* Trim trailing whitespace. */ |
630 | for (int i = len - 1; i >= 0; i--, len--) |
631 | if (!ISBLANK (ns[i])) |
632 | break; |
633 | |
634 | /* Parse off any modifiers. */ |
635 | while (len > 0 && !ISALNUM (*ns)) |
636 | { |
637 | con += *(ns++); |
638 | len--; |
639 | } |
640 | |
641 | name.assign (s: ns, n: len); |
642 | if (numeric) |
643 | idx = strtol (nptr: name.c_str (), endptr: (char **)NULL, base: 10); |
644 | } |
645 | |
646 | /* Adds a character to the end of the string. */ |
647 | void add (char c) |
648 | { |
649 | con += c; |
650 | } |
651 | |
652 | /* Output the string in the form of a brand-new char *, then effectively |
653 | clear the internal string by resetting len to 0. */ |
654 | char *out () |
655 | { |
656 | /* Final character is always a trailing comma, so strip it out. */ |
657 | char *q = xstrndup (con.c_str (), con.size () - 1); |
658 | con.clear (); |
659 | return q; |
660 | } |
661 | }; |
662 | |
663 | typedef std::vector<conlist> vec_conlist; |
664 | |
665 | /* Add constraints to an rtx. This function is similar to remove_constraints. |
666 | Errors if adding the constraints would overwrite existing constraints. */ |
667 | |
668 | static void |
669 | add_constraints (rtx part, file_location loc, vec_conlist &cons) |
670 | { |
671 | const char *format_ptr; |
672 | |
673 | if (part == NULL_RTX) |
674 | return; |
675 | |
676 | /* If match_op or match_scr, check if we have the right one, and if so, copy |
677 | over the constraint list. */ |
678 | if (GET_CODE (part) == MATCH_OPERAND || GET_CODE (part) == MATCH_SCRATCH) |
679 | { |
680 | int field = GET_CODE (part) == MATCH_OPERAND ? 2 : 1; |
681 | unsigned id = XINT (part, 0); |
682 | |
683 | if (id >= cons.size () || cons[id].idx == -1) |
684 | return; |
685 | |
686 | if (XSTR (part, field)[0] != '\0') |
687 | { |
688 | error_at (loc, "can't mix normal and compact constraint syntax" ); |
689 | return; |
690 | } |
691 | XSTR (part, field) = cons[id].out (); |
692 | cons[id].idx = -1; |
693 | } |
694 | |
695 | format_ptr = GET_RTX_FORMAT (GET_CODE (part)); |
696 | |
697 | /* Recursively search the rtx. */ |
698 | for (int i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++) |
699 | switch (*format_ptr++) |
700 | { |
701 | case 'e': |
702 | case 'u': |
703 | add_constraints (XEXP (part, i), loc, cons); |
704 | break; |
705 | case 'E': |
706 | if (XVEC (part, i) != NULL) |
707 | for (int j = 0; j < XVECLEN (part, i); j++) |
708 | add_constraints (XVECEXP (part, i, j), loc, cons); |
709 | break; |
710 | default: |
711 | continue; |
712 | } |
713 | } |
714 | |
715 | /* Add ATTRS to definition X's attribute list. */ |
716 | |
717 | static void |
718 | add_attributes (rtx x, vec_conlist &attrs) |
719 | { |
720 | unsigned int attr_index = GET_CODE (x) == DEFINE_INSN ? 4 : 3; |
721 | rtvec orig = XVEC (x, attr_index); |
722 | if (orig) |
723 | { |
724 | size_t n_curr = XVECLEN (x, attr_index); |
725 | rtvec copy = rtvec_alloc (n_curr + attrs.size ()); |
726 | |
727 | /* Create a shallow copy of existing entries. */ |
728 | memcpy (dest: ©->elem[attrs.size ()], src: &orig->elem[0], |
729 | n: sizeof (rtx) * n_curr); |
730 | XVEC (x, attr_index) = copy; |
731 | } |
732 | else |
733 | XVEC (x, attr_index) = rtvec_alloc (attrs.size ()); |
734 | |
735 | /* Create the new elements. */ |
736 | for (unsigned i = 0; i < attrs.size (); i++) |
737 | { |
738 | rtx attr = rtx_alloc (SET_ATTR); |
739 | XSTR (attr, 0) = xstrdup (attrs[i].name.c_str ()); |
740 | XSTR (attr, 1) = attrs[i].out (); |
741 | XVECEXP (x, attr_index, i) = attr; |
742 | } |
743 | } |
744 | |
745 | /* Consumes spaces and tabs. */ |
746 | |
747 | static inline void |
748 | skip_spaces (const char **str) |
749 | { |
750 | while (ISBLANK (**str)) |
751 | (*str)++; |
752 | } |
753 | |
754 | /* Consumes the given character, if it's there. */ |
755 | |
756 | static inline bool |
757 | expect_char (const char **str, char c) |
758 | { |
759 | if (**str != c) |
760 | return false; |
761 | (*str)++; |
762 | return true; |
763 | } |
764 | |
765 | /* Parses the section layout that follows a "{@" if using new syntax. Builds |
766 | a vector for a single section. E.g. if we have "attrs: length, arch]..." |
767 | then list will have two elements, the first for "length" and the second |
768 | for "arch". */ |
769 | |
770 | static void |
771 | parse_section_layout (file_location loc, const char **templ, const char *label, |
772 | vec_conlist &list, bool numeric) |
773 | { |
774 | const char *name_start; |
775 | size_t label_len = strlen (s: label); |
776 | if (strncmp (s1: label, s2: *templ, n: label_len) == 0) |
777 | { |
778 | *templ += label_len; |
779 | |
780 | /* Gather the names. */ |
781 | while (**templ != ';' && **templ != ']') |
782 | { |
783 | skip_spaces (str: templ); |
784 | name_start = *templ; |
785 | int len = 0; |
786 | char val = (*templ)[len]; |
787 | while (val != ',' && val != ';' && val != ']') |
788 | { |
789 | if (val == 0 || val == '\n') |
790 | fatal_at (loc, "missing ']'" ); |
791 | val = (*templ)[++len]; |
792 | } |
793 | *templ += len; |
794 | if (val == ',') |
795 | (*templ)++; |
796 | list.push_back (x: conlist (name_start, len, numeric)); |
797 | } |
798 | } |
799 | } |
800 | |
801 | /* Parse a section, a section is defined as a named space separated list, e.g. |
802 | |
803 | foo: a, b, c |
804 | |
805 | is a section named "foo" with entries a, b and c. */ |
806 | |
807 | static void |
808 | parse_section (const char **templ, unsigned int n_elems, unsigned int alt_no, |
809 | vec_conlist &list, file_location loc, const char *name) |
810 | { |
811 | unsigned int i; |
812 | |
813 | /* Go through the list, one character at a time, adding said character |
814 | to the correct string. */ |
815 | for (i = 0; **templ != ']' && **templ != ';'; (*templ)++) |
816 | if (!ISBLANK (**templ)) |
817 | { |
818 | if (**templ == 0 || **templ == '\n') |
819 | fatal_at (loc, "missing ']'" ); |
820 | list[i].add (c: **templ); |
821 | if (**templ == ',') |
822 | { |
823 | ++i; |
824 | if (i == n_elems) |
825 | fatal_at (loc, "too many %ss in alternative %d: expected %d" , |
826 | name, alt_no, n_elems); |
827 | } |
828 | } |
829 | |
830 | if (i + 1 < n_elems) |
831 | fatal_at (loc, "too few %ss in alternative %d: expected %d, got %d" , |
832 | name, alt_no, n_elems, i); |
833 | |
834 | list[i].add (c: ','); |
835 | } |
836 | |
837 | /* The compact syntax has more convience syntaxes. As such we post process |
838 | the lines to get them back to something the normal syntax understands. */ |
839 | |
840 | static void |
841 | preprocess_compact_syntax (file_location loc, int alt_no, std::string &line, |
842 | std::string &last_line) |
843 | { |
844 | /* Check if we're copying the last statement. */ |
845 | if (line.find (s: "^" ) == 0 && line.size () == 1) |
846 | { |
847 | if (last_line.empty ()) |
848 | fatal_at (loc, "found instruction to copy previous line (^) in" |
849 | "alternative %d but no previous line to copy" , alt_no); |
850 | line = last_line; |
851 | return; |
852 | } |
853 | |
854 | std::string result; |
855 | std::string buffer; |
856 | /* Check if we have << which means return c statement. */ |
857 | if (line.find (s: "<<" ) == 0) |
858 | { |
859 | result.append (s: "* return " ); |
860 | const char *chunk = line.c_str () + 2; |
861 | skip_spaces (str: &chunk); |
862 | result.append (s: chunk); |
863 | } |
864 | else |
865 | result.append (str: line); |
866 | |
867 | line = result; |
868 | return; |
869 | } |
870 | |
871 | /* Converts an rtx from compact syntax to normal syntax if possible. */ |
872 | |
873 | static void |
874 | convert_syntax (rtx x, file_location loc) |
875 | { |
876 | int alt_no; |
877 | unsigned int templ_index; |
878 | const char *templ; |
879 | vec_conlist tconvec, convec, attrvec; |
880 | |
881 | templ_index = 3; |
882 | gcc_assert (GET_CODE (x) == DEFINE_INSN); |
883 | |
884 | templ = XTMPL (x, templ_index); |
885 | |
886 | /* Templates with constraints start with "{@". */ |
887 | if (strncmp (s1: "*{@" , s2: templ, n: 3)) |
888 | return; |
889 | |
890 | /* Get the layout for the template. */ |
891 | templ += 3; |
892 | skip_spaces (str: &templ); |
893 | |
894 | if (!expect_char (str: &templ, c: '[')) |
895 | fatal_at (loc, "expecing `[' to begin section list" ); |
896 | |
897 | skip_spaces (str: &templ); |
898 | |
899 | parse_section_layout (loc, templ: &templ, label: "cons:" , list&: tconvec, numeric: true); |
900 | |
901 | if (*templ != ']') |
902 | { |
903 | if (*templ == ';') |
904 | skip_spaces (str: &(++templ)); |
905 | parse_section_layout (loc, templ: &templ, label: "attrs:" , list&: attrvec, numeric: false); |
906 | } |
907 | |
908 | if (!expect_char (str: &templ, c: ']')) |
909 | fatal_at (loc, "expecting `]` to end section list - section list must have " |
910 | "cons first, attrs second" ); |
911 | |
912 | /* We will write the un-constrainified template into new_templ. */ |
913 | std::string new_templ; |
914 | new_templ.append (s: "@" ); |
915 | |
916 | /* Skip to the first proper line. */ |
917 | skip_spaces (str: &templ); |
918 | if (*templ == 0) |
919 | fatal_at (loc, "'{@...}' blocks must have at least one alternative" ); |
920 | if (*templ != '\n') |
921 | fatal_at (loc, "unexpected character '%c' after ']'" , *templ); |
922 | templ++; |
923 | |
924 | alt_no = 0; |
925 | std::string last_line; |
926 | |
927 | /* Process the alternatives. */ |
928 | while (*(templ - 1) != '\0') |
929 | { |
930 | /* Skip leading whitespace. */ |
931 | std::string buffer; |
932 | skip_spaces (str: &templ); |
933 | |
934 | /* Check if we're at the end. */ |
935 | if (templ[0] == '}' && templ[1] == '\0') |
936 | break; |
937 | |
938 | if (expect_char (str: &templ, c: '[')) |
939 | { |
940 | new_templ += '\n'; |
941 | new_templ.append (str: buffer); |
942 | /* Parse the constraint list, then the attribute list. */ |
943 | if (tconvec.size () > 0) |
944 | parse_section (templ: &templ, n_elems: tconvec.size (), alt_no, list&: tconvec, loc, |
945 | name: "constraint" ); |
946 | |
947 | if (attrvec.size () > 0) |
948 | { |
949 | if (tconvec.size () > 0 && !expect_char (str: &templ, c: ';')) |
950 | fatal_at (loc, "expected `;' to separate constraints " |
951 | "and attributes in alternative %d" , alt_no); |
952 | |
953 | parse_section (templ: &templ, n_elems: attrvec.size (), alt_no, |
954 | list&: attrvec, loc, name: "attribute" ); |
955 | } |
956 | |
957 | if (!expect_char (str: &templ, c: ']')) |
958 | fatal_at (loc, "expected end of constraint/attribute list but " |
959 | "missing an ending `]' in alternative %d" , alt_no); |
960 | } |
961 | else if (templ[0] == '/' && templ[1] == '/') |
962 | { |
963 | templ += 2; |
964 | /* Glob till newline or end of string. */ |
965 | while (*templ != '\n' || *templ != '\0') |
966 | templ++; |
967 | |
968 | /* Skip any newlines or whitespaces needed. */ |
969 | while (ISSPACE(*templ)) |
970 | templ++; |
971 | continue; |
972 | } |
973 | else if (templ[0] == '/' && templ[1] == '*') |
974 | { |
975 | templ += 2; |
976 | /* Glob till newline or end of multiline comment. */ |
977 | while (templ[0] != 0 && templ[0] != '*' && templ[1] != '/') |
978 | templ++; |
979 | |
980 | while (templ[0] != '*' || templ[1] != '/') |
981 | { |
982 | if (templ[0] == 0) |
983 | fatal_at (loc, "unterminated '/*'" ); |
984 | templ++; |
985 | } |
986 | templ += 2; |
987 | |
988 | /* Skip any newlines or whitespaces needed. */ |
989 | while (ISSPACE(*templ)) |
990 | templ++; |
991 | continue; |
992 | } |
993 | else |
994 | fatal_at (loc, "expected constraint/attribute list at beginning of " |
995 | "alternative %d but missing a starting `['" , alt_no); |
996 | |
997 | /* Skip whitespace between list and asm. */ |
998 | skip_spaces (str: &templ); |
999 | |
1000 | /* Copy asm to new template. */ |
1001 | std::string line; |
1002 | while (*templ != '\n' && *templ != '\0') |
1003 | line += *templ++; |
1004 | |
1005 | /* Apply any pre-processing needed to the line. */ |
1006 | preprocess_compact_syntax (loc, alt_no, line, last_line); |
1007 | new_templ.append (str: line); |
1008 | last_line = line; |
1009 | |
1010 | /* Normal "*..." syntax expects the closing quote to be on the final |
1011 | line of asm, whereas we allow the closing "}" to be on its own line. |
1012 | Postpone copying the '\n' until we know that there is another |
1013 | alternative in the list. */ |
1014 | while (ISSPACE (*templ)) |
1015 | templ++; |
1016 | ++alt_no; |
1017 | } |
1018 | |
1019 | /* Check for any duplicate cons entries and sort based on i. */ |
1020 | for (auto e : tconvec) |
1021 | { |
1022 | unsigned idx = e.idx; |
1023 | if (idx >= convec.size ()) |
1024 | convec.resize (new_size: idx + 1); |
1025 | |
1026 | if (convec[idx].idx >= 0) |
1027 | fatal_at (loc, "duplicate cons number found: %d" , idx); |
1028 | convec[idx] = e; |
1029 | } |
1030 | tconvec.clear (); |
1031 | |
1032 | /* Write the constraints and attributes into their proper places. */ |
1033 | if (convec.size () > 0) |
1034 | add_constraints (part: x, loc, cons&: convec); |
1035 | |
1036 | if (attrvec.size () > 0) |
1037 | add_attributes (x, attrs&: attrvec); |
1038 | |
1039 | /* Copy over the new un-constrainified template. */ |
1040 | XTMPL (x, templ_index) = xstrdup (new_templ.c_str ()); |
1041 | |
1042 | /* Register for later checks during iterator expansions. */ |
1043 | compact_syntax.add (k: x); |
1044 | } |
1045 | |
1046 | /* Process a top level rtx in some way, queuing as appropriate. */ |
1047 | |
1048 | static void |
1049 | process_rtx (rtx desc, file_location loc) |
1050 | { |
1051 | switch (GET_CODE (desc)) |
1052 | { |
1053 | case DEFINE_INSN: |
1054 | convert_syntax (x: desc, loc); |
1055 | queue_pattern (pattern: desc, list_tail: &define_insn_tail, loc); |
1056 | break; |
1057 | |
1058 | case DEFINE_COND_EXEC: |
1059 | queue_pattern (pattern: desc, list_tail: &define_cond_exec_tail, loc); |
1060 | break; |
1061 | |
1062 | case DEFINE_SUBST: |
1063 | queue_pattern (pattern: desc, list_tail: &define_subst_tail, loc); |
1064 | break; |
1065 | |
1066 | case DEFINE_SUBST_ATTR: |
1067 | queue_pattern (pattern: desc, list_tail: &define_subst_attr_tail, loc); |
1068 | break; |
1069 | |
1070 | case DEFINE_ATTR: |
1071 | case DEFINE_ENUM_ATTR: |
1072 | queue_pattern (pattern: desc, list_tail: &define_attr_tail, loc); |
1073 | break; |
1074 | |
1075 | case DEFINE_PREDICATE: |
1076 | case DEFINE_SPECIAL_PREDICATE: |
1077 | process_define_predicate (desc, loc); |
1078 | /* Fall through. */ |
1079 | |
1080 | case DEFINE_CONSTRAINT: |
1081 | case DEFINE_REGISTER_CONSTRAINT: |
1082 | case DEFINE_MEMORY_CONSTRAINT: |
1083 | case DEFINE_SPECIAL_MEMORY_CONSTRAINT: |
1084 | case DEFINE_RELAXED_MEMORY_CONSTRAINT: |
1085 | case DEFINE_ADDRESS_CONSTRAINT: |
1086 | queue_pattern (pattern: desc, list_tail: &define_pred_tail, loc); |
1087 | break; |
1088 | |
1089 | case DEFINE_INSN_AND_SPLIT: |
1090 | case DEFINE_INSN_AND_REWRITE: |
1091 | { |
1092 | const char *split_cond; |
1093 | rtx split; |
1094 | rtvec attr; |
1095 | int i; |
1096 | class queue_elem *insn_elem; |
1097 | class queue_elem *split_elem; |
1098 | int split_code = (GET_CODE (desc) == DEFINE_INSN_AND_REWRITE ? 5 : 6); |
1099 | |
1100 | /* Create a split with values from the insn_and_split. */ |
1101 | split = rtx_alloc (DEFINE_SPLIT); |
1102 | |
1103 | i = XVECLEN (desc, 1); |
1104 | XVEC (split, 0) = rtvec_alloc (i); |
1105 | while (--i >= 0) |
1106 | { |
1107 | XVECEXP (split, 0, i) = copy_rtx (XVECEXP (desc, 1, i)); |
1108 | remove_constraints (XVECEXP (split, 0, i)); |
1109 | } |
1110 | |
1111 | /* If the split condition starts with "&&", append it to the |
1112 | insn condition to create the new split condition. */ |
1113 | split_cond = XSTR (desc, 4); |
1114 | if (split_cond[0] == '&' && split_cond[1] == '&') |
1115 | { |
1116 | rtx_reader_ptr->copy_md_ptr_loc (new_ptr: split_cond + 2, old_ptr: split_cond); |
1117 | split_cond = rtx_reader_ptr->join_c_conditions (XSTR (desc, 2), |
1118 | cond2: split_cond + 2); |
1119 | } |
1120 | else if (GET_CODE (desc) == DEFINE_INSN_AND_REWRITE) |
1121 | error_at (loc, "the rewrite condition must start with `&&'" ); |
1122 | XSTR (split, 1) = split_cond; |
1123 | if (GET_CODE (desc) == DEFINE_INSN_AND_REWRITE) |
1124 | XVEC (split, 2) = gen_rewrite_sequence (XVEC (desc, 1)); |
1125 | else |
1126 | XVEC (split, 2) = XVEC (desc, 5); |
1127 | XSTR (split, 3) = XSTR (desc, split_code); |
1128 | |
1129 | /* Fix up the DEFINE_INSN. */ |
1130 | attr = XVEC (desc, split_code + 1); |
1131 | PUT_CODE (desc, DEFINE_INSN); |
1132 | XVEC (desc, 4) = attr; |
1133 | convert_syntax (x: desc, loc); |
1134 | |
1135 | /* Queue them. */ |
1136 | insn_elem = queue_pattern (pattern: desc, list_tail: &define_insn_tail, loc); |
1137 | split_elem = queue_pattern (pattern: split, list_tail: &other_tail, loc); |
1138 | insn_elem->split = split_elem; |
1139 | break; |
1140 | } |
1141 | |
1142 | default: |
1143 | queue_pattern (pattern: desc, list_tail: &other_tail, loc); |
1144 | break; |
1145 | } |
1146 | } |
1147 | |
1148 | /* Return true if attribute PREDICABLE is true for ELEM, which holds |
1149 | a DEFINE_INSN. */ |
1150 | |
1151 | static int |
1152 | is_predicable (class queue_elem *elem) |
1153 | { |
1154 | rtvec vec = XVEC (elem->data, 4); |
1155 | const char *value; |
1156 | int i; |
1157 | |
1158 | if (! vec) |
1159 | return predicable_default; |
1160 | |
1161 | for (i = GET_NUM_ELEM (vec) - 1; i >= 0; --i) |
1162 | { |
1163 | rtx sub = RTVEC_ELT (vec, i); |
1164 | switch (GET_CODE (sub)) |
1165 | { |
1166 | case SET_ATTR: |
1167 | if (strcmp (XSTR (sub, 0), s2: "predicable" ) == 0) |
1168 | { |
1169 | value = XSTR (sub, 1); |
1170 | goto found; |
1171 | } |
1172 | break; |
1173 | |
1174 | case SET_ATTR_ALTERNATIVE: |
1175 | if (strcmp (XSTR (sub, 0), s2: "predicable" ) == 0) |
1176 | { |
1177 | error_at (elem->loc, "multiple alternatives for `predicable'" ); |
1178 | return 0; |
1179 | } |
1180 | break; |
1181 | |
1182 | case SET: |
1183 | if (GET_CODE (SET_DEST (sub)) != ATTR |
1184 | || strcmp (XSTR (SET_DEST (sub), 0), s2: "predicable" ) != 0) |
1185 | break; |
1186 | sub = SET_SRC (sub); |
1187 | if (GET_CODE (sub) == CONST_STRING) |
1188 | { |
1189 | value = XSTR (sub, 0); |
1190 | goto found; |
1191 | } |
1192 | |
1193 | /* ??? It would be possible to handle this if we really tried. |
1194 | It's not easy though, and I'm not going to bother until it |
1195 | really proves necessary. */ |
1196 | error_at (elem->loc, "non-constant value for `predicable'" ); |
1197 | return 0; |
1198 | |
1199 | default: |
1200 | gcc_unreachable (); |
1201 | } |
1202 | } |
1203 | |
1204 | return predicable_default; |
1205 | |
1206 | found: |
1207 | /* Find out which value we're looking at. Multiple alternatives means at |
1208 | least one is predicable. */ |
1209 | if (strchr (s: value, c: ',') != NULL) |
1210 | return 1; |
1211 | if (strcmp (s1: value, s2: predicable_true) == 0) |
1212 | return 1; |
1213 | if (strcmp (s1: value, s2: predicable_false) == 0) |
1214 | return 0; |
1215 | |
1216 | error_at (elem->loc, "unknown value `%s' for `predicable' attribute" , value); |
1217 | return 0; |
1218 | } |
1219 | |
1220 | /* Find attribute SUBST in ELEM and assign NEW_VALUE to it. */ |
1221 | static void |
1222 | change_subst_attribute (class queue_elem *elem, |
1223 | class queue_elem *subst_elem, |
1224 | const char *new_value) |
1225 | { |
1226 | rtvec attrs_vec = XVEC (elem->data, 4); |
1227 | const char *subst_name = XSTR (subst_elem->data, 0); |
1228 | int i; |
1229 | |
1230 | if (! attrs_vec) |
1231 | return; |
1232 | |
1233 | for (i = GET_NUM_ELEM (attrs_vec) - 1; i >= 0; --i) |
1234 | { |
1235 | rtx cur_attr = RTVEC_ELT (attrs_vec, i); |
1236 | if (GET_CODE (cur_attr) != SET_ATTR) |
1237 | continue; |
1238 | if (strcmp (XSTR (cur_attr, 0), s2: subst_name) == 0) |
1239 | { |
1240 | XSTR (cur_attr, 1) = new_value; |
1241 | return; |
1242 | } |
1243 | } |
1244 | } |
1245 | |
1246 | /* Return true if ELEM has the attribute with the name of DEFINE_SUBST |
1247 | represented by SUBST_ELEM and this attribute has value SUBST_TRUE. |
1248 | DEFINE_SUBST isn't applied to patterns without such attribute. In other |
1249 | words, we suppose the default value of the attribute to be 'no' since it is |
1250 | always generated automatically in read-rtl.cc. */ |
1251 | static bool |
1252 | has_subst_attribute (class queue_elem *elem, class queue_elem *subst_elem) |
1253 | { |
1254 | rtvec attrs_vec = XVEC (elem->data, 4); |
1255 | const char *value, *subst_name = XSTR (subst_elem->data, 0); |
1256 | int i; |
1257 | |
1258 | if (! attrs_vec) |
1259 | return false; |
1260 | |
1261 | for (i = GET_NUM_ELEM (attrs_vec) - 1; i >= 0; --i) |
1262 | { |
1263 | rtx cur_attr = RTVEC_ELT (attrs_vec, i); |
1264 | switch (GET_CODE (cur_attr)) |
1265 | { |
1266 | case SET_ATTR: |
1267 | if (strcmp (XSTR (cur_attr, 0), s2: subst_name) == 0) |
1268 | { |
1269 | value = XSTR (cur_attr, 1); |
1270 | goto found; |
1271 | } |
1272 | break; |
1273 | |
1274 | case SET: |
1275 | if (GET_CODE (SET_DEST (cur_attr)) != ATTR |
1276 | || strcmp (XSTR (SET_DEST (cur_attr), 0), s2: subst_name) != 0) |
1277 | break; |
1278 | cur_attr = SET_SRC (cur_attr); |
1279 | if (GET_CODE (cur_attr) == CONST_STRING) |
1280 | { |
1281 | value = XSTR (cur_attr, 0); |
1282 | goto found; |
1283 | } |
1284 | |
1285 | /* Only (set_attr "subst" "yes/no") and |
1286 | (set (attr "subst" (const_string "yes/no"))) |
1287 | are currently allowed. */ |
1288 | error_at (elem->loc, "unsupported value for `%s'" , subst_name); |
1289 | return false; |
1290 | |
1291 | case SET_ATTR_ALTERNATIVE: |
1292 | if (strcmp (XSTR (cur_attr, 0), s2: subst_name) == 0) |
1293 | error_at (elem->loc, |
1294 | "%s: `set_attr_alternative' is unsupported by " |
1295 | "`define_subst'" , XSTR (elem->data, 0)); |
1296 | return false; |
1297 | |
1298 | |
1299 | default: |
1300 | gcc_unreachable (); |
1301 | } |
1302 | } |
1303 | |
1304 | return false; |
1305 | |
1306 | found: |
1307 | if (strcmp (s1: value, s2: subst_true) == 0) |
1308 | return true; |
1309 | if (strcmp (s1: value, s2: subst_false) == 0) |
1310 | return false; |
1311 | |
1312 | error_at (elem->loc, "unknown value `%s' for `%s' attribute" , |
1313 | value, subst_name); |
1314 | return false; |
1315 | } |
1316 | |
1317 | /* Compare RTL-template of original define_insn X to input RTL-template of |
1318 | define_subst PT. Return 1 if the templates match, 0 otherwise. |
1319 | During the comparison, the routine also fills global_array OPERAND_DATA. */ |
1320 | static bool |
1321 | subst_pattern_match (rtx x, rtx pt, file_location loc) |
1322 | { |
1323 | RTX_CODE code, code_pt; |
1324 | int i, j, len; |
1325 | const char *fmt, *pred_name; |
1326 | |
1327 | code = GET_CODE (x); |
1328 | code_pt = GET_CODE (pt); |
1329 | |
1330 | if (code_pt == MATCH_OPERAND) |
1331 | { |
1332 | /* MATCH_DUP, and MATCH_OP_DUP don't have a specified mode, so we |
1333 | always accept them. */ |
1334 | if (GET_MODE (pt) != VOIDmode && GET_MODE (x) != GET_MODE (pt) |
1335 | && (code != MATCH_DUP && code != MATCH_OP_DUP)) |
1336 | return false; /* Modes don't match. */ |
1337 | |
1338 | if (code == MATCH_OPERAND) |
1339 | { |
1340 | pred_name = XSTR (pt, 1); |
1341 | if (pred_name[0] != 0) |
1342 | { |
1343 | const struct pred_data *pred_pt = lookup_predicate (pred_name); |
1344 | if (!pred_pt || pred_pt != lookup_predicate (XSTR (x, 1))) |
1345 | return false; /* Predicates don't match. */ |
1346 | } |
1347 | } |
1348 | |
1349 | gcc_assert (XINT (pt, 0) >= 0 && XINT (pt, 0) < MAX_OPERANDS); |
1350 | operand_data[XINT (pt, 0)] = x; |
1351 | return true; |
1352 | } |
1353 | |
1354 | if (code_pt == MATCH_OPERATOR) |
1355 | { |
1356 | int x_vecexp_pos = -1; |
1357 | |
1358 | /* Compare modes. */ |
1359 | if (GET_MODE (pt) != VOIDmode && GET_MODE (x) != GET_MODE (pt)) |
1360 | return false; |
1361 | |
1362 | /* In case X is also match_operator, compare predicates. */ |
1363 | if (code == MATCH_OPERATOR) |
1364 | { |
1365 | pred_name = XSTR (pt, 1); |
1366 | if (pred_name[0] != 0) |
1367 | { |
1368 | const struct pred_data *pred_pt = lookup_predicate (pred_name); |
1369 | if (!pred_pt || pred_pt != lookup_predicate (XSTR (x, 1))) |
1370 | return false; |
1371 | } |
1372 | } |
1373 | |
1374 | /* Compare operands. |
1375 | MATCH_OPERATOR in input template could match in original template |
1376 | either 1) MATCH_OPERAND, 2) UNSPEC, 3) ordinary operation (like PLUS). |
1377 | In the first case operands are at (XVECEXP (x, 2, j)), in the second |
1378 | - at (XVECEXP (x, 0, j)), in the last one - (XEXP (x, j)). |
1379 | X_VECEXP_POS variable shows, where to look for these operands. */ |
1380 | if (code == UNSPEC |
1381 | || code == UNSPEC_VOLATILE) |
1382 | x_vecexp_pos = 0; |
1383 | else if (code == MATCH_OPERATOR) |
1384 | x_vecexp_pos = 2; |
1385 | else |
1386 | x_vecexp_pos = -1; |
1387 | |
1388 | /* MATCH_OPERATOR or UNSPEC case. */ |
1389 | if (x_vecexp_pos >= 0) |
1390 | { |
1391 | /* Compare operands number in X and PT. */ |
1392 | if (XVECLEN (x, x_vecexp_pos) != XVECLEN (pt, 2)) |
1393 | return false; |
1394 | for (j = 0; j < XVECLEN (pt, 2); j++) |
1395 | if (!subst_pattern_match (XVECEXP (x, x_vecexp_pos, j), |
1396 | XVECEXP (pt, 2, j), loc)) |
1397 | return false; |
1398 | } |
1399 | |
1400 | /* Ordinary operator. */ |
1401 | else |
1402 | { |
1403 | /* Compare operands number in X and PT. |
1404 | We count operands differently for X and PT since we compare |
1405 | an operator (with operands directly in RTX) and MATCH_OPERATOR |
1406 | (that has a vector with operands). */ |
1407 | if (GET_RTX_LENGTH (code) != XVECLEN (pt, 2)) |
1408 | return false; |
1409 | for (j = 0; j < XVECLEN (pt, 2); j++) |
1410 | if (!subst_pattern_match (XEXP (x, j), XVECEXP (pt, 2, j), loc)) |
1411 | return false; |
1412 | } |
1413 | |
1414 | /* Store the operand to OPERAND_DATA array. */ |
1415 | gcc_assert (XINT (pt, 0) >= 0 && XINT (pt, 0) < MAX_OPERANDS); |
1416 | operand_data[XINT (pt, 0)] = x; |
1417 | return true; |
1418 | } |
1419 | |
1420 | if (code_pt == MATCH_PAR_DUP |
1421 | || code_pt == MATCH_DUP |
1422 | || code_pt == MATCH_OP_DUP |
1423 | || code_pt == MATCH_SCRATCH |
1424 | || code_pt == MATCH_PARALLEL) |
1425 | { |
1426 | /* Currently interface for these constructions isn't defined - |
1427 | probably they aren't needed in input template of define_subst at all. |
1428 | So, for now their usage in define_subst is forbidden. */ |
1429 | error_at (loc, "%s cannot be used in define_subst" , |
1430 | GET_RTX_NAME (code_pt)); |
1431 | } |
1432 | |
1433 | gcc_assert (code != MATCH_PAR_DUP |
1434 | && code_pt != MATCH_DUP |
1435 | && code_pt != MATCH_OP_DUP |
1436 | && code_pt != MATCH_SCRATCH |
1437 | && code_pt != MATCH_PARALLEL |
1438 | && code_pt != MATCH_OPERAND |
1439 | && code_pt != MATCH_OPERATOR); |
1440 | /* If PT is none of the handled above, then we match only expressions with |
1441 | the same code in X. */ |
1442 | if (code != code_pt) |
1443 | return false; |
1444 | |
1445 | fmt = GET_RTX_FORMAT (code_pt); |
1446 | len = GET_RTX_LENGTH (code_pt); |
1447 | |
1448 | for (i = 0; i < len; i++) |
1449 | { |
1450 | if (fmt[i] == '0') |
1451 | break; |
1452 | |
1453 | switch (fmt[i]) |
1454 | { |
1455 | case 'r': case 'p': case 'i': case 'w': case 's': |
1456 | continue; |
1457 | |
1458 | case 'e': case 'u': |
1459 | if (!subst_pattern_match (XEXP (x, i), XEXP (pt, i), loc)) |
1460 | return false; |
1461 | break; |
1462 | case 'E': |
1463 | { |
1464 | if (XVECLEN (x, i) != XVECLEN (pt, i)) |
1465 | return false; |
1466 | for (j = 0; j < XVECLEN (pt, i); j++) |
1467 | if (!subst_pattern_match (XVECEXP (x, i, j), |
1468 | XVECEXP (pt, i, j), loc)) |
1469 | return false; |
1470 | break; |
1471 | } |
1472 | default: |
1473 | gcc_unreachable (); |
1474 | } |
1475 | } |
1476 | |
1477 | return true; |
1478 | } |
1479 | |
1480 | /* Examine the attribute "predicable"; discover its boolean values |
1481 | and its default. */ |
1482 | |
1483 | static void |
1484 | identify_predicable_attribute (void) |
1485 | { |
1486 | class queue_elem *elem; |
1487 | char *p_true, *p_false; |
1488 | const char *value; |
1489 | |
1490 | /* Look for the DEFINE_ATTR for `predicable', which must exist. */ |
1491 | for (elem = define_attr_queue; elem ; elem = elem->next) |
1492 | if (strcmp (XSTR (elem->data, 0), s2: "predicable" ) == 0) |
1493 | goto found; |
1494 | |
1495 | error_at (define_cond_exec_queue->loc, |
1496 | "attribute `predicable' not defined" ); |
1497 | return; |
1498 | |
1499 | found: |
1500 | value = XSTR (elem->data, 1); |
1501 | p_false = xstrdup (value); |
1502 | p_true = strchr (s: p_false, c: ','); |
1503 | if (p_true == NULL || strchr (s: ++p_true, c: ',') != NULL) |
1504 | { |
1505 | error_at (elem->loc, "attribute `predicable' is not a boolean" ); |
1506 | free (ptr: p_false); |
1507 | return; |
1508 | } |
1509 | p_true[-1] = '\0'; |
1510 | |
1511 | predicable_true = p_true; |
1512 | predicable_false = p_false; |
1513 | |
1514 | switch (GET_CODE (XEXP (elem->data, 2))) |
1515 | { |
1516 | case CONST_STRING: |
1517 | value = XSTR (XEXP (elem->data, 2), 0); |
1518 | break; |
1519 | |
1520 | case CONST: |
1521 | error_at (elem->loc, "attribute `predicable' cannot be const" ); |
1522 | free (ptr: p_false); |
1523 | return; |
1524 | |
1525 | default: |
1526 | error_at (elem->loc, |
1527 | "attribute `predicable' must have a constant default" ); |
1528 | free (ptr: p_false); |
1529 | return; |
1530 | } |
1531 | |
1532 | if (strcmp (s1: value, s2: p_true) == 0) |
1533 | predicable_default = 1; |
1534 | else if (strcmp (s1: value, s2: p_false) == 0) |
1535 | predicable_default = 0; |
1536 | else |
1537 | { |
1538 | error_at (elem->loc, "unknown value `%s' for `predicable' attribute" , |
1539 | value); |
1540 | free (ptr: p_false); |
1541 | } |
1542 | } |
1543 | |
1544 | /* Return the number of alternatives in constraint S. */ |
1545 | |
1546 | static int |
1547 | n_alternatives (const char *s) |
1548 | { |
1549 | int n = 1; |
1550 | |
1551 | if (s) |
1552 | while (*s) |
1553 | n += (*s++ == ','); |
1554 | |
1555 | return n; |
1556 | } |
1557 | |
1558 | /* The routine scans rtl PATTERN, find match_operand in it and counts |
1559 | number of alternatives. If PATTERN contains several match_operands |
1560 | with different number of alternatives, error is emitted, and the |
1561 | routine returns 0. If all match_operands in PATTERN have the same |
1562 | number of alternatives, it's stored in N_ALT, and the routine returns 1. |
1563 | LOC is the location of PATTERN, for error reporting. */ |
1564 | static int |
1565 | get_alternatives_number (rtx pattern, int *n_alt, file_location loc) |
1566 | { |
1567 | const char *fmt; |
1568 | enum rtx_code code; |
1569 | int i, j, len; |
1570 | |
1571 | if (!n_alt) |
1572 | return 0; |
1573 | |
1574 | code = GET_CODE (pattern); |
1575 | switch (code) |
1576 | { |
1577 | case MATCH_OPERAND: |
1578 | i = n_alternatives (XSTR (pattern, 2)); |
1579 | /* n_alternatives returns 1 if constraint string is empty - |
1580 | here we fix it up. */ |
1581 | if (!*(XSTR (pattern, 2))) |
1582 | i = 0; |
1583 | if (*n_alt <= 0) |
1584 | *n_alt = i; |
1585 | |
1586 | else if (i && i != *n_alt) |
1587 | { |
1588 | error_at (loc, "wrong number of alternatives in operand %d" , |
1589 | XINT (pattern, 0)); |
1590 | return 0; |
1591 | } |
1592 | |
1593 | default: |
1594 | break; |
1595 | } |
1596 | |
1597 | fmt = GET_RTX_FORMAT (code); |
1598 | len = GET_RTX_LENGTH (code); |
1599 | for (i = 0; i < len; i++) |
1600 | { |
1601 | switch (fmt[i]) |
1602 | { |
1603 | case 'e': case 'u': |
1604 | if (!get_alternatives_number (XEXP (pattern, i), n_alt, loc)) |
1605 | return 0; |
1606 | break; |
1607 | |
1608 | case 'V': |
1609 | if (XVEC (pattern, i) == NULL) |
1610 | break; |
1611 | /* FALLTHRU */ |
1612 | |
1613 | case 'E': |
1614 | for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) |
1615 | if (!get_alternatives_number (XVECEXP (pattern, i, j), n_alt, loc)) |
1616 | return 0; |
1617 | break; |
1618 | |
1619 | case 'r': case 'p': case 'i': case 'w': |
1620 | case '0': case 's': case 'S': case 'T': |
1621 | break; |
1622 | |
1623 | default: |
1624 | gcc_unreachable (); |
1625 | } |
1626 | } |
1627 | return 1; |
1628 | } |
1629 | |
1630 | /* Determine how many alternatives there are in INSN, and how many |
1631 | operands. */ |
1632 | |
1633 | static void |
1634 | collect_insn_data (rtx pattern, int *palt, int *pmax) |
1635 | { |
1636 | const char *fmt; |
1637 | enum rtx_code code; |
1638 | int i, j, len; |
1639 | |
1640 | code = GET_CODE (pattern); |
1641 | switch (code) |
1642 | { |
1643 | case MATCH_OPERAND: |
1644 | case MATCH_SCRATCH: |
1645 | i = n_alternatives (XSTR (pattern, code == MATCH_SCRATCH ? 1 : 2)); |
1646 | *palt = (i > *palt ? i : *palt); |
1647 | /* Fall through. */ |
1648 | |
1649 | case MATCH_OPERATOR: |
1650 | case MATCH_PARALLEL: |
1651 | i = XINT (pattern, 0); |
1652 | if (i > *pmax) |
1653 | *pmax = i; |
1654 | break; |
1655 | |
1656 | default: |
1657 | break; |
1658 | } |
1659 | |
1660 | fmt = GET_RTX_FORMAT (code); |
1661 | len = GET_RTX_LENGTH (code); |
1662 | for (i = 0; i < len; i++) |
1663 | { |
1664 | switch (fmt[i]) |
1665 | { |
1666 | case 'e': case 'u': |
1667 | collect_insn_data (XEXP (pattern, i), palt, pmax); |
1668 | break; |
1669 | |
1670 | case 'V': |
1671 | if (XVEC (pattern, i) == NULL) |
1672 | break; |
1673 | /* Fall through. */ |
1674 | case 'E': |
1675 | for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) |
1676 | collect_insn_data (XVECEXP (pattern, i, j), palt, pmax); |
1677 | break; |
1678 | |
1679 | case 'r': case 'p': case 'i': case 'w': |
1680 | case '0': case 's': case 'S': case 'T': |
1681 | break; |
1682 | |
1683 | default: |
1684 | gcc_unreachable (); |
1685 | } |
1686 | } |
1687 | } |
1688 | |
1689 | static rtx |
1690 | alter_predicate_for_insn (rtx pattern, int alt, int max_op, |
1691 | file_location loc) |
1692 | { |
1693 | const char *fmt; |
1694 | enum rtx_code code; |
1695 | int i, j, len; |
1696 | |
1697 | code = GET_CODE (pattern); |
1698 | switch (code) |
1699 | { |
1700 | case MATCH_OPERAND: |
1701 | { |
1702 | const char *c = XSTR (pattern, 2); |
1703 | |
1704 | if (n_alternatives (s: c) != 1) |
1705 | { |
1706 | error_at (loc, "too many alternatives for operand %d" , |
1707 | XINT (pattern, 0)); |
1708 | return NULL; |
1709 | } |
1710 | |
1711 | /* Replicate C as needed to fill out ALT alternatives. */ |
1712 | if (c && *c && alt > 1) |
1713 | { |
1714 | size_t c_len = strlen (s: c); |
1715 | size_t len = alt * (c_len + 1); |
1716 | char *new_c = XNEWVEC (char, len); |
1717 | |
1718 | memcpy (dest: new_c, src: c, n: c_len); |
1719 | for (i = 1; i < alt; ++i) |
1720 | { |
1721 | new_c[i * (c_len + 1) - 1] = ','; |
1722 | memcpy (dest: &new_c[i * (c_len + 1)], src: c, n: c_len); |
1723 | } |
1724 | new_c[len - 1] = '\0'; |
1725 | XSTR (pattern, 2) = new_c; |
1726 | } |
1727 | } |
1728 | /* Fall through. */ |
1729 | |
1730 | case MATCH_OPERATOR: |
1731 | case MATCH_SCRATCH: |
1732 | case MATCH_PARALLEL: |
1733 | case MATCH_DUP: |
1734 | XINT (pattern, 0) += max_op; |
1735 | break; |
1736 | |
1737 | default: |
1738 | break; |
1739 | } |
1740 | |
1741 | fmt = GET_RTX_FORMAT (code); |
1742 | len = GET_RTX_LENGTH (code); |
1743 | for (i = 0; i < len; i++) |
1744 | { |
1745 | rtx r; |
1746 | |
1747 | switch (fmt[i]) |
1748 | { |
1749 | case 'e': case 'u': |
1750 | r = alter_predicate_for_insn (XEXP (pattern, i), alt, max_op, loc); |
1751 | if (r == NULL) |
1752 | return r; |
1753 | break; |
1754 | |
1755 | case 'E': |
1756 | for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) |
1757 | { |
1758 | r = alter_predicate_for_insn (XVECEXP (pattern, i, j), |
1759 | alt, max_op, loc); |
1760 | if (r == NULL) |
1761 | return r; |
1762 | } |
1763 | break; |
1764 | |
1765 | case 'r': case 'p': case 'i': case 'w': case '0': case 's': |
1766 | break; |
1767 | |
1768 | default: |
1769 | gcc_unreachable (); |
1770 | } |
1771 | } |
1772 | |
1773 | return pattern; |
1774 | } |
1775 | |
1776 | /* Duplicate constraints in PATTERN. If pattern is from original |
1777 | rtl-template, we need to duplicate each alternative - for that we |
1778 | need to use duplicate_each_alternative () as a functor ALTER. |
1779 | If pattern is from output-pattern of define_subst, we need to |
1780 | duplicate constraints in another way - with duplicate_alternatives (). |
1781 | N_DUP is multiplication factor. */ |
1782 | static rtx |
1783 | alter_constraints (rtx pattern, int n_dup, constraints_handler_t alter) |
1784 | { |
1785 | const char *fmt; |
1786 | enum rtx_code code; |
1787 | int i, j, len; |
1788 | |
1789 | code = GET_CODE (pattern); |
1790 | switch (code) |
1791 | { |
1792 | case MATCH_OPERAND: |
1793 | XSTR (pattern, 2) = alter (XSTR (pattern, 2), n_dup); |
1794 | break; |
1795 | case MATCH_SCRATCH: |
1796 | XSTR (pattern, 1) = alter (XSTR (pattern, 1), n_dup); |
1797 | break; |
1798 | |
1799 | default: |
1800 | break; |
1801 | } |
1802 | |
1803 | fmt = GET_RTX_FORMAT (code); |
1804 | len = GET_RTX_LENGTH (code); |
1805 | for (i = 0; i < len; i++) |
1806 | { |
1807 | rtx r; |
1808 | |
1809 | switch (fmt[i]) |
1810 | { |
1811 | case 'e': case 'u': |
1812 | r = alter_constraints (XEXP (pattern, i), n_dup, alter); |
1813 | if (r == NULL) |
1814 | return r; |
1815 | break; |
1816 | |
1817 | case 'E': |
1818 | for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) |
1819 | { |
1820 | r = alter_constraints (XVECEXP (pattern, i, j), n_dup, alter); |
1821 | if (r == NULL) |
1822 | return r; |
1823 | } |
1824 | break; |
1825 | |
1826 | case 'r': case 'p': case 'i': case 'w': case '0': case 's': |
1827 | break; |
1828 | |
1829 | default: |
1830 | break; |
1831 | } |
1832 | } |
1833 | |
1834 | return pattern; |
1835 | } |
1836 | |
1837 | static const char * |
1838 | alter_test_for_insn (class queue_elem *ce_elem, |
1839 | class queue_elem *insn_elem) |
1840 | { |
1841 | return rtx_reader_ptr->join_c_conditions (XSTR (ce_elem->data, 1), |
1842 | XSTR (insn_elem->data, 2)); |
1843 | } |
1844 | |
1845 | /* Modify VAL, which is an attribute expression for the "enabled" attribute, |
1846 | to take "ce_enabled" into account. Return the new expression. */ |
1847 | static rtx |
1848 | modify_attr_enabled_ce (rtx val) |
1849 | { |
1850 | rtx eq_attr, str; |
1851 | rtx ite; |
1852 | eq_attr = rtx_alloc (EQ_ATTR); |
1853 | ite = rtx_alloc (IF_THEN_ELSE); |
1854 | str = rtx_alloc (CONST_STRING); |
1855 | |
1856 | XSTR (eq_attr, 0) = "ce_enabled" ; |
1857 | XSTR (eq_attr, 1) = "yes" ; |
1858 | XSTR (str, 0) = "no" ; |
1859 | XEXP (ite, 0) = eq_attr; |
1860 | XEXP (ite, 1) = val; |
1861 | XEXP (ite, 2) = str; |
1862 | |
1863 | return ite; |
1864 | } |
1865 | |
1866 | /* Alter the attribute vector of INSN, which is a COND_EXEC variant created |
1867 | from a define_insn pattern. We must modify the "predicable" attribute |
1868 | to be named "ce_enabled", and also change any "enabled" attribute that's |
1869 | present so that it takes ce_enabled into account. |
1870 | We rely on the fact that INSN was created with copy_rtx, and modify data |
1871 | in-place. */ |
1872 | |
1873 | static void |
1874 | alter_attrs_for_insn (rtx insn) |
1875 | { |
1876 | static bool global_changes_made = false; |
1877 | rtvec vec = XVEC (insn, 4); |
1878 | rtvec new_vec; |
1879 | rtx val, set; |
1880 | int num_elem; |
1881 | int predicable_idx = -1; |
1882 | int enabled_idx = -1; |
1883 | int i; |
1884 | |
1885 | if (! vec) |
1886 | return; |
1887 | |
1888 | num_elem = GET_NUM_ELEM (vec); |
1889 | for (i = num_elem - 1; i >= 0; --i) |
1890 | { |
1891 | rtx sub = RTVEC_ELT (vec, i); |
1892 | switch (GET_CODE (sub)) |
1893 | { |
1894 | case SET_ATTR: |
1895 | if (strcmp (XSTR (sub, 0), s2: "predicable" ) == 0) |
1896 | { |
1897 | predicable_idx = i; |
1898 | XSTR (sub, 0) = "ce_enabled" ; |
1899 | } |
1900 | else if (strcmp (XSTR (sub, 0), s2: "enabled" ) == 0) |
1901 | { |
1902 | enabled_idx = i; |
1903 | XSTR (sub, 0) = "nonce_enabled" ; |
1904 | } |
1905 | break; |
1906 | |
1907 | case SET_ATTR_ALTERNATIVE: |
1908 | if (strcmp (XSTR (sub, 0), s2: "predicable" ) == 0) |
1909 | /* We already give an error elsewhere. */ |
1910 | return; |
1911 | else if (strcmp (XSTR (sub, 0), s2: "enabled" ) == 0) |
1912 | { |
1913 | enabled_idx = i; |
1914 | XSTR (sub, 0) = "nonce_enabled" ; |
1915 | } |
1916 | break; |
1917 | |
1918 | case SET: |
1919 | if (GET_CODE (SET_DEST (sub)) != ATTR) |
1920 | break; |
1921 | if (strcmp (XSTR (SET_DEST (sub), 0), s2: "predicable" ) == 0) |
1922 | { |
1923 | sub = SET_SRC (sub); |
1924 | if (GET_CODE (sub) == CONST_STRING) |
1925 | { |
1926 | predicable_idx = i; |
1927 | XSTR (sub, 0) = "ce_enabled" ; |
1928 | } |
1929 | else |
1930 | /* We already give an error elsewhere. */ |
1931 | return; |
1932 | break; |
1933 | } |
1934 | if (strcmp (XSTR (SET_DEST (sub), 0), s2: "enabled" ) == 0) |
1935 | { |
1936 | enabled_idx = i; |
1937 | XSTR (SET_DEST (sub), 0) = "nonce_enabled" ; |
1938 | } |
1939 | break; |
1940 | |
1941 | default: |
1942 | gcc_unreachable (); |
1943 | } |
1944 | } |
1945 | if (predicable_idx == -1) |
1946 | return; |
1947 | |
1948 | if (!global_changes_made) |
1949 | { |
1950 | class queue_elem *elem; |
1951 | |
1952 | global_changes_made = true; |
1953 | add_define_attr (name: "ce_enabled" ); |
1954 | add_define_attr (name: "nonce_enabled" ); |
1955 | |
1956 | for (elem = define_attr_queue; elem ; elem = elem->next) |
1957 | if (strcmp (XSTR (elem->data, 0), s2: "enabled" ) == 0) |
1958 | { |
1959 | XEXP (elem->data, 2) |
1960 | = modify_attr_enabled_ce (XEXP (elem->data, 2)); |
1961 | } |
1962 | } |
1963 | if (enabled_idx == -1) |
1964 | return; |
1965 | |
1966 | new_vec = rtvec_alloc (num_elem + 1); |
1967 | for (i = 0; i < num_elem; i++) |
1968 | RTVEC_ELT (new_vec, i) = RTVEC_ELT (vec, i); |
1969 | val = rtx_alloc (IF_THEN_ELSE); |
1970 | XEXP (val, 0) = rtx_alloc (EQ_ATTR); |
1971 | XEXP (val, 1) = rtx_alloc (CONST_STRING); |
1972 | XEXP (val, 2) = rtx_alloc (CONST_STRING); |
1973 | XSTR (XEXP (val, 0), 0) = "nonce_enabled" ; |
1974 | XSTR (XEXP (val, 0), 1) = "yes" ; |
1975 | XSTR (XEXP (val, 1), 0) = "yes" ; |
1976 | XSTR (XEXP (val, 2), 0) = "no" ; |
1977 | set = rtx_alloc (SET); |
1978 | SET_DEST (set) = rtx_alloc (ATTR); |
1979 | XSTR (SET_DEST (set), 0) = "enabled" ; |
1980 | SET_SRC (set) = modify_attr_enabled_ce (val); |
1981 | RTVEC_ELT (new_vec, i) = set; |
1982 | XVEC (insn, 4) = new_vec; |
1983 | } |
1984 | |
1985 | /* As number of constraints is changed after define_subst, we need to |
1986 | process attributes as well - we need to duplicate them the same way |
1987 | that we duplicated constraints in original pattern |
1988 | ELEM is a queue element, containing our rtl-template, |
1989 | N_DUP - multiplication factor. */ |
1990 | static void |
1991 | alter_attrs_for_subst_insn (class queue_elem * elem, int n_dup) |
1992 | { |
1993 | rtvec vec = XVEC (elem->data, 4); |
1994 | int num_elem; |
1995 | int i; |
1996 | |
1997 | if (n_dup < 2 || ! vec) |
1998 | return; |
1999 | |
2000 | num_elem = GET_NUM_ELEM (vec); |
2001 | for (i = num_elem - 1; i >= 0; --i) |
2002 | { |
2003 | rtx sub = RTVEC_ELT (vec, i); |
2004 | switch (GET_CODE (sub)) |
2005 | { |
2006 | case SET_ATTR: |
2007 | if (strchr (XSTR (sub, 1), c: ',') != NULL) |
2008 | XSTR (sub, 1) = duplicate_alternatives (XSTR (sub, 1), n_dup); |
2009 | break; |
2010 | |
2011 | case SET_ATTR_ALTERNATIVE: |
2012 | case SET: |
2013 | error_at (elem->loc, |
2014 | "%s: `define_subst' does not support attributes " |
2015 | "assigned by `set' and `set_attr_alternative'" , |
2016 | XSTR (elem->data, 0)); |
2017 | return; |
2018 | |
2019 | default: |
2020 | gcc_unreachable (); |
2021 | } |
2022 | } |
2023 | } |
2024 | |
2025 | /* Adjust all of the operand numbers in SRC to match the shift they'll |
2026 | get from an operand displacement of DISP. Return a pointer after the |
2027 | adjusted string. */ |
2028 | |
2029 | static char * |
2030 | shift_output_template (char *dest, const char *src, int disp) |
2031 | { |
2032 | while (*src) |
2033 | { |
2034 | char c = *src++; |
2035 | *dest++ = c; |
2036 | if (c == '%') |
2037 | { |
2038 | c = *src++; |
2039 | if (ISDIGIT ((unsigned char) c)) |
2040 | c += disp; |
2041 | else if (ISALPHA (c)) |
2042 | { |
2043 | *dest++ = c; |
2044 | c = *src++ + disp; |
2045 | } |
2046 | *dest++ = c; |
2047 | } |
2048 | } |
2049 | |
2050 | return dest; |
2051 | } |
2052 | |
2053 | static const char * |
2054 | alter_output_for_insn (class queue_elem *ce_elem, |
2055 | class queue_elem *insn_elem, |
2056 | int alt, int max_op) |
2057 | { |
2058 | const char *ce_out, *insn_out; |
2059 | char *result, *p; |
2060 | size_t len, ce_len, insn_len; |
2061 | |
2062 | /* ??? Could coordinate with genoutput to not duplicate code here. */ |
2063 | |
2064 | ce_out = XSTR (ce_elem->data, 2); |
2065 | insn_out = XTMPL (insn_elem->data, 3); |
2066 | if (!ce_out || *ce_out == '\0') |
2067 | return insn_out; |
2068 | |
2069 | ce_len = strlen (s: ce_out); |
2070 | insn_len = strlen (s: insn_out); |
2071 | |
2072 | if (*insn_out == '*') |
2073 | /* You must take care of the predicate yourself. */ |
2074 | return insn_out; |
2075 | |
2076 | if (*insn_out == '@') |
2077 | { |
2078 | len = (ce_len + 1) * alt + insn_len + 1; |
2079 | p = result = XNEWVEC (char, len); |
2080 | |
2081 | do |
2082 | { |
2083 | do |
2084 | *p++ = *insn_out++; |
2085 | while (ISSPACE ((unsigned char) *insn_out)); |
2086 | |
2087 | if (*insn_out != '#') |
2088 | { |
2089 | p = shift_output_template (dest: p, src: ce_out, disp: max_op); |
2090 | *p++ = ' '; |
2091 | } |
2092 | |
2093 | do |
2094 | *p++ = *insn_out++; |
2095 | while (*insn_out && *insn_out != '\n'); |
2096 | } |
2097 | while (*insn_out); |
2098 | *p = '\0'; |
2099 | } |
2100 | else |
2101 | { |
2102 | len = ce_len + 1 + insn_len + 1; |
2103 | result = XNEWVEC (char, len); |
2104 | |
2105 | p = shift_output_template (dest: result, src: ce_out, disp: max_op); |
2106 | *p++ = ' '; |
2107 | memcpy (dest: p, src: insn_out, n: insn_len + 1); |
2108 | } |
2109 | |
2110 | return result; |
2111 | } |
2112 | |
2113 | /* From string STR "a,b,c" produce "a,b,c,a,b,c,a,b,c", i.e. original |
2114 | string, duplicated N_DUP times. */ |
2115 | |
2116 | static const char * |
2117 | duplicate_alternatives (const char * str, int n_dup) |
2118 | { |
2119 | int i, len, new_len; |
2120 | char *result, *sp; |
2121 | const char *cp; |
2122 | |
2123 | if (n_dup < 2) |
2124 | return str; |
2125 | |
2126 | while (ISSPACE (*str)) |
2127 | str++; |
2128 | |
2129 | if (*str == '\0') |
2130 | return str; |
2131 | |
2132 | cp = str; |
2133 | len = strlen (s: str); |
2134 | new_len = (len + 1) * n_dup; |
2135 | |
2136 | sp = result = XNEWVEC (char, new_len); |
2137 | |
2138 | /* Global modifier characters mustn't be duplicated: skip if found. */ |
2139 | if (*cp == '=' || *cp == '+' || *cp == '%') |
2140 | { |
2141 | *sp++ = *cp++; |
2142 | len--; |
2143 | } |
2144 | |
2145 | /* Copy original constraints N_DUP times. */ |
2146 | for (i = 0; i < n_dup; i++, sp += len+1) |
2147 | { |
2148 | memcpy (dest: sp, src: cp, n: len); |
2149 | *(sp+len) = (i == n_dup - 1) ? '\0' : ','; |
2150 | } |
2151 | |
2152 | return result; |
2153 | } |
2154 | |
2155 | /* From string STR "a,b,c" produce "a,a,a,b,b,b,c,c,c", i.e. string where |
2156 | each alternative from the original string is duplicated N_DUP times. */ |
2157 | static const char * |
2158 | duplicate_each_alternative (const char * str, int n_dup) |
2159 | { |
2160 | int i, len, new_len; |
2161 | char *result, *sp, *ep, *cp; |
2162 | |
2163 | if (n_dup < 2) |
2164 | return str; |
2165 | |
2166 | while (ISSPACE (*str)) |
2167 | str++; |
2168 | |
2169 | if (*str == '\0') |
2170 | return str; |
2171 | |
2172 | cp = xstrdup (str); |
2173 | |
2174 | new_len = (strlen (s: cp) + 1) * n_dup; |
2175 | |
2176 | sp = result = XNEWVEC (char, new_len); |
2177 | |
2178 | /* Global modifier characters mustn't be duplicated: skip if found. */ |
2179 | if (*cp == '=' || *cp == '+' || *cp == '%') |
2180 | *sp++ = *cp++; |
2181 | |
2182 | do |
2183 | { |
2184 | if ((ep = strchr (s: cp, c: ',')) != NULL) |
2185 | *ep++ = '\0'; |
2186 | len = strlen (s: cp); |
2187 | |
2188 | /* Copy a constraint N_DUP times. */ |
2189 | for (i = 0; i < n_dup; i++, sp += len + 1) |
2190 | { |
2191 | memcpy (dest: sp, src: cp, n: len); |
2192 | *(sp+len) = (ep == NULL && i == n_dup - 1) ? '\0' : ','; |
2193 | } |
2194 | |
2195 | cp = ep; |
2196 | } |
2197 | while (cp != NULL); |
2198 | |
2199 | return result; |
2200 | } |
2201 | |
2202 | /* Alter the output of INSN whose pattern was modified by |
2203 | DEFINE_SUBST. We must replicate output strings according |
2204 | to the new number of alternatives ALT in substituted pattern. |
2205 | If ALT equals 1, output has one alternative or defined by C |
2206 | code, then output is returned without any changes. */ |
2207 | |
2208 | static const char * |
2209 | alter_output_for_subst_insn (rtx insn, int alt) |
2210 | { |
2211 | const char *insn_out, *old_out; |
2212 | char *new_out, *cp; |
2213 | size_t old_len, new_len; |
2214 | int j; |
2215 | |
2216 | insn_out = XTMPL (insn, 3); |
2217 | |
2218 | if (alt < 2 || *insn_out != '@') |
2219 | return insn_out; |
2220 | |
2221 | old_out = insn_out + 1; |
2222 | while (ISSPACE (*old_out)) |
2223 | old_out++; |
2224 | old_len = strlen (s: old_out); |
2225 | |
2226 | new_len = alt * (old_len + 1) + 1; |
2227 | |
2228 | new_out = XNEWVEC (char, new_len); |
2229 | new_out[0] = '@'; |
2230 | |
2231 | for (j = 0, cp = new_out + 1; j < alt; j++, cp += old_len + 1) |
2232 | { |
2233 | memcpy (dest: cp, src: old_out, n: old_len); |
2234 | cp[old_len] = (j == alt - 1) ? '\0' : '\n'; |
2235 | } |
2236 | |
2237 | return new_out; |
2238 | } |
2239 | |
2240 | /* Replicate insns as appropriate for the given DEFINE_COND_EXEC. */ |
2241 | |
2242 | static void |
2243 | process_one_cond_exec (class queue_elem *ce_elem) |
2244 | { |
2245 | class queue_elem *insn_elem; |
2246 | for (insn_elem = define_insn_queue; insn_elem ; insn_elem = insn_elem->next) |
2247 | { |
2248 | int alternatives, max_operand; |
2249 | rtx pred, insn, pattern, split; |
2250 | char *new_name; |
2251 | int i; |
2252 | |
2253 | if (! is_predicable (elem: insn_elem)) |
2254 | continue; |
2255 | |
2256 | alternatives = 1; |
2257 | max_operand = -1; |
2258 | collect_insn_data (pattern: insn_elem->data, palt: &alternatives, pmax: &max_operand); |
2259 | max_operand += 1; |
2260 | |
2261 | if (XVECLEN (ce_elem->data, 0) != 1) |
2262 | { |
2263 | error_at (ce_elem->loc, "too many patterns in predicate" ); |
2264 | return; |
2265 | } |
2266 | |
2267 | pred = copy_rtx (XVECEXP (ce_elem->data, 0, 0)); |
2268 | pred = alter_predicate_for_insn (pattern: pred, alt: alternatives, max_op: max_operand, |
2269 | loc: ce_elem->loc); |
2270 | if (pred == NULL) |
2271 | return; |
2272 | |
2273 | /* Construct a new pattern for the new insn. */ |
2274 | insn = copy_rtx (insn_elem->data); |
2275 | new_name = XNEWVAR (char, strlen XSTR (insn_elem->data, 0) + 4); |
2276 | sprintf (s: new_name, format: "*p %s" , XSTR (insn_elem->data, 0)); |
2277 | XSTR (insn, 0) = new_name; |
2278 | pattern = rtx_alloc (COND_EXEC); |
2279 | XEXP (pattern, 0) = pred; |
2280 | XEXP (pattern, 1) = add_implicit_parallel (XVEC (insn, 1)); |
2281 | XVEC (insn, 1) = rtvec_alloc (1); |
2282 | XVECEXP (insn, 1, 0) = pattern; |
2283 | |
2284 | if (XVEC (ce_elem->data, 3) != NULL) |
2285 | { |
2286 | rtvec attributes = rtvec_alloc (XVECLEN (insn, 4) |
2287 | + XVECLEN (ce_elem->data, 3)); |
2288 | int i = 0; |
2289 | int j = 0; |
2290 | for (i = 0; i < XVECLEN (insn, 4); i++) |
2291 | RTVEC_ELT (attributes, i) = XVECEXP (insn, 4, i); |
2292 | |
2293 | for (j = 0; j < XVECLEN (ce_elem->data, 3); j++, i++) |
2294 | RTVEC_ELT (attributes, i) = XVECEXP (ce_elem->data, 3, j); |
2295 | |
2296 | XVEC (insn, 4) = attributes; |
2297 | } |
2298 | |
2299 | XSTR (insn, 2) = alter_test_for_insn (ce_elem, insn_elem); |
2300 | XTMPL (insn, 3) = alter_output_for_insn (ce_elem, insn_elem, |
2301 | alt: alternatives, max_op: max_operand); |
2302 | alter_attrs_for_insn (insn); |
2303 | |
2304 | /* Put the new pattern on the `other' list so that it |
2305 | (a) is not reprocessed by other define_cond_exec patterns |
2306 | (b) appears after all normal define_insn patterns. |
2307 | |
2308 | ??? B is debatable. If one has normal insns that match |
2309 | cond_exec patterns, they will be preferred over these |
2310 | generated patterns. Whether this matters in practice, or if |
2311 | it's a good thing, or whether we should thread these new |
2312 | patterns into the define_insn chain just after their generator |
2313 | is something we'll have to experiment with. */ |
2314 | |
2315 | queue_pattern (pattern: insn, list_tail: &other_tail, loc: insn_elem->loc); |
2316 | |
2317 | if (!insn_elem->split) |
2318 | continue; |
2319 | |
2320 | /* If the original insn came from a define_insn_and_split, |
2321 | generate a new split to handle the predicated insn. */ |
2322 | split = copy_rtx (insn_elem->split->data); |
2323 | /* Predicate the pattern matched by the split. */ |
2324 | pattern = rtx_alloc (COND_EXEC); |
2325 | XEXP (pattern, 0) = pred; |
2326 | XEXP (pattern, 1) = add_implicit_parallel (XVEC (split, 0)); |
2327 | XVEC (split, 0) = rtvec_alloc (1); |
2328 | XVECEXP (split, 0, 0) = pattern; |
2329 | |
2330 | /* Predicate all of the insns generated by the split. */ |
2331 | for (i = 0; i < XVECLEN (split, 2); i++) |
2332 | { |
2333 | pattern = rtx_alloc (COND_EXEC); |
2334 | XEXP (pattern, 0) = pred; |
2335 | XEXP (pattern, 1) = XVECEXP (split, 2, i); |
2336 | XVECEXP (split, 2, i) = pattern; |
2337 | } |
2338 | /* Add the new split to the queue. */ |
2339 | queue_pattern (pattern: split, list_tail: &other_tail, loc: insn_elem->split->loc); |
2340 | } |
2341 | } |
2342 | |
2343 | /* Try to apply define_substs to the given ELEM. |
2344 | Only define_substs, specified via attributes would be applied. |
2345 | If attribute, requiring define_subst, is set, but no define_subst |
2346 | was applied, ELEM would be deleted. */ |
2347 | |
2348 | static void |
2349 | process_substs_on_one_elem (class queue_elem *elem, |
2350 | class queue_elem *queue) |
2351 | { |
2352 | class queue_elem *subst_elem; |
2353 | int i, j, patterns_match; |
2354 | |
2355 | for (subst_elem = define_subst_queue; |
2356 | subst_elem; subst_elem = subst_elem->next) |
2357 | { |
2358 | int alternatives, alternatives_subst; |
2359 | rtx subst_pattern; |
2360 | rtvec subst_pattern_vec; |
2361 | |
2362 | if (!has_subst_attribute (elem, subst_elem)) |
2363 | continue; |
2364 | |
2365 | /* Compare original rtl-pattern from define_insn with input |
2366 | pattern from define_subst. |
2367 | Also, check if numbers of alternatives are the same in all |
2368 | match_operands. */ |
2369 | if (XVECLEN (elem->data, 1) != XVECLEN (subst_elem->data, 1)) |
2370 | continue; |
2371 | patterns_match = 1; |
2372 | alternatives = -1; |
2373 | alternatives_subst = -1; |
2374 | for (j = 0; j < XVECLEN (elem->data, 1); j++) |
2375 | { |
2376 | if (!subst_pattern_match (XVECEXP (elem->data, 1, j), |
2377 | XVECEXP (subst_elem->data, 1, j), |
2378 | loc: subst_elem->loc)) |
2379 | { |
2380 | patterns_match = 0; |
2381 | break; |
2382 | } |
2383 | |
2384 | if (!get_alternatives_number (XVECEXP (elem->data, 1, j), |
2385 | n_alt: &alternatives, loc: subst_elem->loc)) |
2386 | { |
2387 | patterns_match = 0; |
2388 | break; |
2389 | } |
2390 | } |
2391 | |
2392 | /* Check if numbers of alternatives are the same in all |
2393 | match_operands in output template of define_subst. */ |
2394 | for (j = 0; j < XVECLEN (subst_elem->data, 3); j++) |
2395 | { |
2396 | if (!get_alternatives_number (XVECEXP (subst_elem->data, 3, j), |
2397 | n_alt: &alternatives_subst, |
2398 | loc: subst_elem->loc)) |
2399 | { |
2400 | patterns_match = 0; |
2401 | break; |
2402 | } |
2403 | } |
2404 | |
2405 | if (!patterns_match) |
2406 | continue; |
2407 | |
2408 | /* Clear array in which we save occupied indexes of operands. */ |
2409 | memset (s: used_operands_numbers, c: 0, n: sizeof (used_operands_numbers)); |
2410 | |
2411 | /* Create a pattern, based on the output one from define_subst. */ |
2412 | subst_pattern_vec = rtvec_alloc (XVECLEN (subst_elem->data, 3)); |
2413 | for (j = 0; j < XVECLEN (subst_elem->data, 3); j++) |
2414 | { |
2415 | subst_pattern = copy_rtx (XVECEXP (subst_elem->data, 3, j)); |
2416 | |
2417 | /* Duplicate constraints in substitute-pattern. */ |
2418 | subst_pattern = alter_constraints (pattern: subst_pattern, n_dup: alternatives, |
2419 | alter: duplicate_each_alternative); |
2420 | |
2421 | subst_pattern = adjust_operands_numbers (subst_pattern); |
2422 | |
2423 | /* Substitute match_dup and match_op_dup in the new pattern and |
2424 | duplicate constraints. */ |
2425 | subst_pattern = subst_dup (subst_pattern, alternatives, |
2426 | alternatives_subst); |
2427 | |
2428 | replace_duplicating_operands_in_pattern (subst_pattern); |
2429 | |
2430 | /* We don't need any constraints in DEFINE_EXPAND. */ |
2431 | if (GET_CODE (elem->data) == DEFINE_EXPAND) |
2432 | remove_constraints (part: subst_pattern); |
2433 | |
2434 | RTVEC_ELT (subst_pattern_vec, j) = subst_pattern; |
2435 | } |
2436 | XVEC (elem->data, 1) = subst_pattern_vec; |
2437 | |
2438 | for (i = 0; i < MAX_OPERANDS; i++) |
2439 | match_operand_entries_in_pattern[i] = NULL; |
2440 | |
2441 | if (GET_CODE (elem->data) == DEFINE_INSN) |
2442 | { |
2443 | XTMPL (elem->data, 3) = |
2444 | alter_output_for_subst_insn (insn: elem->data, alt: alternatives_subst); |
2445 | alter_attrs_for_subst_insn (elem, n_dup: alternatives_subst); |
2446 | } |
2447 | |
2448 | /* Recalculate condition, joining conditions from original and |
2449 | DEFINE_SUBST input patterns. */ |
2450 | XSTR (elem->data, 2) |
2451 | = rtx_reader_ptr->join_c_conditions (XSTR (subst_elem->data, 2), |
2452 | XSTR (elem->data, 2)); |
2453 | /* Mark that subst was applied by changing attribute from "yes" |
2454 | to "no". */ |
2455 | change_subst_attribute (elem, subst_elem, new_value: subst_false); |
2456 | } |
2457 | |
2458 | /* If ELEM contains a subst attribute with value "yes", then we |
2459 | expected that a subst would be applied, but it wasn't - so, |
2460 | we need to remove that elementto avoid duplicating. */ |
2461 | for (subst_elem = define_subst_queue; |
2462 | subst_elem; subst_elem = subst_elem->next) |
2463 | { |
2464 | if (has_subst_attribute (elem, subst_elem)) |
2465 | { |
2466 | remove_from_queue (elem, queue: &queue); |
2467 | return; |
2468 | } |
2469 | } |
2470 | } |
2471 | |
2472 | /* This is a subroutine of mark_operands_used_in_match_dup. |
2473 | This routine is marks all MATCH_OPERANDs inside PATTERN as occupied. */ |
2474 | static void |
2475 | mark_operands_from_match_dup (rtx pattern) |
2476 | { |
2477 | const char *fmt; |
2478 | int i, j, len, opno; |
2479 | |
2480 | if (GET_CODE (pattern) == MATCH_OPERAND |
2481 | || GET_CODE (pattern) == MATCH_OPERATOR |
2482 | || GET_CODE (pattern) == MATCH_PARALLEL) |
2483 | { |
2484 | opno = XINT (pattern, 0); |
2485 | gcc_assert (opno >= 0 && opno < MAX_OPERANDS); |
2486 | used_operands_numbers [opno] = 1; |
2487 | } |
2488 | fmt = GET_RTX_FORMAT (GET_CODE (pattern)); |
2489 | len = GET_RTX_LENGTH (GET_CODE (pattern)); |
2490 | for (i = 0; i < len; i++) |
2491 | { |
2492 | switch (fmt[i]) |
2493 | { |
2494 | case 'e': case 'u': |
2495 | mark_operands_from_match_dup (XEXP (pattern, i)); |
2496 | break; |
2497 | case 'E': |
2498 | for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) |
2499 | mark_operands_from_match_dup (XVECEXP (pattern, i, j)); |
2500 | break; |
2501 | } |
2502 | } |
2503 | } |
2504 | |
2505 | /* This is a subroutine of adjust_operands_numbers. |
2506 | It goes through all expressions in PATTERN and when MATCH_DUP is |
2507 | met, all MATCH_OPERANDs inside it is marked as occupied. The |
2508 | process of marking is done by routin mark_operands_from_match_dup. */ |
2509 | static void |
2510 | mark_operands_used_in_match_dup (rtx pattern) |
2511 | { |
2512 | const char *fmt; |
2513 | int i, j, len, opno; |
2514 | |
2515 | if (GET_CODE (pattern) == MATCH_DUP) |
2516 | { |
2517 | opno = XINT (pattern, 0); |
2518 | gcc_assert (opno >= 0 && opno < MAX_OPERANDS); |
2519 | mark_operands_from_match_dup (pattern: operand_data[opno]); |
2520 | return; |
2521 | } |
2522 | fmt = GET_RTX_FORMAT (GET_CODE (pattern)); |
2523 | len = GET_RTX_LENGTH (GET_CODE (pattern)); |
2524 | for (i = 0; i < len; i++) |
2525 | { |
2526 | switch (fmt[i]) |
2527 | { |
2528 | case 'e': case 'u': |
2529 | mark_operands_used_in_match_dup (XEXP (pattern, i)); |
2530 | break; |
2531 | case 'E': |
2532 | for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) |
2533 | mark_operands_used_in_match_dup (XVECEXP (pattern, i, j)); |
2534 | break; |
2535 | } |
2536 | } |
2537 | } |
2538 | |
2539 | /* This is subroutine of renumerate_operands_in_pattern. |
2540 | It finds first not-occupied operand-index. */ |
2541 | static int |
2542 | find_first_unused_number_of_operand () |
2543 | { |
2544 | int i; |
2545 | for (i = 0; i < MAX_OPERANDS; i++) |
2546 | if (!used_operands_numbers[i]) |
2547 | return i; |
2548 | return MAX_OPERANDS; |
2549 | } |
2550 | |
2551 | /* This is subroutine of adjust_operands_numbers. |
2552 | It visits all expressions in PATTERN and assigns not-occupied |
2553 | operand indexes to MATCH_OPERANDs and MATCH_OPERATORs of this |
2554 | PATTERN. */ |
2555 | static void |
2556 | renumerate_operands_in_pattern (rtx pattern) |
2557 | { |
2558 | const char *fmt; |
2559 | enum rtx_code code; |
2560 | int i, j, len, new_opno; |
2561 | code = GET_CODE (pattern); |
2562 | |
2563 | if (code == MATCH_OPERAND |
2564 | || code == MATCH_OPERATOR) |
2565 | { |
2566 | new_opno = find_first_unused_number_of_operand (); |
2567 | gcc_assert (new_opno >= 0 && new_opno < MAX_OPERANDS); |
2568 | XINT (pattern, 0) = new_opno; |
2569 | used_operands_numbers [new_opno] = 1; |
2570 | } |
2571 | |
2572 | fmt = GET_RTX_FORMAT (GET_CODE (pattern)); |
2573 | len = GET_RTX_LENGTH (GET_CODE (pattern)); |
2574 | for (i = 0; i < len; i++) |
2575 | { |
2576 | switch (fmt[i]) |
2577 | { |
2578 | case 'e': case 'u': |
2579 | renumerate_operands_in_pattern (XEXP (pattern, i)); |
2580 | break; |
2581 | case 'E': |
2582 | for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) |
2583 | renumerate_operands_in_pattern (XVECEXP (pattern, i, j)); |
2584 | break; |
2585 | } |
2586 | } |
2587 | } |
2588 | |
2589 | /* If output pattern of define_subst contains MATCH_DUP, then this |
2590 | expression would be replaced with the pattern, matched with |
2591 | MATCH_OPERAND from input pattern. This pattern could contain any |
2592 | number of MATCH_OPERANDs, MATCH_OPERATORs etc., so it's possible |
2593 | that a MATCH_OPERAND from output_pattern (if any) would have the |
2594 | same number, as MATCH_OPERAND from copied pattern. To avoid such |
2595 | indexes overlapping, we assign new indexes to MATCH_OPERANDs, |
2596 | laying in the output pattern outside of MATCH_DUPs. */ |
2597 | static rtx |
2598 | adjust_operands_numbers (rtx pattern) |
2599 | { |
2600 | mark_operands_used_in_match_dup (pattern); |
2601 | |
2602 | renumerate_operands_in_pattern (pattern); |
2603 | |
2604 | return pattern; |
2605 | } |
2606 | |
2607 | /* Generate RTL expression |
2608 | (match_dup OPNO) |
2609 | */ |
2610 | static rtx |
2611 | generate_match_dup (int opno) |
2612 | { |
2613 | rtx return_rtx = rtx_alloc (MATCH_DUP); |
2614 | PUT_CODE (return_rtx, MATCH_DUP); |
2615 | XINT (return_rtx, 0) = opno; |
2616 | return return_rtx; |
2617 | } |
2618 | |
2619 | /* This routine checks all match_operands in PATTERN and if some of |
2620 | have the same index, it replaces all of them except the first one to |
2621 | match_dup. |
2622 | Usually, match_operands with the same indexes are forbidden, but |
2623 | after define_subst copy an RTL-expression from original template, |
2624 | indexes of existed and just-copied match_operands could coincide. |
2625 | To fix it, we replace one of them with match_dup. */ |
2626 | static rtx |
2627 | replace_duplicating_operands_in_pattern (rtx pattern) |
2628 | { |
2629 | const char *fmt; |
2630 | int i, j, len, opno; |
2631 | rtx mdup; |
2632 | |
2633 | if (GET_CODE (pattern) == MATCH_OPERAND) |
2634 | { |
2635 | opno = XINT (pattern, 0); |
2636 | gcc_assert (opno >= 0 && opno < MAX_OPERANDS); |
2637 | if (match_operand_entries_in_pattern[opno] == NULL) |
2638 | { |
2639 | match_operand_entries_in_pattern[opno] = pattern; |
2640 | return NULL; |
2641 | } |
2642 | else |
2643 | { |
2644 | /* Compare predicates before replacing with match_dup. */ |
2645 | if (strcmp (XSTR (pattern, 1), |
2646 | XSTR (match_operand_entries_in_pattern[opno], 1))) |
2647 | { |
2648 | error ("duplicated match_operands with different predicates were" |
2649 | " found." ); |
2650 | return NULL; |
2651 | } |
2652 | return generate_match_dup (opno); |
2653 | } |
2654 | } |
2655 | fmt = GET_RTX_FORMAT (GET_CODE (pattern)); |
2656 | len = GET_RTX_LENGTH (GET_CODE (pattern)); |
2657 | for (i = 0; i < len; i++) |
2658 | { |
2659 | switch (fmt[i]) |
2660 | { |
2661 | case 'e': case 'u': |
2662 | mdup = replace_duplicating_operands_in_pattern (XEXP (pattern, i)); |
2663 | if (mdup) |
2664 | XEXP (pattern, i) = mdup; |
2665 | break; |
2666 | case 'E': |
2667 | for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) |
2668 | { |
2669 | mdup = |
2670 | replace_duplicating_operands_in_pattern (XVECEXP |
2671 | (pattern, i, j)); |
2672 | if (mdup) |
2673 | XVECEXP (pattern, i, j) = mdup; |
2674 | } |
2675 | break; |
2676 | } |
2677 | } |
2678 | return NULL; |
2679 | } |
2680 | |
2681 | /* The routine modifies given input PATTERN of define_subst, replacing |
2682 | MATCH_DUP and MATCH_OP_DUP with operands from define_insn original |
2683 | pattern, whose operands are stored in OPERAND_DATA array. |
2684 | It also duplicates constraints in operands - constraints from |
2685 | define_insn operands are duplicated N_SUBST_ALT times, constraints |
2686 | from define_subst operands are duplicated N_ALT times. |
2687 | After the duplication, returned output rtl-pattern contains every |
2688 | combination of input constraints Vs constraints from define_subst |
2689 | output. */ |
2690 | static rtx |
2691 | subst_dup (rtx pattern, int n_alt, int n_subst_alt) |
2692 | { |
2693 | const char *fmt; |
2694 | enum rtx_code code; |
2695 | int i, j, len, opno; |
2696 | |
2697 | code = GET_CODE (pattern); |
2698 | switch (code) |
2699 | { |
2700 | case MATCH_DUP: |
2701 | case MATCH_OP_DUP: |
2702 | opno = XINT (pattern, 0); |
2703 | |
2704 | gcc_assert (opno >= 0 && opno < MAX_OPERANDS); |
2705 | |
2706 | if (operand_data[opno]) |
2707 | { |
2708 | pattern = copy_rtx (operand_data[opno]); |
2709 | |
2710 | /* Duplicate constraints. */ |
2711 | pattern = alter_constraints (pattern, n_dup: n_subst_alt, |
2712 | alter: duplicate_alternatives); |
2713 | } |
2714 | break; |
2715 | |
2716 | default: |
2717 | break; |
2718 | } |
2719 | |
2720 | fmt = GET_RTX_FORMAT (GET_CODE (pattern)); |
2721 | len = GET_RTX_LENGTH (GET_CODE (pattern)); |
2722 | for (i = 0; i < len; i++) |
2723 | { |
2724 | switch (fmt[i]) |
2725 | { |
2726 | case 'e': case 'u': |
2727 | if (code != MATCH_DUP && code != MATCH_OP_DUP) |
2728 | XEXP (pattern, i) = subst_dup (XEXP (pattern, i), |
2729 | n_alt, n_subst_alt); |
2730 | break; |
2731 | case 'V': |
2732 | if (XVEC (pattern, i) == NULL) |
2733 | break; |
2734 | /* FALLTHRU */ |
2735 | case 'E': |
2736 | if (code != MATCH_DUP && code != MATCH_OP_DUP) |
2737 | for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) |
2738 | XVECEXP (pattern, i, j) = subst_dup (XVECEXP (pattern, i, j), |
2739 | n_alt, n_subst_alt); |
2740 | break; |
2741 | |
2742 | case 'r': case 'p': case 'i': case 'w': |
2743 | case '0': case 's': case 'S': case 'T': |
2744 | break; |
2745 | |
2746 | default: |
2747 | gcc_unreachable (); |
2748 | } |
2749 | } |
2750 | return pattern; |
2751 | } |
2752 | |
2753 | /* If we have any DEFINE_COND_EXEC patterns, expand the DEFINE_INSN |
2754 | patterns appropriately. */ |
2755 | |
2756 | static void |
2757 | process_define_cond_exec (void) |
2758 | { |
2759 | class queue_elem *elem; |
2760 | |
2761 | identify_predicable_attribute (); |
2762 | if (have_error) |
2763 | return; |
2764 | |
2765 | for (elem = define_cond_exec_queue; elem ; elem = elem->next) |
2766 | process_one_cond_exec (ce_elem: elem); |
2767 | } |
2768 | |
2769 | /* If we have any DEFINE_SUBST patterns, expand DEFINE_INSN and |
2770 | DEFINE_EXPAND patterns appropriately. */ |
2771 | |
2772 | static void |
2773 | process_define_subst (void) |
2774 | { |
2775 | class queue_elem *elem, *elem_attr; |
2776 | |
2777 | /* Check if each define_subst has corresponding define_subst_attr. */ |
2778 | for (elem = define_subst_queue; elem ; elem = elem->next) |
2779 | { |
2780 | for (elem_attr = define_subst_attr_queue; |
2781 | elem_attr; |
2782 | elem_attr = elem_attr->next) |
2783 | if (strcmp (XSTR (elem->data, 0), XSTR (elem_attr->data, 1)) == 0) |
2784 | goto found; |
2785 | |
2786 | error_at (elem->loc, |
2787 | "%s: `define_subst' must have at least one " |
2788 | "corresponding `define_subst_attr'" , |
2789 | XSTR (elem->data, 0)); |
2790 | return; |
2791 | |
2792 | found: |
2793 | continue; |
2794 | } |
2795 | |
2796 | for (elem = define_insn_queue; elem ; elem = elem->next) |
2797 | process_substs_on_one_elem (elem, queue: define_insn_queue); |
2798 | for (elem = other_queue; elem ; elem = elem->next) |
2799 | { |
2800 | if (GET_CODE (elem->data) != DEFINE_EXPAND) |
2801 | continue; |
2802 | process_substs_on_one_elem (elem, queue: other_queue); |
2803 | } |
2804 | } |
2805 | |
2806 | /* A subclass of rtx_reader which reads .md files and calls process_rtx on |
2807 | the top-level elements. */ |
2808 | |
2809 | class gen_reader : public rtx_reader |
2810 | { |
2811 | public: |
2812 | gen_reader () : rtx_reader (false) {} |
2813 | void handle_unknown_directive (file_location, const char *) final override; |
2814 | }; |
2815 | |
2816 | void |
2817 | gen_reader::handle_unknown_directive (file_location loc, const char *rtx_name) |
2818 | { |
2819 | auto_vec<rtx, 32> subrtxs; |
2820 | if (!read_rtx (rtx_name, rtxen: &subrtxs)) |
2821 | return; |
2822 | |
2823 | rtx x; |
2824 | unsigned int i; |
2825 | FOR_EACH_VEC_ELT (subrtxs, i, x) |
2826 | process_rtx (desc: x, loc); |
2827 | } |
2828 | |
2829 | /* Add mnemonic STR with length LEN to the mnemonic hash table |
2830 | MNEMONIC_HTAB. A trailing zero end character is appended to STR |
2831 | and a permanent heap copy of STR is created. */ |
2832 | |
2833 | static void |
2834 | add_mnemonic_string (htab_t mnemonic_htab, const char *str, size_t len) |
2835 | { |
2836 | char *new_str; |
2837 | void **slot; |
2838 | char *str_zero = (char*)alloca (len + 1); |
2839 | |
2840 | memcpy (dest: str_zero, src: str, n: len); |
2841 | str_zero[len] = '\0'; |
2842 | |
2843 | slot = htab_find_slot (mnemonic_htab, str_zero, INSERT); |
2844 | |
2845 | if (*slot) |
2846 | return; |
2847 | |
2848 | /* Not found; create a permanent copy and add it to the hash table. */ |
2849 | new_str = XNEWVAR (char, len + 1); |
2850 | memcpy (dest: new_str, src: str_zero, n: len + 1); |
2851 | *slot = new_str; |
2852 | } |
2853 | |
2854 | /* Scan INSN for mnemonic strings and add them to the mnemonic hash |
2855 | table in MNEMONIC_HTAB. |
2856 | |
2857 | The mnemonics cannot be found if they are emitted using C code. |
2858 | |
2859 | If a mnemonic string contains ';' or a newline the string assumed |
2860 | to consist of more than a single instruction. The attribute value |
2861 | will then be set to the user defined default value. */ |
2862 | |
2863 | static void |
2864 | gen_mnemonic_setattr (htab_t mnemonic_htab, rtx insn) |
2865 | { |
2866 | const char *template_code, *cp; |
2867 | int i; |
2868 | int vec_len; |
2869 | rtx set_attr; |
2870 | char *attr_name; |
2871 | rtvec new_vec; |
2872 | struct obstack *string_obstack = rtx_reader_ptr->get_string_obstack (); |
2873 | |
2874 | template_code = XTMPL (insn, 3); |
2875 | |
2876 | /* Skip patterns which use C code to emit the template. */ |
2877 | if (template_code[0] == '*') |
2878 | return; |
2879 | |
2880 | if (template_code[0] == '@') |
2881 | cp = &template_code[1]; |
2882 | else |
2883 | cp = &template_code[0]; |
2884 | |
2885 | for (i = 0; *cp; ) |
2886 | { |
2887 | const char *ep, *sp; |
2888 | size_t size = 0; |
2889 | |
2890 | while (ISSPACE (*cp)) |
2891 | cp++; |
2892 | |
2893 | for (ep = sp = cp; !IS_VSPACE (*ep) && *ep != '\0'; ++ep) |
2894 | if (!ISSPACE (*ep)) |
2895 | sp = ep + 1; |
2896 | |
2897 | if (i > 0) |
2898 | obstack_1grow (string_obstack, ','); |
2899 | |
2900 | while (cp < sp && ((*cp >= '0' && *cp <= '9') |
2901 | || (*cp >= 'a' && *cp <= 'z'))) |
2902 | |
2903 | { |
2904 | obstack_1grow (string_obstack, *cp); |
2905 | cp++; |
2906 | size++; |
2907 | } |
2908 | |
2909 | while (cp < sp) |
2910 | { |
2911 | if (*cp == ';' || (*cp == '\\' && cp[1] == 'n')) |
2912 | { |
2913 | /* Don't set a value if there are more than one |
2914 | instruction in the string. */ |
2915 | obstack_blank_fast (string_obstack, -size); |
2916 | size = 0; |
2917 | |
2918 | cp = sp; |
2919 | break; |
2920 | } |
2921 | cp++; |
2922 | } |
2923 | if (size == 0) |
2924 | obstack_1grow (string_obstack, '*'); |
2925 | else |
2926 | add_mnemonic_string (mnemonic_htab, |
2927 | str: (char *) obstack_next_free (string_obstack) - size, |
2928 | len: size); |
2929 | i++; |
2930 | } |
2931 | |
2932 | /* An insn definition might emit an empty string. */ |
2933 | if (obstack_object_size (string_obstack) == 0) |
2934 | return; |
2935 | |
2936 | obstack_1grow (string_obstack, '\0'); |
2937 | |
2938 | set_attr = rtx_alloc (SET_ATTR); |
2939 | XSTR (set_attr, 1) = XOBFINISH (string_obstack, char *); |
2940 | attr_name = XNEWVAR (char, strlen (MNEMONIC_ATTR_NAME) + 1); |
2941 | strcpy (dest: attr_name, MNEMONIC_ATTR_NAME); |
2942 | XSTR (set_attr, 0) = attr_name; |
2943 | |
2944 | if (!XVEC (insn, 4)) |
2945 | vec_len = 0; |
2946 | else |
2947 | vec_len = XVECLEN (insn, 4); |
2948 | |
2949 | new_vec = rtvec_alloc (vec_len + 1); |
2950 | for (i = 0; i < vec_len; i++) |
2951 | RTVEC_ELT (new_vec, i) = XVECEXP (insn, 4, i); |
2952 | RTVEC_ELT (new_vec, vec_len) = set_attr; |
2953 | XVEC (insn, 4) = new_vec; |
2954 | } |
2955 | |
2956 | /* This function is called for the elements in the mnemonic hashtable |
2957 | and generates a comma separated list of the mnemonics. */ |
2958 | |
2959 | static int |
2960 | mnemonic_htab_callback (void **slot, void *info ATTRIBUTE_UNUSED) |
2961 | { |
2962 | struct obstack *string_obstack = rtx_reader_ptr->get_string_obstack (); |
2963 | |
2964 | obstack_grow (string_obstack, (char*) *slot, strlen ((char*) *slot)); |
2965 | obstack_1grow (string_obstack, ','); |
2966 | return 1; |
2967 | } |
2968 | |
2969 | /* Generate (set_attr "mnemonic" "..") RTXs and append them to every |
2970 | insn definition in case the back end requests it by defining the |
2971 | mnemonic attribute. The values for the attribute will be extracted |
2972 | from the output patterns of the insn definitions as far as |
2973 | possible. */ |
2974 | |
2975 | static void |
2976 | gen_mnemonic_attr (void) |
2977 | { |
2978 | class queue_elem *elem; |
2979 | rtx mnemonic_attr = NULL; |
2980 | htab_t mnemonic_htab; |
2981 | const char *str, *p; |
2982 | int i; |
2983 | struct obstack *string_obstack = rtx_reader_ptr->get_string_obstack (); |
2984 | |
2985 | if (have_error) |
2986 | return; |
2987 | |
2988 | /* Look for the DEFINE_ATTR for `mnemonic'. */ |
2989 | for (elem = define_attr_queue; elem != *define_attr_tail; elem = elem->next) |
2990 | if (GET_CODE (elem->data) == DEFINE_ATTR |
2991 | && strcmp (XSTR (elem->data, 0), MNEMONIC_ATTR_NAME) == 0) |
2992 | { |
2993 | mnemonic_attr = elem->data; |
2994 | break; |
2995 | } |
2996 | |
2997 | /* A (define_attr "mnemonic" "...") indicates that the back-end |
2998 | wants a mnemonic attribute to be generated. */ |
2999 | if (!mnemonic_attr) |
3000 | return; |
3001 | |
3002 | mnemonic_htab = htab_create_alloc (MNEMONIC_HTAB_SIZE, htab_hash_string, |
3003 | htab_eq_string, 0, xcalloc, free); |
3004 | |
3005 | for (elem = define_insn_queue; elem; elem = elem->next) |
3006 | { |
3007 | rtx insn = elem->data; |
3008 | bool found = false; |
3009 | |
3010 | /* Check if the insn definition already has |
3011 | (set_attr "mnemonic" ...) or (set (attr "mnemonic") ...). */ |
3012 | if (XVEC (insn, 4)) |
3013 | for (i = 0; i < XVECLEN (insn, 4); i++) |
3014 | { |
3015 | rtx set_attr = XVECEXP (insn, 4, i); |
3016 | |
3017 | switch (GET_CODE (set_attr)) |
3018 | { |
3019 | case SET_ATTR: |
3020 | case SET_ATTR_ALTERNATIVE: |
3021 | if (strcmp (XSTR (set_attr, 0), MNEMONIC_ATTR_NAME) == 0) |
3022 | found = true; |
3023 | break; |
3024 | case SET: |
3025 | if (GET_CODE (SET_DEST (set_attr)) == ATTR |
3026 | && strcmp (XSTR (SET_DEST (set_attr), 0), |
3027 | MNEMONIC_ATTR_NAME) == 0) |
3028 | found = true; |
3029 | break; |
3030 | default: |
3031 | break; |
3032 | } |
3033 | } |
3034 | |
3035 | if (!found) |
3036 | gen_mnemonic_setattr (mnemonic_htab, insn); |
3037 | } |
3038 | |
3039 | /* Add the user defined values to the hash table. */ |
3040 | str = XSTR (mnemonic_attr, 1); |
3041 | while ((p = scan_comma_elt (&str)) != NULL) |
3042 | add_mnemonic_string (mnemonic_htab, str: p, len: str - p); |
3043 | |
3044 | htab_traverse (mnemonic_htab, mnemonic_htab_callback, NULL); |
3045 | |
3046 | /* Replace the last ',' with the zero end character. */ |
3047 | *((char *) obstack_next_free (string_obstack) - 1) = '\0'; |
3048 | XSTR (mnemonic_attr, 1) = XOBFINISH (string_obstack, char *); |
3049 | } |
3050 | |
3051 | /* Check if there are DEFINE_ATTRs with the same name. */ |
3052 | static void |
3053 | check_define_attr_duplicates () |
3054 | { |
3055 | class queue_elem *elem; |
3056 | htab_t attr_htab; |
3057 | char * attr_name; |
3058 | void **slot; |
3059 | |
3060 | attr_htab = htab_create (500, htab_hash_string, htab_eq_string, NULL); |
3061 | |
3062 | for (elem = define_attr_queue; elem; elem = elem->next) |
3063 | { |
3064 | attr_name = xstrdup (XSTR (elem->data, 0)); |
3065 | |
3066 | slot = htab_find_slot (attr_htab, attr_name, INSERT); |
3067 | |
3068 | /* Duplicate. */ |
3069 | if (*slot) |
3070 | { |
3071 | error_at (elem->loc, "redefinition of attribute '%s'" , attr_name); |
3072 | htab_delete (attr_htab); |
3073 | return; |
3074 | } |
3075 | |
3076 | *slot = attr_name; |
3077 | } |
3078 | |
3079 | htab_delete (attr_htab); |
3080 | } |
3081 | |
3082 | /* The entry point for initializing the reader. */ |
3083 | |
3084 | rtx_reader * |
3085 | init_rtx_reader_args_cb (int argc, const char **argv, |
3086 | bool (*parse_opt) (const char *)) |
3087 | { |
3088 | /* Prepare to read input. */ |
3089 | condition_table = htab_create (500, hash_c_test, cmp_c_test, NULL); |
3090 | init_predicate_table (); |
3091 | obstack_init (rtl_obstack); |
3092 | |
3093 | /* Start at 1, to make 0 available for CODE_FOR_nothing. */ |
3094 | insn_sequence_num = 1; |
3095 | |
3096 | /* These sequences are not used as indices, so can start at 1 also. */ |
3097 | split_sequence_num = 1; |
3098 | peephole2_sequence_num = 1; |
3099 | |
3100 | gen_reader *reader = new gen_reader (); |
3101 | reader->read_md_files (argc, argv, parse_opt); |
3102 | |
3103 | if (define_attr_queue != NULL) |
3104 | check_define_attr_duplicates (); |
3105 | |
3106 | /* Process define_cond_exec patterns. */ |
3107 | if (define_cond_exec_queue != NULL) |
3108 | process_define_cond_exec (); |
3109 | |
3110 | /* Process define_subst patterns. */ |
3111 | if (define_subst_queue != NULL) |
3112 | process_define_subst (); |
3113 | |
3114 | if (define_attr_queue != NULL) |
3115 | gen_mnemonic_attr (); |
3116 | |
3117 | if (have_error) |
3118 | { |
3119 | delete reader; |
3120 | return NULL; |
3121 | } |
3122 | |
3123 | return reader; |
3124 | } |
3125 | |
3126 | /* Programs that don't have their own options can use this entry point |
3127 | instead. */ |
3128 | rtx_reader * |
3129 | init_rtx_reader_args (int argc, const char **argv) |
3130 | { |
3131 | return init_rtx_reader_args_cb (argc, argv, parse_opt: 0); |
3132 | } |
3133 | |
3134 | /* Count the number of patterns in all queues and return the count. */ |
3135 | int |
3136 | count_patterns () |
3137 | { |
3138 | int count = 0, truth = 1; |
3139 | rtx def; |
3140 | class queue_elem *cur = define_attr_queue; |
3141 | while (cur) |
3142 | { |
3143 | def = cur->data; |
3144 | |
3145 | truth = maybe_eval_c_test (get_c_test (def)); |
3146 | if (truth || !insn_elision) |
3147 | count++; |
3148 | cur = cur->next; |
3149 | } |
3150 | |
3151 | cur = define_pred_queue; |
3152 | while (cur) |
3153 | { |
3154 | def = cur->data; |
3155 | |
3156 | truth = maybe_eval_c_test (get_c_test (def)); |
3157 | if (truth || !insn_elision) |
3158 | count++; |
3159 | cur = cur->next; |
3160 | } |
3161 | |
3162 | cur = define_insn_queue; |
3163 | truth = 1; |
3164 | while (cur) |
3165 | { |
3166 | def = cur->data; |
3167 | |
3168 | truth = maybe_eval_c_test (get_c_test (def)); |
3169 | if (truth || !insn_elision) |
3170 | count++; |
3171 | cur = cur->next; |
3172 | } |
3173 | |
3174 | cur = other_queue; |
3175 | truth = 1; |
3176 | while (cur) |
3177 | { |
3178 | def = cur->data; |
3179 | |
3180 | truth = maybe_eval_c_test (get_c_test (def)); |
3181 | if (truth || !insn_elision) |
3182 | count++; |
3183 | cur = cur->next; |
3184 | } |
3185 | |
3186 | return count; |
3187 | } |
3188 | |
3189 | /* Try to read a single rtx from the file. Return true on success, |
3190 | describing it in *INFO. */ |
3191 | |
3192 | bool |
3193 | read_md_rtx (md_rtx_info *info) |
3194 | { |
3195 | int truth, *counter; |
3196 | rtx def; |
3197 | |
3198 | /* Discard insn patterns which we know can never match (because |
3199 | their C test is provably always false). If insn_elision is |
3200 | false, our caller needs to see all the patterns. Note that the |
3201 | elided patterns are never counted by the sequence numbering; it |
3202 | is the caller's responsibility, when insn_elision is false, not |
3203 | to use elided pattern numbers for anything. */ |
3204 | do |
3205 | { |
3206 | class queue_elem **queue, *elem; |
3207 | |
3208 | /* Read all patterns from a given queue before moving on to the next. */ |
3209 | if (define_attr_queue != NULL) |
3210 | queue = &define_attr_queue; |
3211 | else if (define_pred_queue != NULL) |
3212 | queue = &define_pred_queue; |
3213 | else if (define_insn_queue != NULL) |
3214 | queue = &define_insn_queue; |
3215 | else if (other_queue != NULL) |
3216 | queue = &other_queue; |
3217 | else |
3218 | return false; |
3219 | |
3220 | elem = *queue; |
3221 | *queue = elem->next; |
3222 | def = elem->data; |
3223 | info->def = def; |
3224 | info->loc = elem->loc; |
3225 | free (ptr: elem); |
3226 | |
3227 | truth = maybe_eval_c_test (get_c_test (def)); |
3228 | } |
3229 | while (truth == 0 && insn_elision); |
3230 | |
3231 | /* Perform code-specific processing and pick the appropriate sequence |
3232 | number counter. */ |
3233 | switch (GET_CODE (def)) |
3234 | { |
3235 | case DEFINE_INSN: |
3236 | case DEFINE_EXPAND: |
3237 | /* insn_sequence_num is used here so the name table will match caller's |
3238 | idea of insn numbering, whether or not elision is active. */ |
3239 | record_insn_name (insn_sequence_num, XSTR (def, 0)); |
3240 | |
3241 | /* Fall through. */ |
3242 | case DEFINE_PEEPHOLE: |
3243 | counter = &insn_sequence_num; |
3244 | break; |
3245 | |
3246 | case DEFINE_SPLIT: |
3247 | counter = &split_sequence_num; |
3248 | break; |
3249 | |
3250 | case DEFINE_PEEPHOLE2: |
3251 | counter = &peephole2_sequence_num; |
3252 | break; |
3253 | |
3254 | default: |
3255 | counter = NULL; |
3256 | break; |
3257 | } |
3258 | |
3259 | if (counter) |
3260 | { |
3261 | info->index = *counter; |
3262 | if (truth != 0) |
3263 | *counter += 1; |
3264 | } |
3265 | else |
3266 | info->index = -1; |
3267 | |
3268 | if (!rtx_locs) |
3269 | rtx_locs = new hash_map <rtx, file_location>; |
3270 | rtx_locs->put (k: info->def, v: info->loc); |
3271 | |
3272 | return true; |
3273 | } |
3274 | |
3275 | /* Return the file location of DEFINE_* rtx X, which was previously |
3276 | returned by read_md_rtx. */ |
3277 | file_location |
3278 | get_file_location (rtx x) |
3279 | { |
3280 | gcc_assert (rtx_locs); |
3281 | file_location *entry = rtx_locs->get (k: x); |
3282 | gcc_assert (entry); |
3283 | return *entry; |
3284 | } |
3285 | |
3286 | /* Return the number of possible INSN_CODEs. Only meaningful once the |
3287 | whole file has been processed. */ |
3288 | unsigned int |
3289 | get_num_insn_codes () |
3290 | { |
3291 | return insn_sequence_num; |
3292 | } |
3293 | |
3294 | /* Return the C test that says whether definition rtx DEF can be used, |
3295 | or "" if it can be used unconditionally. */ |
3296 | |
3297 | const char * |
3298 | get_c_test (rtx x) |
3299 | { |
3300 | switch (GET_CODE (x)) |
3301 | { |
3302 | case DEFINE_INSN: |
3303 | case DEFINE_EXPAND: |
3304 | case DEFINE_SUBST: |
3305 | return XSTR (x, 2); |
3306 | |
3307 | case DEFINE_SPLIT: |
3308 | case DEFINE_PEEPHOLE: |
3309 | case DEFINE_PEEPHOLE2: |
3310 | return XSTR (x, 1); |
3311 | |
3312 | default: |
3313 | return "" ; |
3314 | } |
3315 | } |
3316 | |
3317 | /* Helper functions for insn elision. */ |
3318 | |
3319 | /* Compute a hash function of a c_test structure, which is keyed |
3320 | by its ->expr field. */ |
3321 | hashval_t |
3322 | hash_c_test (const void *x) |
3323 | { |
3324 | const struct c_test *a = (const struct c_test *) x; |
3325 | const unsigned char *base, *s = (const unsigned char *) a->expr; |
3326 | hashval_t hash; |
3327 | unsigned char c; |
3328 | unsigned int len; |
3329 | |
3330 | base = s; |
3331 | hash = 0; |
3332 | |
3333 | while ((c = *s++) != '\0') |
3334 | { |
3335 | hash += c + (c << 17); |
3336 | hash ^= hash >> 2; |
3337 | } |
3338 | |
3339 | len = s - base; |
3340 | hash += len + (len << 17); |
3341 | hash ^= hash >> 2; |
3342 | |
3343 | return hash; |
3344 | } |
3345 | |
3346 | /* Compare two c_test expression structures. */ |
3347 | int |
3348 | cmp_c_test (const void *x, const void *y) |
3349 | { |
3350 | const struct c_test *a = (const struct c_test *) x; |
3351 | const struct c_test *b = (const struct c_test *) y; |
3352 | |
3353 | return !strcmp (s1: a->expr, s2: b->expr); |
3354 | } |
3355 | |
3356 | /* Given a string representing a C test expression, look it up in the |
3357 | condition_table and report whether or not its value is known |
3358 | at compile time. Returns a tristate: 1 for known true, 0 for |
3359 | known false, -1 for unknown. */ |
3360 | int |
3361 | maybe_eval_c_test (const char *expr) |
3362 | { |
3363 | const struct c_test *test; |
3364 | struct c_test dummy; |
3365 | |
3366 | if (expr[0] == 0) |
3367 | return 1; |
3368 | |
3369 | dummy.expr = expr; |
3370 | test = (const struct c_test *)htab_find (condition_table, &dummy); |
3371 | if (!test) |
3372 | return -1; |
3373 | return test->value; |
3374 | } |
3375 | |
3376 | /* Record the C test expression EXPR in the condition_table, with |
3377 | value VAL. Duplicates clobber previous entries. */ |
3378 | |
3379 | void |
3380 | add_c_test (const char *expr, int value) |
3381 | { |
3382 | struct c_test *test; |
3383 | |
3384 | if (expr[0] == 0) |
3385 | return; |
3386 | |
3387 | test = XNEW (struct c_test); |
3388 | test->expr = expr; |
3389 | test->value = value; |
3390 | |
3391 | *(htab_find_slot (condition_table, test, INSERT)) = test; |
3392 | } |
3393 | |
3394 | /* For every C test, call CALLBACK with two arguments: a pointer to |
3395 | the condition structure and INFO. Stops when CALLBACK returns zero. */ |
3396 | void |
3397 | traverse_c_tests (htab_trav callback, void *info) |
3398 | { |
3399 | if (condition_table) |
3400 | htab_traverse (condition_table, callback, info); |
3401 | } |
3402 | |
3403 | /* Helper functions for define_predicate and define_special_predicate |
3404 | processing. Shared between genrecog.cc and genpreds.cc. */ |
3405 | |
3406 | static htab_t predicate_table; |
3407 | struct pred_data *first_predicate; |
3408 | static struct pred_data **last_predicate = &first_predicate; |
3409 | |
3410 | static hashval_t |
3411 | hash_struct_pred_data (const void *ptr) |
3412 | { |
3413 | return htab_hash_string (((const struct pred_data *)ptr)->name); |
3414 | } |
3415 | |
3416 | static int |
3417 | eq_struct_pred_data (const void *a, const void *b) |
3418 | { |
3419 | return !strcmp (s1: ((const struct pred_data *)a)->name, |
3420 | s2: ((const struct pred_data *)b)->name); |
3421 | } |
3422 | |
3423 | struct pred_data * |
3424 | lookup_predicate (const char *name) |
3425 | { |
3426 | struct pred_data key; |
3427 | key.name = name; |
3428 | return (struct pred_data *) htab_find (predicate_table, &key); |
3429 | } |
3430 | |
3431 | /* Record that predicate PRED can accept CODE. */ |
3432 | |
3433 | void |
3434 | add_predicate_code (struct pred_data *pred, enum rtx_code code) |
3435 | { |
3436 | if (!pred->codes[code]) |
3437 | { |
3438 | pred->num_codes++; |
3439 | pred->codes[code] = true; |
3440 | |
3441 | if (GET_RTX_CLASS (code) != RTX_CONST_OBJ) |
3442 | pred->allows_non_const = true; |
3443 | |
3444 | if (code != REG |
3445 | && code != SUBREG |
3446 | && code != MEM |
3447 | && code != CONCAT |
3448 | && code != PARALLEL |
3449 | && code != STRICT_LOW_PART |
3450 | && code != ZERO_EXTRACT |
3451 | && code != SCRATCH) |
3452 | pred->allows_non_lvalue = true; |
3453 | |
3454 | if (pred->num_codes == 1) |
3455 | pred->singleton = code; |
3456 | else if (pred->num_codes == 2) |
3457 | pred->singleton = UNKNOWN; |
3458 | } |
3459 | } |
3460 | |
3461 | void |
3462 | add_predicate (struct pred_data *pred) |
3463 | { |
3464 | void **slot = htab_find_slot (predicate_table, pred, INSERT); |
3465 | if (*slot) |
3466 | { |
3467 | error ("duplicate predicate definition for '%s'" , pred->name); |
3468 | return; |
3469 | } |
3470 | *slot = pred; |
3471 | *last_predicate = pred; |
3472 | last_predicate = &pred->next; |
3473 | } |
3474 | |
3475 | /* This array gives the initial content of the predicate table. It |
3476 | has entries for all predicates defined in recog.cc. */ |
3477 | |
3478 | struct std_pred_table |
3479 | { |
3480 | const char *name; |
3481 | bool special; |
3482 | bool allows_const_p; |
3483 | RTX_CODE codes[NUM_RTX_CODE]; |
3484 | }; |
3485 | |
3486 | static const struct std_pred_table std_preds[] = { |
3487 | {.name: "general_operand" , .special: false, .allows_const_p: true, .codes: {SUBREG, REG, MEM}}, |
3488 | {.name: "address_operand" , .special: true, .allows_const_p: true, .codes: {SUBREG, REG, MEM, PLUS, MINUS, MULT, |
3489 | ZERO_EXTEND, SIGN_EXTEND, AND}}, |
3490 | {.name: "register_operand" , .special: false, .allows_const_p: false, .codes: {SUBREG, REG}}, |
3491 | {.name: "pmode_register_operand" , .special: true, .allows_const_p: false, .codes: {SUBREG, REG}}, |
3492 | {.name: "scratch_operand" , .special: false, .allows_const_p: false, .codes: {SCRATCH, REG}}, |
3493 | {.name: "immediate_operand" , .special: false, .allows_const_p: true, .codes: {UNKNOWN}}, |
3494 | {.name: "const_int_operand" , .special: false, .allows_const_p: false, .codes: {CONST_INT}}, |
3495 | #if TARGET_SUPPORTS_WIDE_INT |
3496 | {.name: "const_scalar_int_operand" , .special: false, .allows_const_p: false, .codes: {CONST_INT, CONST_WIDE_INT}}, |
3497 | {.name: "const_double_operand" , .special: false, .allows_const_p: false, .codes: {CONST_DOUBLE}}, |
3498 | #else |
3499 | {"const_double_operand" , false, false, {CONST_INT, CONST_DOUBLE}}, |
3500 | #endif |
3501 | {.name: "nonimmediate_operand" , .special: false, .allows_const_p: false, .codes: {SUBREG, REG, MEM}}, |
3502 | {.name: "nonmemory_operand" , .special: false, .allows_const_p: true, .codes: {SUBREG, REG}}, |
3503 | {.name: "push_operand" , .special: false, .allows_const_p: false, .codes: {MEM}}, |
3504 | {.name: "pop_operand" , .special: false, .allows_const_p: false, .codes: {MEM}}, |
3505 | {.name: "memory_operand" , .special: false, .allows_const_p: false, .codes: {SUBREG, MEM}}, |
3506 | {.name: "indirect_operand" , .special: false, .allows_const_p: false, .codes: {SUBREG, MEM}}, |
3507 | {.name: "ordered_comparison_operator" , .special: false, .allows_const_p: false, .codes: {EQ, NE, |
3508 | LE, LT, GE, GT, |
3509 | LEU, LTU, GEU, GTU}}, |
3510 | {.name: "comparison_operator" , .special: false, .allows_const_p: false, .codes: {EQ, NE, |
3511 | LE, LT, GE, GT, |
3512 | LEU, LTU, GEU, GTU, |
3513 | UNORDERED, ORDERED, |
3514 | UNEQ, UNGE, UNGT, |
3515 | UNLE, UNLT, LTGT}} |
3516 | }; |
3517 | #define NUM_KNOWN_STD_PREDS ARRAY_SIZE (std_preds) |
3518 | |
3519 | /* Initialize the table of predicate definitions, starting with |
3520 | the information we have on generic predicates. */ |
3521 | |
3522 | static void |
3523 | init_predicate_table (void) |
3524 | { |
3525 | size_t i, j; |
3526 | struct pred_data *pred; |
3527 | |
3528 | predicate_table = htab_create_alloc (37, hash_struct_pred_data, |
3529 | eq_struct_pred_data, 0, |
3530 | xcalloc, free); |
3531 | |
3532 | for (i = 0; i < NUM_KNOWN_STD_PREDS; i++) |
3533 | { |
3534 | pred = XCNEW (struct pred_data); |
3535 | pred->name = std_preds[i].name; |
3536 | pred->special = std_preds[i].special; |
3537 | |
3538 | for (j = 0; std_preds[i].codes[j] != 0; j++) |
3539 | add_predicate_code (pred, code: std_preds[i].codes[j]); |
3540 | |
3541 | if (std_preds[i].allows_const_p) |
3542 | for (j = 0; j < NUM_RTX_CODE; j++) |
3543 | if (GET_RTX_CLASS (j) == RTX_CONST_OBJ) |
3544 | add_predicate_code (pred, code: (enum rtx_code) j); |
3545 | |
3546 | add_predicate (pred); |
3547 | } |
3548 | } |
3549 | |
3550 | /* These functions allow linkage with print-rtl.cc. Also, some generators |
3551 | like to annotate their output with insn names. */ |
3552 | |
3553 | /* Holds an array of names indexed by insn_code_number. */ |
3554 | static char **insn_name_ptr = 0; |
3555 | static int insn_name_ptr_size = 0; |
3556 | |
3557 | const char * |
3558 | get_insn_name (int code) |
3559 | { |
3560 | if (code < insn_name_ptr_size) |
3561 | return insn_name_ptr[code]; |
3562 | else |
3563 | return NULL; |
3564 | } |
3565 | |
3566 | static void |
3567 | record_insn_name (int code, const char *name) |
3568 | { |
3569 | static const char *last_real_name = "insn" ; |
3570 | static int last_real_code = 0; |
3571 | char *new_name; |
3572 | |
3573 | if (insn_name_ptr_size <= code) |
3574 | { |
3575 | int new_size; |
3576 | new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512); |
3577 | insn_name_ptr = XRESIZEVEC (char *, insn_name_ptr, new_size); |
3578 | memset (s: insn_name_ptr + insn_name_ptr_size, c: 0, |
3579 | n: sizeof (char *) * (new_size - insn_name_ptr_size)); |
3580 | insn_name_ptr_size = new_size; |
3581 | } |
3582 | |
3583 | if (!name || name[0] == '\0') |
3584 | { |
3585 | new_name = XNEWVAR (char, strlen (last_real_name) + 10); |
3586 | sprintf (s: new_name, format: "%s+%d" , last_real_name, code - last_real_code); |
3587 | } |
3588 | else |
3589 | { |
3590 | last_real_name = new_name = xstrdup (name); |
3591 | last_real_code = code; |
3592 | } |
3593 | |
3594 | insn_name_ptr[code] = new_name; |
3595 | } |
3596 | |
3597 | /* Make STATS describe the operands that appear in rtx X. */ |
3598 | |
3599 | static void |
3600 | get_pattern_stats_1 (struct pattern_stats *stats, rtx x) |
3601 | { |
3602 | RTX_CODE code; |
3603 | int i; |
3604 | int len; |
3605 | const char *fmt; |
3606 | |
3607 | if (x == NULL_RTX) |
3608 | return; |
3609 | |
3610 | code = GET_CODE (x); |
3611 | switch (code) |
3612 | { |
3613 | case MATCH_OPERAND: |
3614 | case MATCH_OPERATOR: |
3615 | case MATCH_PARALLEL: |
3616 | stats->max_opno = MAX (stats->max_opno, XINT (x, 0)); |
3617 | break; |
3618 | |
3619 | case MATCH_DUP: |
3620 | case MATCH_OP_DUP: |
3621 | case MATCH_PAR_DUP: |
3622 | stats->num_dups++; |
3623 | stats->max_dup_opno = MAX (stats->max_dup_opno, XINT (x, 0)); |
3624 | break; |
3625 | |
3626 | case MATCH_SCRATCH: |
3627 | if (stats->min_scratch_opno == -1) |
3628 | stats->min_scratch_opno = XINT (x, 0); |
3629 | else |
3630 | stats->min_scratch_opno = MIN (stats->min_scratch_opno, XINT (x, 0)); |
3631 | stats->max_scratch_opno = MAX (stats->max_scratch_opno, XINT (x, 0)); |
3632 | break; |
3633 | |
3634 | default: |
3635 | break; |
3636 | } |
3637 | |
3638 | fmt = GET_RTX_FORMAT (code); |
3639 | len = GET_RTX_LENGTH (code); |
3640 | for (i = 0; i < len; i++) |
3641 | { |
3642 | if (fmt[i] == 'e' || fmt[i] == 'u') |
3643 | get_pattern_stats_1 (stats, XEXP (x, i)); |
3644 | else if (fmt[i] == 'E') |
3645 | { |
3646 | int j; |
3647 | for (j = 0; j < XVECLEN (x, i); j++) |
3648 | get_pattern_stats_1 (stats, XVECEXP (x, i, j)); |
3649 | } |
3650 | } |
3651 | } |
3652 | |
3653 | /* Make STATS describe the operands that appear in instruction pattern |
3654 | PATTERN. */ |
3655 | |
3656 | void |
3657 | get_pattern_stats (struct pattern_stats *stats, rtvec pattern) |
3658 | { |
3659 | int i, len; |
3660 | |
3661 | stats->max_opno = -1; |
3662 | stats->max_dup_opno = -1; |
3663 | stats->min_scratch_opno = -1; |
3664 | stats->max_scratch_opno = -1; |
3665 | stats->num_dups = 0; |
3666 | |
3667 | len = GET_NUM_ELEM (pattern); |
3668 | for (i = 0; i < len; i++) |
3669 | get_pattern_stats_1 (stats, RTVEC_ELT (pattern, i)); |
3670 | |
3671 | stats->num_generator_args = stats->max_opno + 1; |
3672 | stats->num_insn_operands = MAX (stats->max_opno, |
3673 | stats->max_scratch_opno) + 1; |
3674 | stats->num_operand_vars = MAX (stats->max_opno, |
3675 | MAX (stats->max_dup_opno, |
3676 | stats->max_scratch_opno)) + 1; |
3677 | } |
3678 | |
3679 | /* Return the emit_* function that should be used for pattern X, or NULL |
3680 | if we can't pick a particular type at compile time and should instead |
3681 | fall back to "emit". */ |
3682 | |
3683 | const char * |
3684 | get_emit_function (rtx x) |
3685 | { |
3686 | switch (classify_insn (x)) |
3687 | { |
3688 | case INSN: |
3689 | return "emit_insn" ; |
3690 | |
3691 | case CALL_INSN: |
3692 | return "emit_call_insn" ; |
3693 | |
3694 | case JUMP_INSN: |
3695 | return "emit_jump_insn" ; |
3696 | |
3697 | case UNKNOWN: |
3698 | return NULL; |
3699 | |
3700 | default: |
3701 | gcc_unreachable (); |
3702 | } |
3703 | } |
3704 | |
3705 | /* Return true if we must emit a barrier after pattern X. */ |
3706 | |
3707 | bool |
3708 | needs_barrier_p (rtx x) |
3709 | { |
3710 | return (GET_CODE (x) == SET |
3711 | && GET_CODE (SET_DEST (x)) == PC |
3712 | && GET_CODE (SET_SRC (x)) == LABEL_REF); |
3713 | } |
3714 | |
3715 | #define NS "NULL" |
3716 | #define ZS "'\\0'" |
3717 | #define OPTAB_CL(o, p, c, b, l) { #o, p, #b, ZS, #l, o, c, UNKNOWN, 1 }, |
3718 | #define OPTAB_CX(o, p) { #o, p, NULL, NULL, NULL, o, UNKNOWN, UNKNOWN, 1 }, |
3719 | #define OPTAB_CD(o, p) { #o, p, NS, ZS, NS, o, UNKNOWN, UNKNOWN, 2 }, |
3720 | #define OPTAB_NL(o, p, c, b, s, l) { #o, p, #b, #s, #l, o, c, c, 3 }, |
3721 | #define OPTAB_NC(o, p, c) { #o, p, NS, ZS, NS, o, c, c, 3 }, |
3722 | #define OPTAB_NX(o, p) { #o, p, NULL, NULL, NULL, o, UNKNOWN, UNKNOWN, 3 }, |
3723 | #define OPTAB_VL(o, p, c, b, s, l) { #o, p, #b, #s, #l, o, c, UNKNOWN, 3 }, |
3724 | #define OPTAB_VC(o, p, c) { #o, p, NS, ZS, NS, o, c, UNKNOWN, 3 }, |
3725 | #define OPTAB_VX(o, p) { #o, p, NULL, NULL, NULL, o, UNKNOWN, UNKNOWN, 3 }, |
3726 | #define OPTAB_DC(o, p, c) { #o, p, NS, ZS, NS, o, c, c, 4 }, |
3727 | #define OPTAB_D(o, p) { #o, p, NS, ZS, NS, o, UNKNOWN, UNKNOWN, 4 }, |
3728 | |
3729 | /* An array of all optabs. Note that the same optab can appear more |
3730 | than once, with a different pattern. */ |
3731 | optab_def optabs[] = { |
3732 | { .name: "unknown_optab" , NULL, NS, ZS, NS, .op: unknown_optab, .fcode: UNKNOWN, .rcode: UNKNOWN, .kind: 0 }, |
3733 | #include "optabs.def" |
3734 | }; |
3735 | |
3736 | /* The number of entries in optabs[]. */ |
3737 | unsigned int num_optabs = ARRAY_SIZE (optabs); |
3738 | |
3739 | #undef OPTAB_CL |
3740 | #undef OPTAB_CX |
3741 | #undef OPTAB_CD |
3742 | #undef OPTAB_NL |
3743 | #undef OPTAB_NC |
3744 | #undef OPTAB_NX |
3745 | #undef OPTAB_VL |
3746 | #undef OPTAB_VC |
3747 | #undef OPTAB_VX |
3748 | #undef OPTAB_DC |
3749 | #undef OPTAB_D |
3750 | |
3751 | /* Return true if instruction NAME matches pattern PAT, storing information |
3752 | about the match in P if so. */ |
3753 | |
3754 | static bool |
3755 | match_pattern (optab_pattern *p, const char *name, const char *pat) |
3756 | { |
3757 | bool force_float = false; |
3758 | bool force_int = false; |
3759 | bool force_partial_int = false; |
3760 | bool force_fixed = false; |
3761 | |
3762 | if (pat == NULL) |
3763 | return false; |
3764 | for (; ; ++pat) |
3765 | { |
3766 | if (*pat != '$') |
3767 | { |
3768 | if (*pat != *name++) |
3769 | return false; |
3770 | if (*pat == '\0') |
3771 | return true; |
3772 | continue; |
3773 | } |
3774 | switch (*++pat) |
3775 | { |
3776 | case 'I': |
3777 | force_int = 1; |
3778 | break; |
3779 | case 'P': |
3780 | force_partial_int = 1; |
3781 | break; |
3782 | case 'F': |
3783 | force_float = 1; |
3784 | break; |
3785 | case 'Q': |
3786 | force_fixed = 1; |
3787 | break; |
3788 | |
3789 | case 'a': |
3790 | case 'b': |
3791 | { |
3792 | int i; |
3793 | |
3794 | /* This loop will stop at the first prefix match, so |
3795 | look through the modes in reverse order, in case |
3796 | there are extra CC modes and CC is a prefix of the |
3797 | CC modes (as it should be). */ |
3798 | for (i = (MAX_MACHINE_MODE) - 1; i >= 0; i--) |
3799 | { |
3800 | const char *p, *q; |
3801 | for (p = GET_MODE_NAME (i), q = name; *p; p++, q++) |
3802 | if (TOLOWER (*p) != *q) |
3803 | break; |
3804 | if (*p == 0 |
3805 | && (! force_int || mode_class[i] == MODE_INT |
3806 | || mode_class[i] == MODE_VECTOR_INT) |
3807 | && (! force_partial_int |
3808 | || mode_class[i] == MODE_INT |
3809 | || mode_class[i] == MODE_PARTIAL_INT |
3810 | || mode_class[i] == MODE_VECTOR_INT) |
3811 | && (! force_float |
3812 | || mode_class[i] == MODE_FLOAT |
3813 | || mode_class[i] == MODE_DECIMAL_FLOAT |
3814 | || mode_class[i] == MODE_COMPLEX_FLOAT |
3815 | || mode_class[i] == MODE_VECTOR_FLOAT) |
3816 | && (! force_fixed |
3817 | || mode_class[i] == MODE_FRACT |
3818 | || mode_class[i] == MODE_UFRACT |
3819 | || mode_class[i] == MODE_ACCUM |
3820 | || mode_class[i] == MODE_UACCUM |
3821 | || mode_class[i] == MODE_VECTOR_FRACT |
3822 | || mode_class[i] == MODE_VECTOR_UFRACT |
3823 | || mode_class[i] == MODE_VECTOR_ACCUM |
3824 | || mode_class[i] == MODE_VECTOR_UACCUM)) |
3825 | break; |
3826 | } |
3827 | |
3828 | if (i < 0) |
3829 | return false; |
3830 | name += strlen (GET_MODE_NAME (i)); |
3831 | if (*pat == 'a') |
3832 | p->m1 = i; |
3833 | else |
3834 | p->m2 = i; |
3835 | |
3836 | force_int = false; |
3837 | force_partial_int = false; |
3838 | force_float = false; |
3839 | force_fixed = false; |
3840 | } |
3841 | break; |
3842 | |
3843 | default: |
3844 | gcc_unreachable (); |
3845 | } |
3846 | } |
3847 | } |
3848 | |
3849 | /* Return true if NAME is the name of an optab, describing it in P if so. */ |
3850 | |
3851 | bool |
3852 | find_optab (optab_pattern *p, const char *name) |
3853 | { |
3854 | if (*name == 0 || *name == '*') |
3855 | return false; |
3856 | |
3857 | /* See if NAME matches one of the patterns we have for the optabs |
3858 | we know about. */ |
3859 | for (unsigned int pindex = 0; pindex < ARRAY_SIZE (optabs); pindex++) |
3860 | { |
3861 | p->m1 = p->m2 = 0; |
3862 | if (match_pattern (p, name, pat: optabs[pindex].pattern)) |
3863 | { |
3864 | p->name = name; |
3865 | p->op = optabs[pindex].op; |
3866 | p->sort_num = (p->op << 20) | (p->m2 << 10) | p->m1; |
3867 | return true; |
3868 | } |
3869 | } |
3870 | return false; |
3871 | } |
3872 | |