Line data Source code
1 : /* Declarations for interface to insn recognizer and insn-output.cc.
2 : Copyright (C) 1987-2026 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 under
7 : the terms of the GNU General Public License as published by the Free
8 : Software Foundation; either version 3, or (at your option) any later
9 : version.
10 :
11 : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 : WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 : 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 : #ifndef GCC_RECOG_H
21 : #define GCC_RECOG_H
22 :
23 : /* For enum tree_code ERROR_MARK. */
24 : #include "tree.h"
25 :
26 : /* Random number that should be large enough for all purposes. Also define
27 : a type that has at least MAX_RECOG_ALTERNATIVES + 1 bits, with the extra
28 : bit giving an invalid value that can be used to mean "uninitialized". */
29 : #define MAX_RECOG_ALTERNATIVES 35
30 : typedef uint64_t alternative_mask; /* Keep in sync with genattrtab.cc. */
31 :
32 : /* A mask of all alternatives. */
33 : #define ALL_ALTERNATIVES ((alternative_mask) -1)
34 :
35 : /* A mask containing just alternative X. */
36 : #define ALTERNATIVE_BIT(X) ((alternative_mask) 1 << (X))
37 :
38 : /* Types of operands. */
39 : enum op_type {
40 : OP_IN,
41 : OP_OUT,
42 : OP_INOUT
43 : };
44 :
45 : #ifndef GENERATOR_FILE
46 : struct operand_alternative
47 : {
48 : /* Pointer to the beginning of the constraint string for this alternative,
49 : for easier access by alternative number. */
50 : const char *constraint;
51 :
52 : /* The register class valid for this alternative (possibly NO_REGS). */
53 : enum reg_class cl : 16;
54 :
55 : /* "Badness" of this alternative, computed from number of '?' and '!'
56 : characters in the constraint string. */
57 : unsigned int reject : 16;
58 :
59 : /* -1 if no matching constraint was found, or an operand number. */
60 : int matches : 8;
61 : /* The same information, but reversed: -1 if this operand is not
62 : matched by any other, or the operand number of the operand that
63 : matches this one. */
64 : int matched : 8;
65 :
66 : /* Bit ID is set if the constraint string includes a register constraint with
67 : register filter ID. Use test_register_filters (REGISTER_FILTERS, REGNO)
68 : to test whether REGNO is a valid start register for the operand. */
69 : unsigned int register_filters : MAX (NUM_REGISTER_FILTERS, 1);
70 :
71 : /* Bit ID is set if the constraint string includes a dependent
72 : register constraint with dependent-filter id ID. */
73 : unsigned int dependent_filters : MAX (NUM_DEPENDENT_FILTERS, 1);
74 :
75 : /* Nonzero if '&' was found in the constraint string. */
76 : unsigned int earlyclobber : 1;
77 : /* Nonzero if TARGET_MEM_CONSTRAINT was found in the constraint
78 : string. */
79 : unsigned int memory_ok : 1;
80 : /* Nonzero if 'p' was found in the constraint string. */
81 : unsigned int is_address : 1;
82 : /* Nonzero if 'X' was found in the constraint string, or if the constraint
83 : string for this alternative was empty. */
84 : unsigned int anything_ok : 1;
85 : };
86 :
87 : /* Return the class for operand I of alternative ALT, taking matching
88 : constraints into account. */
89 :
90 : inline enum reg_class
91 186024595 : alternative_class (const operand_alternative *alt, int i)
92 : {
93 186024595 : return alt[i].matches >= 0 ? alt[alt[i].matches].cl : alt[i].cl;
94 : }
95 :
96 : /* Return the mask of register filters that should be applied to operand I
97 : of alternative ALT, taking matching constraints into account. */
98 :
99 : inline unsigned int
100 95856465 : alternative_register_filters (const operand_alternative *alt, int i)
101 : {
102 95856465 : return (alt[i].matches >= 0
103 95856465 : ? alt[alt[i].matches].register_filters
104 85531662 : : alt[i].register_filters);
105 : }
106 :
107 : /* Return the mask of dynamic register filters that should be applied to
108 : operand I of alternative ALT, taking matching constraints into
109 : account. */
110 :
111 : inline unsigned int
112 : alternative_dependent_filters (const operand_alternative *alt, int i)
113 : {
114 0 : return (alt[i].matches >= 0
115 : ? alt[alt[i].matches].dependent_filters
116 : : alt[i].dependent_filters);
117 : }
118 : #endif
119 :
120 : /* A class for substituting one rtx for another within an instruction,
121 : or for recursively simplifying the instruction as-is. Derived classes
122 : can record or filter certain decisions. */
123 :
124 : class insn_propagation : public simplify_context
125 : {
126 : public:
127 : /* Assignments for RESULT_FLAGS.
128 :
129 : UNSIMPLIFIED is true if a substitution has been made inside an rtx
130 : X and if neither X nor its parent expressions could be simplified.
131 :
132 : FIRST_SPARE_RESULT is the first flag available for derived classes. */
133 : static const uint16_t UNSIMPLIFIED = 1U << 0;
134 : static const uint16_t FIRST_SPARE_RESULT = 1U << 1;
135 :
136 : insn_propagation (rtx_insn *);
137 : insn_propagation (rtx_insn *, rtx, rtx, bool = true);
138 : bool apply_to_pattern (rtx *);
139 : bool apply_to_rvalue (rtx *);
140 : bool apply_to_note (rtx *);
141 :
142 : /* Return true if we should accept a substitution into the address of
143 : memory expression MEM. Undoing changes OLD_NUM_CHANGES and up restores
144 : MEM's original address. */
145 0 : virtual bool check_mem (int /*old_num_changes*/,
146 0 : rtx /*mem*/) { return true; }
147 :
148 : /* Note that we've simplified OLD_RTX into NEW_RTX. When substituting,
149 : this only happens if a substitution occurred within OLD_RTX.
150 : Undoing OLD_NUM_CHANGES and up will restore the old form of OLD_RTX.
151 : OLD_RESULT_FLAGS is the value that RESULT_FLAGS had before processing
152 : OLD_RTX. */
153 0 : virtual void note_simplification (int /*old_num_changes*/,
154 : uint16_t /*old_result_flags*/,
155 0 : rtx /*old_rtx*/, rtx /*new_rtx*/) {}
156 :
157 : private:
158 : bool apply_to_mem_1 (rtx);
159 : bool apply_to_lvalue_1 (rtx);
160 : bool apply_to_rvalue_1 (rtx *);
161 : bool apply_to_pattern_1 (rtx *);
162 :
163 : public:
164 : /* The instruction that we are simplifying or propagating into. */
165 : rtx_insn *insn;
166 :
167 : /* If FROM is nonnull, we're replacing FROM with TO, otherwise we're
168 : just doing a recursive simplification. */
169 : rtx from;
170 : rtx to;
171 :
172 : /* The number of times that we have replaced FROM with TO. */
173 : unsigned int num_replacements;
174 :
175 : /* A bitmask of flags that describe the result of the simplificiation;
176 : see above for details. */
177 : uint16_t result_flags : 16;
178 :
179 : /* True if we should unshare TO when making the next substitution,
180 : false if we can use TO itself. */
181 : uint16_t should_unshare : 1;
182 :
183 : /* True if we should call check_mem after substituting into a memory. */
184 : uint16_t should_check_mems : 1;
185 :
186 : /* True if we should call note_simplification after each simplification. */
187 : uint16_t should_note_simplifications : 1;
188 :
189 : /* For future expansion. */
190 : uint16_t spare : 13;
191 :
192 : /* Gives the reason that a substitution failed, for debug purposes. */
193 : const char *failure_reason;
194 : };
195 :
196 : /* Try to replace FROM with TO in INSN. SHARED_P is true if TO is shared
197 : with other instructions, false if INSN can use TO directly. */
198 :
199 71004291 : inline insn_propagation::insn_propagation (rtx_insn *insn, rtx from, rtx to,
200 : bool shared_p)
201 71004291 : : insn (insn),
202 71004291 : from (from),
203 71004291 : to (to),
204 71004291 : num_replacements (0),
205 71004291 : result_flags (0),
206 71004291 : should_unshare (shared_p),
207 71004291 : should_check_mems (false),
208 71004291 : should_note_simplifications (false),
209 71004291 : spare (0),
210 71004291 : failure_reason (nullptr)
211 : {
212 : }
213 :
214 : /* Try to simplify INSN without performing a substitution. */
215 :
216 3522231 : inline insn_propagation::insn_propagation (rtx_insn *insn)
217 3522231 : : insn_propagation (insn, NULL_RTX, NULL_RTX)
218 : {
219 : }
220 :
221 : /* An RAII class that temporarily undoes part of the current change group.
222 : The sequence:
223 :
224 : {
225 : ...;
226 : undo_recog_changes undo (NUM);
227 : STMTS;
228 : }
229 :
230 : executes STMTS with all the changes numbered NUM and up temporarily
231 : reverted. STMTS must not try to add to the current change group.
232 :
233 : Nested uses are supported, but each nested NUM must be no greater than
234 : outer NUMs. */
235 :
236 : class undo_recog_changes
237 : {
238 : public:
239 : undo_recog_changes (int);
240 : ~undo_recog_changes ();
241 :
242 2795068779 : static bool is_active () { return s_num_changes != 0; }
243 :
244 : private:
245 : int m_old_num_changes;
246 :
247 : static int s_num_changes;
248 : };
249 :
250 : extern void init_recog (void);
251 : extern void init_recog_no_volatile (void);
252 : extern bool check_asm_operands (rtx);
253 : extern int asm_operand_ok (rtx, const char *, const char **);
254 : extern bool validate_change (rtx, rtx *, rtx, bool);
255 : extern bool validate_unshare_change (rtx, rtx *, rtx, bool);
256 : extern bool validate_change_xveclen (rtx, rtx *, int, bool);
257 : extern bool canonicalize_change_group (rtx_insn *insn, rtx x);
258 : extern bool insn_invalid_p (rtx_insn *, bool);
259 : extern bool verify_changes (int);
260 : extern void confirm_change_group (void);
261 : extern bool apply_change_group (void);
262 : extern int num_validated_changes (void);
263 : extern void cancel_changes (int);
264 : extern bool constrain_operands (int, alternative_mask);
265 : extern bool constrain_operands_cached (rtx_insn *, int);
266 : extern bool memory_address_addr_space_p (machine_mode, rtx, addr_space_t,
267 : code_helper = ERROR_MARK);
268 : #define memory_address_p(mode,addr) \
269 : memory_address_addr_space_p ((mode), (addr), ADDR_SPACE_GENERIC)
270 : extern bool strict_memory_address_addr_space_p (machine_mode, rtx, addr_space_t,
271 : code_helper = ERROR_MARK);
272 : #define strict_memory_address_p(mode,addr) \
273 : strict_memory_address_addr_space_p ((mode), (addr), ADDR_SPACE_GENERIC)
274 : extern bool validate_replace_rtx_subexp (rtx, rtx, rtx_insn *, rtx *);
275 : extern bool validate_replace_rtx (rtx, rtx, rtx_insn *);
276 : extern bool validate_replace_rtx_part (rtx, rtx, rtx *, rtx_insn *);
277 : extern bool validate_replace_rtx_part_nosimplify (rtx, rtx, rtx *, rtx_insn *);
278 : extern void validate_replace_rtx_group (rtx, rtx, rtx_insn *);
279 : extern void validate_replace_src_group (rtx, rtx, rtx_insn *);
280 : extern bool validate_simplify_insn (rtx_insn *insn);
281 : extern int num_changes_pending (void);
282 : extern bool reg_fits_class_p (const_rtx, reg_class_t, int, machine_mode);
283 : extern bool valid_insn_p (rtx_insn *);
284 :
285 : extern bool offsettable_memref_p (rtx);
286 : extern bool offsettable_nonstrict_memref_p (rtx);
287 : extern bool offsettable_address_addr_space_p (int, machine_mode, rtx,
288 : addr_space_t);
289 : #define offsettable_address_p(strict,mode,addr) \
290 : offsettable_address_addr_space_p ((strict), (mode), (addr), \
291 : ADDR_SPACE_GENERIC)
292 : extern bool mode_dependent_address_p (rtx, addr_space_t);
293 :
294 : extern int recog (rtx, rtx_insn *, int *);
295 : #ifndef GENERATOR_FILE
296 : inline int recog_memoized (rtx_insn *insn);
297 : #endif
298 : extern void add_clobbers (rtx, int);
299 : extern bool added_clobbers_hard_reg_p (int);
300 : extern void insn_extract (rtx_insn *);
301 : extern void extract_insn (rtx_insn *);
302 : extern void extract_constrain_insn (rtx_insn *insn);
303 : extern void extract_constrain_insn_cached (rtx_insn *);
304 : extern void extract_insn_cached (rtx_insn *);
305 : #ifndef GENERATOR_FILE
306 : extern void preprocess_constraints (int, int, const char **,
307 : operand_alternative *, rtx **);
308 : extern const operand_alternative *preprocess_insn_constraints (unsigned int);
309 : #endif
310 : extern void preprocess_constraints (rtx_insn *);
311 : extern rtx_insn *peep2_next_insn (int);
312 : extern bool peep2_regno_dead_p (int, int);
313 : extern bool peep2_reg_dead_p (int, rtx);
314 : #ifdef HARD_CONST
315 : extern rtx peep2_find_free_register (int, int, const char *,
316 : machine_mode, HARD_REG_SET *);
317 : #endif
318 : extern rtx_insn *peephole2_insns (rtx, rtx_insn *, int *);
319 :
320 : extern bool store_data_bypass_p (rtx_insn *, rtx_insn *);
321 : extern bool if_test_bypass_p (rtx_insn *, rtx_insn *);
322 :
323 : extern void copy_frame_info_to_split_insn (rtx_insn *, rtx_insn *);
324 :
325 : #ifndef GENERATOR_FILE
326 : /* Try recognizing the instruction INSN,
327 : and return the code number that results.
328 : Remember the code so that repeated calls do not
329 : need to spend the time for actual rerecognition.
330 :
331 : This function is the normal interface to instruction recognition.
332 : The automatically-generated function `recog' is normally called
333 : through this one. */
334 :
335 : inline int
336 17696860416 : recog_memoized (rtx_insn *insn)
337 : {
338 17696860416 : if (INSN_CODE (insn) < 0)
339 751026865 : INSN_CODE (insn) = recog (PATTERN (insn), insn, 0);
340 17696860416 : return INSN_CODE (insn);
341 : }
342 : #endif
343 :
344 : /* Skip chars until the next ',' or the end of the string. This is
345 : useful to skip alternatives in a constraint string. */
346 : inline const char *
347 3306328853 : skip_alternative (const char *p)
348 : {
349 3306328853 : const char *r = p;
350 10252425455 : while (*r != '\0' && *r != ',')
351 6946096602 : r++;
352 3306328853 : if (*r == ',')
353 3073977411 : r++;
354 3306328853 : return r;
355 : }
356 :
357 : /* Nonzero means volatile operands are recognized. */
358 : extern int volatile_ok;
359 :
360 : /* RAII class for temporarily setting volatile_ok. */
361 :
362 : class temporary_volatile_ok
363 : {
364 : public:
365 4654253 : temporary_volatile_ok (int value) : save_volatile_ok (volatile_ok)
366 : {
367 4654253 : volatile_ok = value;
368 : }
369 :
370 4654253 : ~temporary_volatile_ok () { volatile_ok = save_volatile_ok; }
371 :
372 : private:
373 : temporary_volatile_ok (const temporary_volatile_ok &);
374 : int save_volatile_ok;
375 : };
376 :
377 : /* Set by constrain_operands to the number of the alternative that
378 : matched. */
379 : extern int which_alternative;
380 :
381 : /* True for inline asm operands with - constraint modifier. */
382 : extern bool raw_constraint_p;
383 :
384 : /* The following vectors hold the results from insn_extract. */
385 :
386 : struct recog_data_d
387 : {
388 : recog_data_d () = default;
389 : recog_data_d (const recog_data_d &) = delete;
390 : recog_data_d (const recog_data_d &&) = delete;
391 :
392 : /* It is very tempting to make the 5 operand related arrays into a
393 : structure and index on that. However, to be source compatible
394 : with all of the existing md file insn constraints and output
395 : templates, we need `operand' as a flat array. Without that
396 : member, making an array for the rest seems pointless. */
397 :
398 : /* Gives value of operand N. */
399 : rtx operand[MAX_RECOG_OPERANDS];
400 :
401 : /* Gives location where operand N was found. */
402 : rtx *operand_loc[MAX_RECOG_OPERANDS];
403 :
404 : /* Gives the constraint string for operand N. */
405 : const char *constraints[MAX_RECOG_OPERANDS];
406 :
407 : /* Nonzero if operand N is a match_operator or a match_parallel. */
408 : char is_operator[MAX_RECOG_OPERANDS];
409 :
410 : /* Gives the mode of operand N. */
411 : machine_mode operand_mode[MAX_RECOG_OPERANDS];
412 :
413 : /* Gives the type (in, out, inout) for operand N. */
414 : enum op_type operand_type[MAX_RECOG_OPERANDS];
415 :
416 : /* Gives location where the Nth duplicate-appearance of an operand
417 : was found. This is something that matched MATCH_DUP. */
418 : rtx *dup_loc[MAX_DUP_OPERANDS];
419 :
420 : /* Gives the operand number that was duplicated in the Nth
421 : duplicate-appearance of an operand. */
422 : char dup_num[MAX_DUP_OPERANDS];
423 :
424 : /* ??? Note that these are `char' instead of `unsigned char' to (try to)
425 : avoid certain lossage from K&R C, wherein `unsigned char' default
426 : promotes to `unsigned int' instead of `int' as in ISO C. As of 1999,
427 : the most common places to bootstrap from K&R C are SunOS and HPUX,
428 : both of which have signed characters by default. The only other
429 : supported natives that have both K&R C and unsigned characters are
430 : ROMP and Irix 3, and neither have been seen for a while, but do
431 : continue to consider unsignedness when performing arithmetic inside
432 : a comparison. */
433 :
434 : /* The number of operands of the insn. */
435 : char n_operands;
436 :
437 : /* The number of MATCH_DUPs in the insn. */
438 : char n_dups;
439 :
440 : /* The number of alternatives in the constraints for the insn. */
441 : char n_alternatives;
442 :
443 : /* True if insn is ASM_OPERANDS. */
444 : bool is_asm;
445 :
446 : /* In case we are caching, hold insn data was generated for. */
447 : rtx_insn *insn;
448 : };
449 :
450 : extern struct recog_data_d *recog_data_ptr;
451 : #define recog_data (*recog_data_ptr)
452 :
453 : #ifndef GENERATOR_FILE
454 : /* RAII class for saving/restoring recog_data. */
455 :
456 : class recog_state_saver
457 : {
458 : recog_data_d m_tmp_recog_data;
459 : public:
460 : recog_state_saver ();
461 : ~recog_state_saver ();
462 :
463 : recog_data_d *saved_recog_data_ptr;
464 : int saved_alternative;
465 : };
466 :
467 74139424 : inline recog_state_saver::recog_state_saver ()
468 74139424 : : saved_recog_data_ptr (recog_data_ptr),
469 74139424 : saved_alternative (which_alternative)
470 : {
471 74139424 : m_tmp_recog_data.insn = nullptr;
472 74139424 : recog_data_ptr = &m_tmp_recog_data;
473 : }
474 :
475 74139424 : inline recog_state_saver::~recog_state_saver ()
476 : {
477 74139424 : recog_data_ptr = saved_recog_data_ptr;
478 74139424 : which_alternative = saved_alternative;
479 : }
480 :
481 : extern const operand_alternative *recog_op_alt;
482 :
483 : /* Return a pointer to an array in which index OP describes the constraints
484 : on operand OP of the current instruction alternative (which_alternative).
485 : Only valid after calling preprocess_constraints and constrain_operands. */
486 :
487 : inline const operand_alternative *
488 106408035 : which_op_alt ()
489 : {
490 106408035 : gcc_checking_assert (IN_RANGE (which_alternative, 0,
491 : recog_data.n_alternatives - 1));
492 106408035 : return &recog_op_alt[which_alternative * recog_data.n_operands];
493 : }
494 : #endif
495 :
496 : /* A table defined in insn-output.cc that give information about
497 : each insn-code value. */
498 :
499 : typedef bool (*insn_operand_predicate_fn) (rtx, machine_mode);
500 : typedef const char * (*insn_output_fn) (rtx *, rtx_insn *);
501 :
502 : struct insn_gen_fn
503 : {
504 : typedef void (*stored_funcptr) (void);
505 :
506 : template<typename ...Ts>
507 108293829 : rtx_insn *operator() (Ts... args) const
508 : {
509 : typedef rtx_insn *(*funcptr) (decltype ((void) args, NULL_RTX)...);
510 108293829 : return ((funcptr) func) (args...);
511 : }
512 :
513 : // This is for compatibility of code that invokes functions like
514 : // (*funcptr) (arg)
515 : insn_gen_fn operator * (void) const { return *this; }
516 :
517 : // The wrapped function pointer must be public and there must not be any
518 : // constructors. Otherwise the insn_data_d struct initializers generated
519 : // by genoutput.cc will result in static initializer functions, which defeats
520 : // the purpose of the generated insn_data_d array.
521 : stored_funcptr func;
522 : };
523 :
524 : struct insn_operand_data
525 : {
526 : const insn_operand_predicate_fn predicate;
527 :
528 : const char *const constraint;
529 :
530 : machine_mode const mode : 16;
531 :
532 : const char strict_low;
533 :
534 : const char is_operator;
535 :
536 : const char eliminable;
537 :
538 : const char allows_mem;
539 : };
540 :
541 : /* Legal values for insn_data.output_format. Indicate what type of data
542 : is stored in insn_data.output. */
543 : #define INSN_OUTPUT_FORMAT_NONE 0 /* abort */
544 : #define INSN_OUTPUT_FORMAT_SINGLE 1 /* const char * */
545 : #define INSN_OUTPUT_FORMAT_MULTI 2 /* const char * const * */
546 : #define INSN_OUTPUT_FORMAT_FUNCTION 3 /* const char * (*)(...) */
547 :
548 : struct insn_data_d
549 : {
550 : const char *const name;
551 :
552 : /* How to print the insn. OUTPUT_FORMAT says which member is live. The
553 : constructors let genoutput write the member's value directly, and pick
554 : the member from its type. */
555 : union insn_output_u
556 : {
557 : const char *single;
558 : const char *const *multi;
559 : insn_output_fn function;
560 :
561 : constexpr insn_output_u () : single (nullptr) {}
562 : constexpr insn_output_u (const char *s) : single (s) {}
563 : constexpr insn_output_u (const char *const *m) : multi (m) {}
564 : constexpr insn_output_u (insn_output_fn f) : function (f) {}
565 : } output;
566 : const insn_gen_fn genfun;
567 : const struct insn_operand_data *const operand;
568 :
569 : const char n_generator_args;
570 : const char n_operands;
571 : const char n_dups;
572 : const char n_alternatives;
573 : const char output_format;
574 : };
575 :
576 : extern const struct insn_data_d insn_data[];
577 : extern int peep2_current_count;
578 :
579 : #ifndef GENERATOR_FILE
580 : #include "insn-codes.h"
581 :
582 : /* An enum of boolean attributes that may only depend on the current
583 : subtarget, not on things like operands or compiler phase. */
584 : enum bool_attr {
585 : BA_ENABLED,
586 : BA_PREFERRED_FOR_SPEED,
587 : BA_PREFERRED_FOR_SIZE,
588 : BA_LAST = BA_PREFERRED_FOR_SIZE
589 : };
590 :
591 : /* Target-dependent globals. */
592 : struct target_recog {
593 : bool x_initialized;
594 : alternative_mask x_bool_attr_masks[NUM_INSN_CODES][BA_LAST + 1];
595 : operand_alternative *x_op_alt[NUM_INSN_CODES];
596 : };
597 :
598 : extern struct target_recog default_target_recog;
599 : #if SWITCHABLE_TARGET
600 : extern struct target_recog *this_target_recog;
601 : #else
602 : #define this_target_recog (&default_target_recog)
603 : #endif
604 :
605 : alternative_mask get_enabled_alternatives (rtx_insn *);
606 : alternative_mask get_preferred_alternatives (rtx_insn *);
607 : alternative_mask get_preferred_alternatives (rtx_insn *, basic_block);
608 : bool check_bool_attrs (rtx_insn *);
609 :
610 : void recog_init ();
611 :
612 : /* This RAII class can help to undo tentative insn changes on failure.
613 : When an object of the class goes out of scope, it undoes all group
614 : changes that have been made via the validate_change machinery and
615 : not yet confirmed via confirm_change_group.
616 :
617 : For example:
618 :
619 : insn_change_watermark watermark;
620 : validate_change (..., true); // A
621 : ...
622 : if (test)
623 : // Undoes change A.
624 : return false;
625 : ...
626 : validate_change (..., true); // B
627 : ...
628 : if (test)
629 : // Undoes changes A and B.
630 : return false;
631 : ...
632 : confirm_change_group ();
633 :
634 : Code that wants to avoid this behavior can use keep ():
635 :
636 : insn_change_watermark watermark;
637 : validate_change (..., true); // A
638 : ...
639 : if (test)
640 : // Undoes change A.
641 : return false;
642 : ...
643 : watermark.keep ();
644 : validate_change (..., true); // B
645 : ...
646 : if (test)
647 : // Undoes change B, but not A.
648 : return false;
649 : ...
650 : confirm_change_group (); */
651 : class insn_change_watermark
652 : {
653 : public:
654 113617061 : insn_change_watermark () : m_old_num_changes (num_validated_changes ()) {}
655 : ~insn_change_watermark ();
656 15671076 : void keep () { m_old_num_changes = num_validated_changes (); }
657 :
658 : private:
659 : int m_old_num_changes;
660 : };
661 :
662 113617061 : inline insn_change_watermark::~insn_change_watermark ()
663 : {
664 113617061 : if (m_old_num_changes < num_validated_changes ())
665 45482653 : cancel_changes (m_old_num_changes);
666 113617061 : }
667 :
668 : #endif
669 :
670 : #endif /* GCC_RECOG_H */
|