Branch data Line data Source code
1 : : /* Declarations for interface to insn recognizer and insn-output.cc.
2 : : Copyright (C) 1987-2024 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 : : /* Nonzero if '&' was found in the constraint string. */
72 : : unsigned int earlyclobber : 1;
73 : : /* Nonzero if TARGET_MEM_CONSTRAINT was found in the constraint
74 : : string. */
75 : : unsigned int memory_ok : 1;
76 : : /* Nonzero if 'p' was found in the constraint string. */
77 : : unsigned int is_address : 1;
78 : : /* Nonzero if 'X' was found in the constraint string, or if the constraint
79 : : string for this alternative was empty. */
80 : : unsigned int anything_ok : 1;
81 : : };
82 : :
83 : : /* Return the class for operand I of alternative ALT, taking matching
84 : : constraints into account. */
85 : :
86 : : inline enum reg_class
87 : 170400222 : alternative_class (const operand_alternative *alt, int i)
88 : : {
89 : 170400222 : return alt[i].matches >= 0 ? alt[alt[i].matches].cl : alt[i].cl;
90 : : }
91 : :
92 : : /* Return the mask of register filters that should be applied to operand I
93 : : of alternative ALT, taking matching constraints into account. */
94 : :
95 : : inline unsigned int
96 : 87981938 : alternative_register_filters (const operand_alternative *alt, int i)
97 : : {
98 : 87981938 : return (alt[i].matches >= 0
99 : 87981938 : ? alt[alt[i].matches].register_filters
100 : 79020507 : : alt[i].register_filters);
101 : : }
102 : : #endif
103 : :
104 : : /* A class for substituting one rtx for another within an instruction,
105 : : or for recursively simplifying the instruction as-is. Derived classes
106 : : can record or filter certain decisions. */
107 : :
108 : : class insn_propagation : public simplify_context
109 : : {
110 : : public:
111 : : /* Assignments for RESULT_FLAGS.
112 : :
113 : : UNSIMPLIFIED is true if a substitution has been made inside an rtx
114 : : X and if neither X nor its parent expressions could be simplified.
115 : :
116 : : FIRST_SPARE_RESULT is the first flag available for derived classes. */
117 : : static const uint16_t UNSIMPLIFIED = 1U << 0;
118 : : static const uint16_t FIRST_SPARE_RESULT = 1U << 1;
119 : :
120 : : insn_propagation (rtx_insn *);
121 : : insn_propagation (rtx_insn *, rtx, rtx, bool = true);
122 : : bool apply_to_pattern (rtx *);
123 : : bool apply_to_rvalue (rtx *);
124 : :
125 : : /* Return true if we should accept a substitution into the address of
126 : : memory expression MEM. Undoing changes OLD_NUM_CHANGES and up restores
127 : : MEM's original address. */
128 : 0 : virtual bool check_mem (int /*old_num_changes*/,
129 : 0 : rtx /*mem*/) { return true; }
130 : :
131 : : /* Note that we've simplified OLD_RTX into NEW_RTX. When substituting,
132 : : this only happens if a substitution occured within OLD_RTX.
133 : : Undoing OLD_NUM_CHANGES and up will restore the old form of OLD_RTX.
134 : : OLD_RESULT_FLAGS is the value that RESULT_FLAGS had before processing
135 : : OLD_RTX. */
136 : 0 : virtual void note_simplification (int /*old_num_changes*/,
137 : : uint16_t /*old_result_flags*/,
138 : 0 : rtx /*old_rtx*/, rtx /*new_rtx*/) {}
139 : :
140 : : private:
141 : : bool apply_to_mem_1 (rtx);
142 : : bool apply_to_lvalue_1 (rtx);
143 : : bool apply_to_rvalue_1 (rtx *);
144 : : bool apply_to_pattern_1 (rtx *);
145 : :
146 : : public:
147 : : /* The instruction that we are simplifying or propagating into. */
148 : : rtx_insn *insn;
149 : :
150 : : /* If FROM is nonnull, we're replacing FROM with TO, otherwise we're
151 : : just doing a recursive simplification. */
152 : : rtx from;
153 : : rtx to;
154 : :
155 : : /* The number of times that we have replaced FROM with TO. */
156 : : unsigned int num_replacements;
157 : :
158 : : /* A bitmask of flags that describe the result of the simplificiation;
159 : : see above for details. */
160 : : uint16_t result_flags : 16;
161 : :
162 : : /* True if we should unshare TO when making the next substitution,
163 : : false if we can use TO itself. */
164 : : uint16_t should_unshare : 1;
165 : :
166 : : /* True if we should call check_mem after substituting into a memory. */
167 : : uint16_t should_check_mems : 1;
168 : :
169 : : /* True if we should call note_simplification after each simplification. */
170 : : uint16_t should_note_simplifications : 1;
171 : :
172 : : /* For future expansion. */
173 : : uint16_t spare : 13;
174 : :
175 : : /* Gives the reason that a substitution failed, for debug purposes. */
176 : : const char *failure_reason;
177 : : };
178 : :
179 : : /* Try to replace FROM with TO in INSN. SHARED_P is true if TO is shared
180 : : with other instructions, false if INSN can use TO directly. */
181 : :
182 : 32005412 : inline insn_propagation::insn_propagation (rtx_insn *insn, rtx from, rtx to,
183 : 32005412 : bool shared_p)
184 : 32005412 : : insn (insn),
185 : 32005412 : from (from),
186 : 32005412 : to (to),
187 : 32005412 : num_replacements (0),
188 : 32005412 : result_flags (0),
189 : 32005412 : should_unshare (shared_p),
190 : 32005412 : should_check_mems (false),
191 : 32005412 : should_note_simplifications (false),
192 : 32005412 : spare (0),
193 : 32005412 : failure_reason (nullptr)
194 : : {
195 : : }
196 : :
197 : : /* Try to simplify INSN without performing a substitution. */
198 : :
199 : 1792056 : inline insn_propagation::insn_propagation (rtx_insn *insn)
200 : 1792056 : : insn_propagation (insn, NULL_RTX, NULL_RTX)
201 : : {
202 : : }
203 : :
204 : : extern void init_recog (void);
205 : : extern void init_recog_no_volatile (void);
206 : : extern bool check_asm_operands (rtx);
207 : : extern int asm_operand_ok (rtx, const char *, const char **);
208 : : extern bool validate_change (rtx, rtx *, rtx, bool);
209 : : extern bool validate_unshare_change (rtx, rtx *, rtx, bool);
210 : : extern bool validate_change_xveclen (rtx, rtx *, int, bool);
211 : : extern bool canonicalize_change_group (rtx_insn *insn, rtx x);
212 : : extern bool insn_invalid_p (rtx_insn *, bool);
213 : : extern bool verify_changes (int);
214 : : extern void confirm_change_group (void);
215 : : extern bool apply_change_group (void);
216 : : extern int num_validated_changes (void);
217 : : extern void cancel_changes (int);
218 : : extern void temporarily_undo_changes (int);
219 : : extern void redo_changes (int);
220 : : extern bool constrain_operands (int, alternative_mask);
221 : : extern bool constrain_operands_cached (rtx_insn *, int);
222 : : extern bool memory_address_addr_space_p (machine_mode, rtx, addr_space_t,
223 : : code_helper = ERROR_MARK);
224 : : #define memory_address_p(mode,addr) \
225 : : memory_address_addr_space_p ((mode), (addr), ADDR_SPACE_GENERIC)
226 : : extern bool strict_memory_address_addr_space_p (machine_mode, rtx, addr_space_t,
227 : : code_helper = ERROR_MARK);
228 : : #define strict_memory_address_p(mode,addr) \
229 : : strict_memory_address_addr_space_p ((mode), (addr), ADDR_SPACE_GENERIC)
230 : : extern bool validate_replace_rtx_subexp (rtx, rtx, rtx_insn *, rtx *);
231 : : extern bool validate_replace_rtx (rtx, rtx, rtx_insn *);
232 : : extern bool validate_replace_rtx_part (rtx, rtx, rtx *, rtx_insn *);
233 : : extern bool validate_replace_rtx_part_nosimplify (rtx, rtx, rtx *, rtx_insn *);
234 : : extern void validate_replace_rtx_group (rtx, rtx, rtx_insn *);
235 : : extern void validate_replace_src_group (rtx, rtx, rtx_insn *);
236 : : extern bool validate_simplify_insn (rtx_insn *insn);
237 : : extern int num_changes_pending (void);
238 : : extern bool reg_fits_class_p (const_rtx, reg_class_t, int, machine_mode);
239 : : extern bool valid_insn_p (rtx_insn *);
240 : :
241 : : extern bool offsettable_memref_p (rtx);
242 : : extern bool offsettable_nonstrict_memref_p (rtx);
243 : : extern bool offsettable_address_addr_space_p (int, machine_mode, rtx,
244 : : addr_space_t);
245 : : #define offsettable_address_p(strict,mode,addr) \
246 : : offsettable_address_addr_space_p ((strict), (mode), (addr), \
247 : : ADDR_SPACE_GENERIC)
248 : : extern bool mode_dependent_address_p (rtx, addr_space_t);
249 : :
250 : : extern int recog (rtx, rtx_insn *, int *);
251 : : #ifndef GENERATOR_FILE
252 : : inline int recog_memoized (rtx_insn *insn);
253 : : #endif
254 : : extern void add_clobbers (rtx, int);
255 : : extern bool added_clobbers_hard_reg_p (int);
256 : : extern void insn_extract (rtx_insn *);
257 : : extern void extract_insn (rtx_insn *);
258 : : extern void extract_constrain_insn (rtx_insn *insn);
259 : : extern void extract_constrain_insn_cached (rtx_insn *);
260 : : extern void extract_insn_cached (rtx_insn *);
261 : : #ifndef GENERATOR_FILE
262 : : extern void preprocess_constraints (int, int, const char **,
263 : : operand_alternative *, rtx **);
264 : : extern const operand_alternative *preprocess_insn_constraints (unsigned int);
265 : : #endif
266 : : extern void preprocess_constraints (rtx_insn *);
267 : : extern rtx_insn *peep2_next_insn (int);
268 : : extern bool peep2_regno_dead_p (int, int);
269 : : extern bool peep2_reg_dead_p (int, rtx);
270 : : #ifdef HARD_CONST
271 : : extern rtx peep2_find_free_register (int, int, const char *,
272 : : machine_mode, HARD_REG_SET *);
273 : : #endif
274 : : extern rtx_insn *peephole2_insns (rtx, rtx_insn *, int *);
275 : :
276 : : extern bool store_data_bypass_p (rtx_insn *, rtx_insn *);
277 : : extern bool if_test_bypass_p (rtx_insn *, rtx_insn *);
278 : :
279 : : extern void copy_frame_info_to_split_insn (rtx_insn *, rtx_insn *);
280 : :
281 : : #ifndef GENERATOR_FILE
282 : : /* Try recognizing the instruction INSN,
283 : : and return the code number that results.
284 : : Remember the code so that repeated calls do not
285 : : need to spend the time for actual rerecognition.
286 : :
287 : : This function is the normal interface to instruction recognition.
288 : : The automatically-generated function `recog' is normally called
289 : : through this one. */
290 : :
291 : : inline int
292 : 15185920914 : recog_memoized (rtx_insn *insn)
293 : : {
294 : 15185920914 : if (INSN_CODE (insn) < 0)
295 : 673230528 : INSN_CODE (insn) = recog (PATTERN (insn), insn, 0);
296 : 15185920914 : return INSN_CODE (insn);
297 : : }
298 : : #endif
299 : :
300 : : /* Skip chars until the next ',' or the end of the string. This is
301 : : useful to skip alternatives in a constraint string. */
302 : : inline const char *
303 : 2696294885 : skip_alternative (const char *p)
304 : : {
305 : 2696294885 : const char *r = p;
306 : 8500939500 : while (*r != '\0' && *r != ',')
307 : 5804644615 : r++;
308 : 2696294885 : if (*r == ',')
309 : 2527695082 : r++;
310 : 2696294885 : return r;
311 : : }
312 : :
313 : : /* Nonzero means volatile operands are recognized. */
314 : : extern int volatile_ok;
315 : :
316 : : /* RAII class for temporarily setting volatile_ok. */
317 : :
318 : : class temporary_volatile_ok
319 : : {
320 : : public:
321 : 3798660 : temporary_volatile_ok (int value) : save_volatile_ok (volatile_ok)
322 : : {
323 : 3798660 : volatile_ok = value;
324 : : }
325 : :
326 : 3798660 : ~temporary_volatile_ok () { volatile_ok = save_volatile_ok; }
327 : :
328 : : private:
329 : : temporary_volatile_ok (const temporary_volatile_ok &);
330 : : int save_volatile_ok;
331 : : };
332 : :
333 : : /* Set by constrain_operands to the number of the alternative that
334 : : matched. */
335 : : extern int which_alternative;
336 : :
337 : : /* The following vectors hold the results from insn_extract. */
338 : :
339 : : struct recog_data_d
340 : : {
341 : : /* It is very tempting to make the 5 operand related arrays into a
342 : : structure and index on that. However, to be source compatible
343 : : with all of the existing md file insn constraints and output
344 : : templates, we need `operand' as a flat array. Without that
345 : : member, making an array for the rest seems pointless. */
346 : :
347 : : /* Gives value of operand N. */
348 : : rtx operand[MAX_RECOG_OPERANDS];
349 : :
350 : : /* Gives location where operand N was found. */
351 : : rtx *operand_loc[MAX_RECOG_OPERANDS];
352 : :
353 : : /* Gives the constraint string for operand N. */
354 : : const char *constraints[MAX_RECOG_OPERANDS];
355 : :
356 : : /* Nonzero if operand N is a match_operator or a match_parallel. */
357 : : char is_operator[MAX_RECOG_OPERANDS];
358 : :
359 : : /* Gives the mode of operand N. */
360 : : machine_mode operand_mode[MAX_RECOG_OPERANDS];
361 : :
362 : : /* Gives the type (in, out, inout) for operand N. */
363 : : enum op_type operand_type[MAX_RECOG_OPERANDS];
364 : :
365 : : /* Gives location where the Nth duplicate-appearance of an operand
366 : : was found. This is something that matched MATCH_DUP. */
367 : : rtx *dup_loc[MAX_DUP_OPERANDS];
368 : :
369 : : /* Gives the operand number that was duplicated in the Nth
370 : : duplicate-appearance of an operand. */
371 : : char dup_num[MAX_DUP_OPERANDS];
372 : :
373 : : /* ??? Note that these are `char' instead of `unsigned char' to (try to)
374 : : avoid certain lossage from K&R C, wherein `unsigned char' default
375 : : promotes to `unsigned int' instead of `int' as in ISO C. As of 1999,
376 : : the most common places to bootstrap from K&R C are SunOS and HPUX,
377 : : both of which have signed characters by default. The only other
378 : : supported natives that have both K&R C and unsigned characters are
379 : : ROMP and Irix 3, and neither have been seen for a while, but do
380 : : continue to consider unsignedness when performing arithmetic inside
381 : : a comparison. */
382 : :
383 : : /* The number of operands of the insn. */
384 : : char n_operands;
385 : :
386 : : /* The number of MATCH_DUPs in the insn. */
387 : : char n_dups;
388 : :
389 : : /* The number of alternatives in the constraints for the insn. */
390 : : char n_alternatives;
391 : :
392 : : /* True if insn is ASM_OPERANDS. */
393 : : bool is_asm;
394 : :
395 : : /* In case we are caching, hold insn data was generated for. */
396 : : rtx_insn *insn;
397 : : };
398 : :
399 : : extern struct recog_data_d recog_data;
400 : :
401 : : /* RAII class for saving/restoring recog_data. */
402 : :
403 : : class recog_data_saver
404 : : {
405 : : recog_data_d m_saved_data;
406 : : public:
407 : 0 : recog_data_saver () : m_saved_data (recog_data) {}
408 : 0 : ~recog_data_saver () { recog_data = m_saved_data; }
409 : : };
410 : :
411 : : #ifndef GENERATOR_FILE
412 : : extern const operand_alternative *recog_op_alt;
413 : :
414 : : /* Return a pointer to an array in which index OP describes the constraints
415 : : on operand OP of the current instruction alternative (which_alternative).
416 : : Only valid after calling preprocess_constraints and constrain_operands. */
417 : :
418 : : inline const operand_alternative *
419 : 92434446 : which_op_alt ()
420 : : {
421 : 92434446 : gcc_checking_assert (IN_RANGE (which_alternative, 0,
422 : : recog_data.n_alternatives - 1));
423 : 92434446 : return &recog_op_alt[which_alternative * recog_data.n_operands];
424 : : }
425 : : #endif
426 : :
427 : : /* A table defined in insn-output.cc that give information about
428 : : each insn-code value. */
429 : :
430 : : typedef bool (*insn_operand_predicate_fn) (rtx, machine_mode);
431 : : typedef const char * (*insn_output_fn) (rtx *, rtx_insn *);
432 : :
433 : : struct insn_gen_fn
434 : : {
435 : : typedef void (*stored_funcptr) (void);
436 : :
437 : : template<typename ...Ts>
438 : 97715961 : rtx_insn *operator() (Ts... args) const
439 : : {
440 : : typedef rtx_insn *(*funcptr) (decltype ((void) args, NULL_RTX)...);
441 : 97715961 : return ((funcptr) func) (args...);
442 : : }
443 : :
444 : : // This is for compatibility of code that invokes functions like
445 : : // (*funcptr) (arg)
446 : : insn_gen_fn operator * (void) const { return *this; }
447 : :
448 : : // The wrapped function pointer must be public and there must not be any
449 : : // constructors. Otherwise the insn_data_d struct initializers generated
450 : : // by genoutput.cc will result in static initializer functions, which defeats
451 : : // the purpose of the generated insn_data_d array.
452 : : stored_funcptr func;
453 : : };
454 : :
455 : : struct insn_operand_data
456 : : {
457 : : const insn_operand_predicate_fn predicate;
458 : :
459 : : const char *const constraint;
460 : :
461 : : ENUM_BITFIELD(machine_mode) const mode : 16;
462 : :
463 : : const char strict_low;
464 : :
465 : : const char is_operator;
466 : :
467 : : const char eliminable;
468 : :
469 : : const char allows_mem;
470 : : };
471 : :
472 : : /* Legal values for insn_data.output_format. Indicate what type of data
473 : : is stored in insn_data.output. */
474 : : #define INSN_OUTPUT_FORMAT_NONE 0 /* abort */
475 : : #define INSN_OUTPUT_FORMAT_SINGLE 1 /* const char * */
476 : : #define INSN_OUTPUT_FORMAT_MULTI 2 /* const char * const * */
477 : : #define INSN_OUTPUT_FORMAT_FUNCTION 3 /* const char * (*)(...) */
478 : :
479 : : struct insn_data_d
480 : : {
481 : : const char *const name;
482 : : #if HAVE_DESIGNATED_UNION_INITIALIZERS
483 : : union {
484 : : const char *single;
485 : : const char *const *multi;
486 : : insn_output_fn function;
487 : : } output;
488 : : #else
489 : : struct {
490 : : const char *single;
491 : : const char *const *multi;
492 : : insn_output_fn function;
493 : : } output;
494 : : #endif
495 : : const insn_gen_fn genfun;
496 : : const struct insn_operand_data *const operand;
497 : :
498 : : const char n_generator_args;
499 : : const char n_operands;
500 : : const char n_dups;
501 : : const char n_alternatives;
502 : : const char output_format;
503 : : };
504 : :
505 : : extern const struct insn_data_d insn_data[];
506 : : extern int peep2_current_count;
507 : :
508 : : #ifndef GENERATOR_FILE
509 : : #include "insn-codes.h"
510 : :
511 : : /* An enum of boolean attributes that may only depend on the current
512 : : subtarget, not on things like operands or compiler phase. */
513 : : enum bool_attr {
514 : : BA_ENABLED,
515 : : BA_PREFERRED_FOR_SPEED,
516 : : BA_PREFERRED_FOR_SIZE,
517 : : BA_LAST = BA_PREFERRED_FOR_SIZE
518 : : };
519 : :
520 : : /* Target-dependent globals. */
521 : : struct target_recog {
522 : : bool x_initialized;
523 : : alternative_mask x_bool_attr_masks[NUM_INSN_CODES][BA_LAST + 1];
524 : : operand_alternative *x_op_alt[NUM_INSN_CODES];
525 : : };
526 : :
527 : : extern struct target_recog default_target_recog;
528 : : #if SWITCHABLE_TARGET
529 : : extern struct target_recog *this_target_recog;
530 : : #else
531 : : #define this_target_recog (&default_target_recog)
532 : : #endif
533 : :
534 : : alternative_mask get_enabled_alternatives (rtx_insn *);
535 : : alternative_mask get_preferred_alternatives (rtx_insn *);
536 : : alternative_mask get_preferred_alternatives (rtx_insn *, basic_block);
537 : : bool check_bool_attrs (rtx_insn *);
538 : :
539 : : void recog_init ();
540 : :
541 : : /* This RAII class can help to undo tentative insn changes on failure.
542 : : When an object of the class goes out of scope, it undoes all group
543 : : changes that have been made via the validate_change machinery and
544 : : not yet confirmed via confirm_change_group.
545 : :
546 : : For example:
547 : :
548 : : insn_change_watermark watermark;
549 : : validate_change (..., true); // A
550 : : ...
551 : : if (test)
552 : : // Undoes change A.
553 : : return false;
554 : : ...
555 : : validate_change (..., true); // B
556 : : ...
557 : : if (test)
558 : : // Undoes changes A and B.
559 : : return false;
560 : : ...
561 : : confirm_change_group ();
562 : :
563 : : Code that wants to avoid this behavior can use keep ():
564 : :
565 : : insn_change_watermark watermark;
566 : : validate_change (..., true); // A
567 : : ...
568 : : if (test)
569 : : // Undoes change A.
570 : : return false;
571 : : ...
572 : : watermark.keep ();
573 : : validate_change (..., true); // B
574 : : ...
575 : : if (test)
576 : : // Undoes change B, but not A.
577 : : return false;
578 : : ...
579 : : confirm_change_group (); */
580 : : class insn_change_watermark
581 : : {
582 : : public:
583 : 47884618 : insn_change_watermark () : m_old_num_changes (num_validated_changes ()) {}
584 : : ~insn_change_watermark ();
585 : 6945114 : void keep () { m_old_num_changes = num_validated_changes (); }
586 : :
587 : : private:
588 : : int m_old_num_changes;
589 : : };
590 : :
591 : 47884618 : inline insn_change_watermark::~insn_change_watermark ()
592 : : {
593 : 47884618 : if (m_old_num_changes < num_validated_changes ())
594 : 18840605 : cancel_changes (m_old_num_changes);
595 : 47884618 : }
596 : :
597 : : #endif
598 : :
599 : : #endif /* GCC_RECOG_H */
|