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_BITFIELD (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 183869986 : alternative_class (const operand_alternative *alt, int i)
92 : {
93 183869986 : 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 94848812 : alternative_register_filters (const operand_alternative *alt, int i)
101 : {
102 94848812 : return (alt[i].matches >= 0
103 94848812 : ? alt[alt[i].matches].register_filters
104 84650772 : : 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 70254141 : inline insn_propagation::insn_propagation (rtx_insn *insn, rtx from, rtx to,
200 70254141 : bool shared_p)
201 70254141 : : insn (insn),
202 70254141 : from (from),
203 70254141 : to (to),
204 70254141 : num_replacements (0),
205 70254141 : result_flags (0),
206 70254141 : should_unshare (shared_p),
207 70254141 : should_check_mems (false),
208 70254141 : should_note_simplifications (false),
209 70254141 : spare (0),
210 70254141 : failure_reason (nullptr)
211 : {
212 : }
213 :
214 : /* Try to simplify INSN without performing a substitution. */
215 :
216 3555461 : inline insn_propagation::insn_propagation (rtx_insn *insn)
217 3555461 : : 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 2760134772 : 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 17389017819 : recog_memoized (rtx_insn *insn)
337 : {
338 17389017819 : if (INSN_CODE (insn) < 0)
339 727062098 : INSN_CODE (insn) = recog (PATTERN (insn), insn, 0);
340 17389017819 : 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 3271771466 : skip_alternative (const char *p)
348 : {
349 3271771466 : const char *r = p;
350 10146168540 : while (*r != '\0' && *r != ',')
351 6874397074 : r++;
352 3271771466 : if (*r == ',')
353 3040901226 : r++;
354 3271771466 : 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 4521539 : temporary_volatile_ok (int value) : save_volatile_ok (volatile_ok)
366 : {
367 4521539 : volatile_ok = value;
368 : }
369 :
370 4521539 : ~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 : /* It is very tempting to make the 5 operand related arrays into a
389 : structure and index on that. However, to be source compatible
390 : with all of the existing md file insn constraints and output
391 : templates, we need `operand' as a flat array. Without that
392 : member, making an array for the rest seems pointless. */
393 :
394 : /* Gives value of operand N. */
395 : rtx operand[MAX_RECOG_OPERANDS];
396 :
397 : /* Gives location where operand N was found. */
398 : rtx *operand_loc[MAX_RECOG_OPERANDS];
399 :
400 : /* Gives the constraint string for operand N. */
401 : const char *constraints[MAX_RECOG_OPERANDS];
402 :
403 : /* Nonzero if operand N is a match_operator or a match_parallel. */
404 : char is_operator[MAX_RECOG_OPERANDS];
405 :
406 : /* Gives the mode of operand N. */
407 : machine_mode operand_mode[MAX_RECOG_OPERANDS];
408 :
409 : /* Gives the type (in, out, inout) for operand N. */
410 : enum op_type operand_type[MAX_RECOG_OPERANDS];
411 :
412 : /* Gives location where the Nth duplicate-appearance of an operand
413 : was found. This is something that matched MATCH_DUP. */
414 : rtx *dup_loc[MAX_DUP_OPERANDS];
415 :
416 : /* Gives the operand number that was duplicated in the Nth
417 : duplicate-appearance of an operand. */
418 : char dup_num[MAX_DUP_OPERANDS];
419 :
420 : /* ??? Note that these are `char' instead of `unsigned char' to (try to)
421 : avoid certain lossage from K&R C, wherein `unsigned char' default
422 : promotes to `unsigned int' instead of `int' as in ISO C. As of 1999,
423 : the most common places to bootstrap from K&R C are SunOS and HPUX,
424 : both of which have signed characters by default. The only other
425 : supported natives that have both K&R C and unsigned characters are
426 : ROMP and Irix 3, and neither have been seen for a while, but do
427 : continue to consider unsignedness when performing arithmetic inside
428 : a comparison. */
429 :
430 : /* The number of operands of the insn. */
431 : char n_operands;
432 :
433 : /* The number of MATCH_DUPs in the insn. */
434 : char n_dups;
435 :
436 : /* The number of alternatives in the constraints for the insn. */
437 : char n_alternatives;
438 :
439 : /* True if insn is ASM_OPERANDS. */
440 : bool is_asm;
441 :
442 : /* In case we are caching, hold insn data was generated for. */
443 : rtx_insn *insn;
444 : };
445 :
446 : extern struct recog_data_d recog_data;
447 :
448 : /* RAII class for saving/restoring recog_data. */
449 :
450 : class recog_data_saver
451 : {
452 : recog_data_d m_saved_data;
453 : public:
454 0 : recog_data_saver () : m_saved_data (recog_data) {}
455 0 : ~recog_data_saver () { recog_data = m_saved_data; }
456 : };
457 :
458 : #ifndef GENERATOR_FILE
459 : extern const operand_alternative *recog_op_alt;
460 :
461 : /* Return a pointer to an array in which index OP describes the constraints
462 : on operand OP of the current instruction alternative (which_alternative).
463 : Only valid after calling preprocess_constraints and constrain_operands. */
464 :
465 : inline const operand_alternative *
466 104978414 : which_op_alt ()
467 : {
468 104978414 : gcc_checking_assert (IN_RANGE (which_alternative, 0,
469 : recog_data.n_alternatives - 1));
470 104978414 : return &recog_op_alt[which_alternative * recog_data.n_operands];
471 : }
472 : #endif
473 :
474 : /* A table defined in insn-output.cc that give information about
475 : each insn-code value. */
476 :
477 : typedef bool (*insn_operand_predicate_fn) (rtx, machine_mode);
478 : typedef const char * (*insn_output_fn) (rtx *, rtx_insn *);
479 :
480 : struct insn_gen_fn
481 : {
482 : typedef void (*stored_funcptr) (void);
483 :
484 : template<typename ...Ts>
485 107119312 : rtx_insn *operator() (Ts... args) const
486 : {
487 : typedef rtx_insn *(*funcptr) (decltype ((void) args, NULL_RTX)...);
488 107119312 : return ((funcptr) func) (args...);
489 : }
490 :
491 : // This is for compatibility of code that invokes functions like
492 : // (*funcptr) (arg)
493 : insn_gen_fn operator * (void) const { return *this; }
494 :
495 : // The wrapped function pointer must be public and there must not be any
496 : // constructors. Otherwise the insn_data_d struct initializers generated
497 : // by genoutput.cc will result in static initializer functions, which defeats
498 : // the purpose of the generated insn_data_d array.
499 : stored_funcptr func;
500 : };
501 :
502 : struct insn_operand_data
503 : {
504 : const insn_operand_predicate_fn predicate;
505 :
506 : const char *const constraint;
507 :
508 : ENUM_BITFIELD(machine_mode) const mode : 16;
509 :
510 : const char strict_low;
511 :
512 : const char is_operator;
513 :
514 : const char eliminable;
515 :
516 : const char allows_mem;
517 : };
518 :
519 : /* Legal values for insn_data.output_format. Indicate what type of data
520 : is stored in insn_data.output. */
521 : #define INSN_OUTPUT_FORMAT_NONE 0 /* abort */
522 : #define INSN_OUTPUT_FORMAT_SINGLE 1 /* const char * */
523 : #define INSN_OUTPUT_FORMAT_MULTI 2 /* const char * const * */
524 : #define INSN_OUTPUT_FORMAT_FUNCTION 3 /* const char * (*)(...) */
525 :
526 : struct insn_data_d
527 : {
528 : const char *const name;
529 : #if HAVE_DESIGNATED_UNION_INITIALIZERS
530 : union {
531 : const char *single;
532 : const char *const *multi;
533 : insn_output_fn function;
534 : } output;
535 : #else
536 : struct {
537 : const char *single;
538 : const char *const *multi;
539 : insn_output_fn function;
540 : } output;
541 : #endif
542 : const insn_gen_fn genfun;
543 : const struct insn_operand_data *const operand;
544 :
545 : const char n_generator_args;
546 : const char n_operands;
547 : const char n_dups;
548 : const char n_alternatives;
549 : const char output_format;
550 : };
551 :
552 : extern const struct insn_data_d insn_data[];
553 : extern int peep2_current_count;
554 :
555 : #ifndef GENERATOR_FILE
556 : #include "insn-codes.h"
557 :
558 : /* An enum of boolean attributes that may only depend on the current
559 : subtarget, not on things like operands or compiler phase. */
560 : enum bool_attr {
561 : BA_ENABLED,
562 : BA_PREFERRED_FOR_SPEED,
563 : BA_PREFERRED_FOR_SIZE,
564 : BA_LAST = BA_PREFERRED_FOR_SIZE
565 : };
566 :
567 : /* Target-dependent globals. */
568 : struct target_recog {
569 : bool x_initialized;
570 : alternative_mask x_bool_attr_masks[NUM_INSN_CODES][BA_LAST + 1];
571 : operand_alternative *x_op_alt[NUM_INSN_CODES];
572 : };
573 :
574 : extern struct target_recog default_target_recog;
575 : #if SWITCHABLE_TARGET
576 : extern struct target_recog *this_target_recog;
577 : #else
578 : #define this_target_recog (&default_target_recog)
579 : #endif
580 :
581 : alternative_mask get_enabled_alternatives (rtx_insn *);
582 : alternative_mask get_preferred_alternatives (rtx_insn *);
583 : alternative_mask get_preferred_alternatives (rtx_insn *, basic_block);
584 : bool check_bool_attrs (rtx_insn *);
585 :
586 : void recog_init ();
587 :
588 : /* This RAII class can help to undo tentative insn changes on failure.
589 : When an object of the class goes out of scope, it undoes all group
590 : changes that have been made via the validate_change machinery and
591 : not yet confirmed via confirm_change_group.
592 :
593 : For example:
594 :
595 : insn_change_watermark watermark;
596 : validate_change (..., true); // A
597 : ...
598 : if (test)
599 : // Undoes change A.
600 : return false;
601 : ...
602 : validate_change (..., true); // B
603 : ...
604 : if (test)
605 : // Undoes changes A and B.
606 : return false;
607 : ...
608 : confirm_change_group ();
609 :
610 : Code that wants to avoid this behavior can use keep ():
611 :
612 : insn_change_watermark watermark;
613 : validate_change (..., true); // A
614 : ...
615 : if (test)
616 : // Undoes change A.
617 : return false;
618 : ...
619 : watermark.keep ();
620 : validate_change (..., true); // B
621 : ...
622 : if (test)
623 : // Undoes change B, but not A.
624 : return false;
625 : ...
626 : confirm_change_group (); */
627 : class insn_change_watermark
628 : {
629 : public:
630 112461534 : insn_change_watermark () : m_old_num_changes (num_validated_changes ()) {}
631 : ~insn_change_watermark ();
632 15463103 : void keep () { m_old_num_changes = num_validated_changes (); }
633 :
634 : private:
635 : int m_old_num_changes;
636 : };
637 :
638 112461534 : inline insn_change_watermark::~insn_change_watermark ()
639 : {
640 112461534 : if (m_old_num_changes < num_validated_changes ())
641 45029322 : cancel_changes (m_old_num_changes);
642 112461534 : }
643 :
644 : #endif
645 :
646 : #endif /* GCC_RECOG_H */
|