On 11/12/23 07:52, Richard Sandiford wrote:
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.
OK. Mostly focused on the concept -- if we need to iterate on the implementation after your using it we can certainly do that.

Jeff

Reply via email to