Add register filter operand to define_register_constraint
The main way of enforcing registers to be aligned is through HARD_REGNO_MODE_OK. But this is a global property that applies to all operands. A given (regno, mode) pair is either globally valid or globally invalid. This patch instead adds a way of specifying that individual operands must be aligned. More generally, it allows constraints to specify a C++ condition that the operand's REGNO must satisfy. The condition must be invariant for a given set of target options, so that it can be precomputed and cached as a HARD_REG_SET. This information will be used in very compile-time-sensitive parts of the compiler. A lot of the complication is in allowing the information to be stored and tested without much memory cost, and without impacting targets that don't use the feature. Specifically: - Constraints are encouraged to test the absolute REGNO rather than an offset from the start of the containing class. For example, all constraints for even registers should use the same condition, such as "regno % 2 == 0". This requires the classes to start at even register boundaries, but that's already an implicit requirement due to things like the ira-costs.cc code that begins: /* Some targets allow pseudos to be allocated to unaligned sequences of hard registers. However, selecting an unaligned sequence can unnecessarily restrict later allocations. So increase the cost of unaligned hard regs to encourage the use of aligned hard regs. */ - Each unique condition is given a "filter identifier". - The total number of filters is given by NUM_REGISTER_FILTERS, defined automatically in insn-config.h. Structures can therefore use a bitfield of NUM_REGISTER_FILTERS to represent a mask of filters. - There is a new target global, target_constraints, that caches the HARD_REG_SET for each filter. - There is a function for looking up the HARD_REG_SET filter for a given constraint and one for looking up the filter id. Both simply return a constant on targets that don't use the feature. - There are functions for testing a register against a specific filter, or against a mask of filters. This patch just adds the information. Later ones make use of it. gcc/ * rtl.def (DEFINE_REGISTER_CONSTRAINT): Add an optional filter operand. * doc/md.texi (define_register_constraint): Document it. * doc/tm.texi.in: Reference it in discussion about aligned registers. * doc/tm.texi: Regenerate. * gensupport.h (register_filters, get_register_filter_id): Declare. * gensupport.cc (register_filter_map, register_filters): New variables. (get_register_filter_id): New function. (process_define_register_constraint): Likewise. (process_rtx): Pass define_register_constraints to process_define_register_constraint. * genconfig.cc (main): Emit a definition of NUM_REGISTER_FILTERS. * genpreds.cc (constraint_data): Add a filter field. (add_constraint): Update accordingly. (process_define_register_constraint): Pass the filter operand. (write_init_reg_class_start_regs): New function. (write_get_register_filter): Likewise. (write_get_register_filter_id): Likewise. (write_tm_preds_h): Write a definition of target_constraints, plus helpers to test its contents. Write the get_register_filter* functions. (write_insn_preds_c): Write init_reg_class_start_regs. * reginfo.cc (init_reg_class_start_regs): Declare. (init_reg_sets): Call it. * target-globals.h (this_target_constraints): Declare. (target_globals): Add a constraints field. (restore_target_globals): Update accordingly. * target-globals.cc: Include tm_p.h. (default_target_globals): Initialize the constraints field. (save_target_globals): Handle the constraints field. (target_globals::~target_globals): Likewise.
This commit is contained in:
parent
aef1aaff41
commit
09a85191d0
11 changed files with 254 additions and 12 deletions
|
@ -4516,8 +4516,8 @@ Register constraints correspond directly to register classes.
|
|||
@xref{Register Classes}. There is thus not much flexibility in their
|
||||
definitions.
|
||||
|
||||
@deffn {MD Expression} define_register_constraint name regclass docstring
|
||||
All three arguments are string constants.
|
||||
@deffn {MD Expression} define_register_constraint name regclass docstring [filter]
|
||||
All arguments are string constants.
|
||||
@var{name} is the name of the constraint, as it will appear in
|
||||
@code{match_operand} expressions. If @var{name} is a multi-letter
|
||||
constraint its length shall be the same for all constraints starting
|
||||
|
@ -4529,6 +4529,43 @@ look at the operand. The usual use of expressions is to map some
|
|||
register constraints to @code{NO_REGS} when the register class
|
||||
is not available on a given subarchitecture.
|
||||
|
||||
If an operand occupies multiple hard registers, the constraint
|
||||
requires all of those registers to belong to @var{regclass}.
|
||||
For example, if @var{regclass} is @code{GENERAL_REGS} and
|
||||
@code{GENERAL_REGS} contains registers @code{r0} to @code{r15},
|
||||
the constraint does not allow @var{r15} to be used for modes
|
||||
that occupy more than one register.
|
||||
|
||||
@cindex @code{TARGET_HARD_REGNO_MODE_OK} and constraints
|
||||
The choice of register is also constrained by @code{TARGET_HARD_REGNO_MODE_OK}.
|
||||
For example, if @code{TARGET_HARD_REGNO_MODE_OK} disallows @samp{(reg:DI r1)},
|
||||
that requirement applies to all constraints whose classes include @code{r1}.
|
||||
|
||||
However, it is sometimes useful to impose extra operand-specific
|
||||
requirements on the register number. For example, a target might not
|
||||
want to prevent @emph{all} odd-even pairs from holding @code{DImode}
|
||||
values, but it might still need to prevent specific operands from
|
||||
having an odd-numbered register. The optional @var{filter} argument
|
||||
exists for such cases. When given, @var{filter} is a C++ expression
|
||||
that evaluates to true if @code{regno} is a valid register for the
|
||||
operand. If an operand occupies multiple registers, the condition
|
||||
applies only to the first register.
|
||||
|
||||
For example:
|
||||
|
||||
@smallexample
|
||||
(define_register_constraint "e" "GENERAL_REGS" "..." "regno % 2 == 0")
|
||||
@end smallexample
|
||||
|
||||
defines a constraint that requires an even-numbered general register.
|
||||
|
||||
Filter conditions that impose an alignment are encouraged to test
|
||||
the alignment of @code{regno} itself, as in the example, rather than
|
||||
calculate an offset relative to the start of the class. If it is
|
||||
sometimes necessary for a register of class @var{c} to be aligned
|
||||
to @var{n}, the first register in @var{c} should itself by divisible
|
||||
by @var{n}.
|
||||
|
||||
@var{docstring} is a sentence documenting the meaning of the
|
||||
constraint. Docstrings are explained further below.
|
||||
@end deffn
|
||||
|
|
|
@ -2478,7 +2478,8 @@ When a value occupying several consecutive registers is expected in a
|
|||
certain class, all the registers used must belong to that class.
|
||||
Therefore, register classes cannot be used to enforce a requirement for
|
||||
a register pair to start with an even-numbered register. The way to
|
||||
specify this requirement is with @code{TARGET_HARD_REGNO_MODE_OK}.
|
||||
specify this requirement is with @code{TARGET_HARD_REGNO_MODE_OK},
|
||||
or with a filter expression in a @code{define_register_constraint}.
|
||||
|
||||
Register classes used for input-operands of bitwise-and or shift
|
||||
instructions have a special requirement: each such class must have, for
|
||||
|
|
|
@ -2060,7 +2060,8 @@ When a value occupying several consecutive registers is expected in a
|
|||
certain class, all the registers used must belong to that class.
|
||||
Therefore, register classes cannot be used to enforce a requirement for
|
||||
a register pair to start with an even-numbered register. The way to
|
||||
specify this requirement is with @code{TARGET_HARD_REGNO_MODE_OK}.
|
||||
specify this requirement is with @code{TARGET_HARD_REGNO_MODE_OK},
|
||||
or with a filter expression in a @code{define_register_constraint}.
|
||||
|
||||
Register classes used for input-operands of bitwise-and or shift
|
||||
instructions have a special requirement: each such class must have, for
|
||||
|
|
|
@ -360,6 +360,8 @@ main (int argc, const char **argv)
|
|||
printf ("#define MAX_INSNS_PER_PEEP2 0\n");
|
||||
}
|
||||
|
||||
printf ("#define NUM_REGISTER_FILTERS %d\n", register_filters.length ());
|
||||
|
||||
puts ("\n#endif /* GCC_INSN_CONFIG_H */");
|
||||
|
||||
if (ferror (stdout) || fflush (stdout) || fclose (stdout))
|
||||
|
|
146
gcc/genpreds.cc
146
gcc/genpreds.cc
|
@ -677,6 +677,7 @@ public:
|
|||
size_t namelen;
|
||||
const char *regclass; /* for register constraints */
|
||||
rtx exp; /* for other constraints */
|
||||
const char *filter; /* the register filter condition, or null if none */
|
||||
unsigned int is_register : 1;
|
||||
unsigned int is_const_int : 1;
|
||||
unsigned int is_const_dbl : 1;
|
||||
|
@ -763,7 +764,8 @@ mangle (const char *name)
|
|||
is the register class, if any; EXP is the expression to test, if any;
|
||||
IS_MEMORY, IS_SPECIAL_MEMORY, IS_RELAXED_MEMORY and IS_ADDRESS indicate
|
||||
memory, special memory, and address constraints, respectively; LOC is the .md
|
||||
file location.
|
||||
file location; FILTER is the filter condition for a register constraint,
|
||||
or null if none.
|
||||
|
||||
Not all combinations of arguments are valid; most importantly, REGCLASS is
|
||||
mutually exclusive with EXP, and
|
||||
|
@ -776,7 +778,8 @@ mangle (const char *name)
|
|||
static void
|
||||
add_constraint (const char *name, const char *regclass,
|
||||
rtx exp, bool is_memory, bool is_special_memory,
|
||||
bool is_relaxed_memory, bool is_address, file_location loc)
|
||||
bool is_relaxed_memory, bool is_address, file_location loc,
|
||||
const char *filter = nullptr)
|
||||
{
|
||||
class constraint_data *c, **iter, **slot;
|
||||
const char *p;
|
||||
|
@ -908,6 +911,7 @@ add_constraint (const char *name, const char *regclass,
|
|||
c->namelen = namelen;
|
||||
c->regclass = regclass;
|
||||
c->exp = exp;
|
||||
c->filter = filter;
|
||||
c->is_register = regclass != 0;
|
||||
c->is_const_int = is_const_int;
|
||||
c->is_const_dbl = is_const_dbl;
|
||||
|
@ -966,7 +970,8 @@ static void
|
|||
process_define_register_constraint (md_rtx_info *info)
|
||||
{
|
||||
add_constraint (XSTR (info->def, 0), XSTR (info->def, 1),
|
||||
0, false, false, false, false, info->loc);
|
||||
0, false, false, false, false, info->loc,
|
||||
XSTR (info->def, 3));
|
||||
}
|
||||
|
||||
/* Put the constraints into enum order. We want to keep constraints
|
||||
|
@ -1319,6 +1324,34 @@ write_insn_const_int_ok_for_constraint (void)
|
|||
" return false;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
/* Print the init_reg_class_start_regs function, which initializes
|
||||
this_target_constraints->register_filters from the C conditions
|
||||
in the define_register_constraints. */
|
||||
static void
|
||||
write_init_reg_class_start_regs ()
|
||||
{
|
||||
printf ("\n"
|
||||
"void\n"
|
||||
"init_reg_class_start_regs ()\n"
|
||||
"{\n");
|
||||
if (!register_filters.is_empty ())
|
||||
{
|
||||
printf (" for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER;"
|
||||
" ++regno)\n"
|
||||
" {\n");
|
||||
for (unsigned int i = 0; i < register_filters.length (); ++i)
|
||||
{
|
||||
printf (" if (");
|
||||
rtx_reader_ptr->print_c_condition (register_filters[i]);
|
||||
printf (")\n"
|
||||
" SET_HARD_REG_BIT (%s[%d], regno);\n",
|
||||
"this_target_constraints->register_filters", i);
|
||||
}
|
||||
printf (" }\n");
|
||||
}
|
||||
printf ("}\n");
|
||||
}
|
||||
|
||||
/* Write a definition for a function NAME that returns true if a given
|
||||
constraint_num is in the range [START, END). */
|
||||
|
@ -1401,6 +1434,54 @@ print_type_tree (const vec <std::pair <unsigned int, const char *> > &vec,
|
|||
printf ("%*sreturn %s;\n", indent, "", fallback);
|
||||
}
|
||||
|
||||
/* Print the get_register_filter function, which returns a pointer
|
||||
to the start register filter for a given constraint, or null if none. */
|
||||
static void
|
||||
write_get_register_filter ()
|
||||
{
|
||||
constraint_data *c;
|
||||
|
||||
printf ("\n"
|
||||
"#ifdef GCC_HARD_REG_SET_H\n"
|
||||
"static inline const HARD_REG_SET *\n"
|
||||
"get_register_filter (constraint_num%s)\n",
|
||||
register_filters.is_empty () ? "" : " c");
|
||||
printf ("{\n");
|
||||
FOR_ALL_CONSTRAINTS (c)
|
||||
if (c->is_register && c->filter)
|
||||
{
|
||||
printf (" if (c == CONSTRAINT_%s)\n", c->c_name);
|
||||
printf (" return &this_target_constraints->register_filters[%d];\n",
|
||||
get_register_filter_id (c->filter));
|
||||
}
|
||||
printf (" return nullptr;\n"
|
||||
"}\n"
|
||||
"#endif\n");
|
||||
}
|
||||
|
||||
/* Print the get_register_filter_id function, which returns the index
|
||||
of the given constraint's register filter in
|
||||
this_target_constraints->register_filters, or -1 if none. */
|
||||
static void
|
||||
write_get_register_filter_id ()
|
||||
{
|
||||
constraint_data *c;
|
||||
|
||||
printf ("\n"
|
||||
"static inline int\n"
|
||||
"get_register_filter_id (constraint_num%s)\n",
|
||||
register_filters.is_empty () ? "" : " c");
|
||||
printf ("{\n");
|
||||
FOR_ALL_CONSTRAINTS (c)
|
||||
if (c->is_register && c->filter)
|
||||
{
|
||||
printf (" if (c == CONSTRAINT_%s)\n", c->c_name);
|
||||
printf (" return %d;\n", get_register_filter_id (c->filter));
|
||||
}
|
||||
printf (" return -1;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
/* Write tm-preds.h. Unfortunately, it is impossible to forward-declare
|
||||
an enumeration in portable C, so we have to condition all these
|
||||
prototypes on HAVE_MACHINE_MODES. */
|
||||
|
@ -1425,6 +1506,53 @@ write_tm_preds_h (void)
|
|||
|
||||
puts ("#endif /* HAVE_MACHINE_MODES */\n");
|
||||
|
||||
/* Print the definition of the target_constraints structure. */
|
||||
printf ("#ifdef GCC_HARD_REG_SET_H\n"
|
||||
"struct target_constraints {\n"
|
||||
" HARD_REG_SET register_filters[%d];\n",
|
||||
MAX (register_filters.length (), 1));
|
||||
printf ("};\n"
|
||||
"\n"
|
||||
"extern struct target_constraints default_target_constraints;\n"
|
||||
"#if SWITCHABLE_TARGET\n"
|
||||
"extern struct target_constraints *this_target_constraints;\n"
|
||||
"#else\n"
|
||||
"#define this_target_constraints (&default_target_constraints)\n"
|
||||
"#endif\n");
|
||||
|
||||
/* Print TEST_REGISTER_FILTER_BIT, which tests whether register REGNO
|
||||
is a valid start register for register filter ID. */
|
||||
printf ("\n"
|
||||
"#define TEST_REGISTER_FILTER_BIT(ID, REGNO) \\\n");
|
||||
if (register_filters.is_empty ())
|
||||
printf (" ((void) (ID), (void) (REGNO), false)\n");
|
||||
else
|
||||
printf (" TEST_HARD_REG_BIT ("
|
||||
"this_target_constraints->register_filters[ID], REGNO)\n");
|
||||
|
||||
/* Print test_register_filters, which tests whether register REGNO
|
||||
is a valid start register for the mask of register filters in MASK. */
|
||||
printf ("\n"
|
||||
"inline bool\n"
|
||||
"test_register_filters (unsigned int%s, unsigned int%s)\n",
|
||||
register_filters.is_empty () ? "" : " mask",
|
||||
register_filters.is_empty () ? "" : " regno");
|
||||
printf ("{\n");
|
||||
if (register_filters.is_empty ())
|
||||
printf (" return true;\n");
|
||||
else
|
||||
{
|
||||
printf (" for (unsigned int id = 0; id < %d; ++id)\n",
|
||||
register_filters.length ());
|
||||
printf (" if ((mask & (1U << id))\n"
|
||||
"\t&& !TEST_REGISTER_FILTER_BIT (id, regno))\n"
|
||||
" return false;\n"
|
||||
" return true;\n");
|
||||
}
|
||||
printf ("}\n"
|
||||
"#endif\n"
|
||||
"\n");
|
||||
|
||||
if (constraint_max_namelen > 0)
|
||||
{
|
||||
write_enum_constraint_num ();
|
||||
|
@ -1548,6 +1676,9 @@ write_tm_preds_h (void)
|
|||
values.safe_push (std::make_pair (address_end, "CT_FIXED_FORM"));
|
||||
print_type_tree (values, 0, values.length (), "CT_REGISTER", 2);
|
||||
puts ("}");
|
||||
|
||||
write_get_register_filter ();
|
||||
write_get_register_filter_id ();
|
||||
}
|
||||
|
||||
puts ("#endif /* tm-preds.h */");
|
||||
|
@ -1599,6 +1730,13 @@ write_insn_preds_c (void)
|
|||
#include \"tm-constrs.h\"\n\
|
||||
#include \"target.h\"\n");
|
||||
|
||||
printf ("\n"
|
||||
"struct target_constraints default_target_constraints;\n"
|
||||
"#if SWITCHABLE_TARGET\n"
|
||||
"struct target_constraints *this_target_constraints"
|
||||
" = &default_target_constraints;\n"
|
||||
"#endif\n");
|
||||
|
||||
FOR_ALL_PREDICATES (p)
|
||||
write_one_predicate_function (p);
|
||||
|
||||
|
@ -1613,6 +1751,8 @@ write_insn_preds_c (void)
|
|||
if (have_const_int_constraints)
|
||||
write_insn_const_int_ok_for_constraint ();
|
||||
}
|
||||
|
||||
write_init_reg_class_start_regs ();
|
||||
}
|
||||
|
||||
/* Argument parsing. */
|
||||
|
|
|
@ -400,6 +400,45 @@ process_define_predicate (rtx desc, file_location loc)
|
|||
#undef I
|
||||
#undef N
|
||||
#undef Y
|
||||
|
||||
/* Maps register filter conditions to the associated filter identifier. */
|
||||
static hash_map<nofree_string_hash, unsigned int> register_filter_map;
|
||||
|
||||
/* All register filter conditions, indexed by identifier. */
|
||||
vec<const char *> register_filters;
|
||||
|
||||
/* Return the unique identifier for filter condition FILTER. Identifiers
|
||||
are assigned automatically when the define_register_constraint is
|
||||
parsed. */
|
||||
|
||||
unsigned int
|
||||
get_register_filter_id (const char *filter)
|
||||
{
|
||||
unsigned int *slot = register_filter_map.get (filter);
|
||||
gcc_assert (slot);
|
||||
return *slot;
|
||||
}
|
||||
|
||||
/* Process define_register_constraint directive DESC, at location LOC. */
|
||||
|
||||
static void
|
||||
process_define_register_constraint (rtx desc, file_location loc)
|
||||
{
|
||||
/* Assign identifiers to each unique register filter condition. */
|
||||
if (const char *filter = XSTR (desc, 3))
|
||||
{
|
||||
bool existed = false;
|
||||
unsigned int &id = register_filter_map.get_or_insert (filter, &existed);
|
||||
if (!existed)
|
||||
{
|
||||
id = register_filters.length ();
|
||||
if (id == 32)
|
||||
fatal_at (loc, "too many distinct register filters, maximum"
|
||||
" is 32");
|
||||
register_filters.safe_push (filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Queue PATTERN on LIST_TAIL. Return the address of the new queue
|
||||
element. */
|
||||
|
@ -1075,10 +1114,15 @@ process_rtx (rtx desc, file_location loc)
|
|||
case DEFINE_PREDICATE:
|
||||
case DEFINE_SPECIAL_PREDICATE:
|
||||
process_define_predicate (desc, loc);
|
||||
/* Fall through. */
|
||||
queue_pattern (desc, &define_pred_tail, loc);
|
||||
break;
|
||||
|
||||
case DEFINE_REGISTER_CONSTRAINT:
|
||||
process_define_register_constraint (desc, loc);
|
||||
queue_pattern (desc, &define_pred_tail, loc);
|
||||
break;
|
||||
|
||||
case DEFINE_CONSTRAINT:
|
||||
case DEFINE_REGISTER_CONSTRAINT:
|
||||
case DEFINE_MEMORY_CONSTRAINT:
|
||||
case DEFINE_SPECIAL_MEMORY_CONSTRAINT:
|
||||
case DEFINE_RELAXED_MEMORY_CONSTRAINT:
|
||||
|
|
|
@ -108,6 +108,9 @@ struct optab_def
|
|||
extern optab_def optabs[];
|
||||
extern unsigned int num_optabs;
|
||||
|
||||
extern vec<const char *> register_filters;
|
||||
extern unsigned int get_register_filter_id (const char *);
|
||||
|
||||
/* Information about an instruction name that matches an optab pattern. */
|
||||
struct optab_pattern
|
||||
{
|
||||
|
|
|
@ -140,6 +140,9 @@ reginfo_cc_finalize (void)
|
|||
CLEAR_HARD_REG_SET (global_reg_set);
|
||||
}
|
||||
|
||||
/* In insn-preds.cc. */
|
||||
extern void init_reg_class_start_regs ();
|
||||
|
||||
/* Given a register bitmap, turn on the bits in a HARD_REG_SET that
|
||||
correspond to the hard registers, if any, set in that map. This
|
||||
could be done far more efficiently by having all sorts of special-cases
|
||||
|
@ -198,6 +201,8 @@ init_reg_sets (void)
|
|||
|
||||
SET_HARD_REG_SET (accessible_reg_set);
|
||||
SET_HARD_REG_SET (operand_reg_set);
|
||||
|
||||
init_reg_class_start_regs ();
|
||||
}
|
||||
|
||||
/* We need to save copies of some of the register information which
|
||||
|
|
|
@ -1016,8 +1016,10 @@ DEF_RTL_EXPR(DEFINE_SPECIAL_PREDICATE, "define_special_predicate", "ses", RTX_EX
|
|||
at -m switches and the like.
|
||||
2: A docstring for this constraint, in Texinfo syntax; not currently
|
||||
used, in future will be incorporated into the manual's list of
|
||||
machine-specific operand constraints. */
|
||||
DEF_RTL_EXPR(DEFINE_REGISTER_CONSTRAINT, "define_register_constraint", "sss", RTX_EXTRA)
|
||||
machine-specific operand constraints.
|
||||
3: A C expression that evalutes to true if "regno" is a valid
|
||||
start register. */
|
||||
DEF_RTL_EXPR(DEFINE_REGISTER_CONSTRAINT, "define_register_constraint", "sssS", RTX_EXTRA)
|
||||
|
||||
/* Definition of a non-register operand constraint. These look at the
|
||||
operand and decide whether it fits the constraint.
|
||||
|
|
|
@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "bb-reorder.h"
|
||||
#include "lower-subreg.h"
|
||||
#include "function-abi.h"
|
||||
#include "tm_p.h"
|
||||
|
||||
#if SWITCHABLE_TARGET
|
||||
class target_globals default_target_globals = {
|
||||
|
@ -60,7 +61,8 @@ class target_globals default_target_globals = {
|
|||
&default_target_builtins,
|
||||
&default_target_gcse,
|
||||
&default_target_bb_reorder,
|
||||
&default_target_lower_subreg
|
||||
&default_target_lower_subreg,
|
||||
&default_target_constraints
|
||||
};
|
||||
|
||||
class target_globals *
|
||||
|
@ -84,6 +86,7 @@ save_target_globals (void)
|
|||
g->gcse = XCNEW (struct target_gcse);
|
||||
g->bb_reorder = XCNEW (struct target_bb_reorder);
|
||||
g->lower_subreg = XCNEW (struct target_lower_subreg);
|
||||
g->constraints = XCNEW (target_constraints);
|
||||
restore_target_globals (g);
|
||||
init_reg_sets ();
|
||||
target_reinit ();
|
||||
|
@ -141,6 +144,7 @@ target_globals::~target_globals ()
|
|||
XDELETE (gcse);
|
||||
XDELETE (bb_reorder);
|
||||
XDELETE (lower_subreg);
|
||||
XDELETE (constraints);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ extern struct target_builtins *this_target_builtins;
|
|||
extern struct target_gcse *this_target_gcse;
|
||||
extern struct target_bb_reorder *this_target_bb_reorder;
|
||||
extern struct target_lower_subreg *this_target_lower_subreg;
|
||||
extern struct target_constraints *this_target_constraints;
|
||||
#endif
|
||||
|
||||
class GTY(()) target_globals {
|
||||
|
@ -61,6 +62,7 @@ public:
|
|||
struct target_gcse *GTY((skip)) gcse;
|
||||
struct target_bb_reorder *GTY((skip)) bb_reorder;
|
||||
struct target_lower_subreg *GTY((skip)) lower_subreg;
|
||||
struct target_constraints *GTY((skip)) constraints;
|
||||
};
|
||||
|
||||
#if SWITCHABLE_TARGET
|
||||
|
@ -89,6 +91,7 @@ restore_target_globals (class target_globals *g)
|
|||
this_target_gcse = g->gcse;
|
||||
this_target_bb_reorder = g->bb_reorder;
|
||||
this_target_lower_subreg = g->lower_subreg;
|
||||
this_target_constraints = g->constraints;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue