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