On Fri, Jun 20, 2025 at 10:17:20AM -0400, Vladimir Makarov wrote:
>
> On 5/20/25 3:22 AM, Stefan Schulze Frielinghaus wrote:
> > Implement hard register constraints of the form {regname} where regname
> > must be a valid register name for the target. Such constraints may be
> > used in asm statements as a replacement for register asm and in machine
> > descriptions.
> >
> > ---
> > gcc/config/cris/cris.cc | 6 +-
> > gcc/config/i386/i386.cc | 6 +
> > gcc/config/s390/s390.cc | 6 +-
> > gcc/doc/extend.texi | 178 ++++++++++++++++++
> > gcc/doc/md.texi | 6 +
> > gcc/function.cc | 116 ++++++++++++
> > gcc/genoutput.cc | 14 ++
> > gcc/genpreds.cc | 4 +-
> > gcc/ira.cc | 79 +++++++-
> > gcc/lra-constraints.cc | 13 ++
> > gcc/recog.cc | 11 +-
> > gcc/stmt.cc | 39 ++++
> > gcc/stmt.h | 1 +
> > gcc/testsuite/gcc.dg/asm-hard-reg-1.c | 85 +++++++++
> > gcc/testsuite/gcc.dg/asm-hard-reg-2.c | 33 ++++
> > gcc/testsuite/gcc.dg/asm-hard-reg-3.c | 25 +++
> > gcc/testsuite/gcc.dg/asm-hard-reg-4.c | 50 +++++
> > gcc/testsuite/gcc.dg/asm-hard-reg-5.c | 36 ++++
> > gcc/testsuite/gcc.dg/asm-hard-reg-6.c | 60 ++++++
> > gcc/testsuite/gcc.dg/asm-hard-reg-7.c | 41 ++++
> > gcc/testsuite/gcc.dg/asm-hard-reg-8.c | 49 +++++
> > .../gcc.target/aarch64/asm-hard-reg-1.c | 55 ++++++
> > .../gcc.target/i386/asm-hard-reg-1.c | 115 +++++++++++
> > .../gcc.target/s390/asm-hard-reg-1.c | 103 ++++++++++
> > .../gcc.target/s390/asm-hard-reg-2.c | 43 +++++
> > .../gcc.target/s390/asm-hard-reg-3.c | 42 +++++
> > .../gcc.target/s390/asm-hard-reg-4.c | 6 +
> > .../gcc.target/s390/asm-hard-reg-5.c | 6 +
> > .../gcc.target/s390/asm-hard-reg-6.c | 152 +++++++++++++++
> > .../gcc.target/s390/asm-hard-reg-longdouble.h | 18 ++
> > 30 files changed, 1391 insertions(+), 7 deletions(-)
> > create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-1.c
> > create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-2.c
> > create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-3.c
> > create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-4.c
> > create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-5.c
> > create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-6.c
> > create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-7.c
> > create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-8.c
> > create mode 100644 gcc/testsuite/gcc.target/aarch64/asm-hard-reg-1.c
> > create mode 100644 gcc/testsuite/gcc.target/i386/asm-hard-reg-1.c
> > create mode 100644 gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c
> > create mode 100644 gcc/testsuite/gcc.target/s390/asm-hard-reg-2.c
> > create mode 100644 gcc/testsuite/gcc.target/s390/asm-hard-reg-3.c
> > create mode 100644 gcc/testsuite/gcc.target/s390/asm-hard-reg-4.c
> > create mode 100644 gcc/testsuite/gcc.target/s390/asm-hard-reg-5.c
> > create mode 100644 gcc/testsuite/gcc.target/s390/asm-hard-reg-6.c
> > create mode 100644 gcc/testsuite/gcc.target/s390/asm-hard-reg-longdouble.h
> > diff --git a/gcc/ira.cc b/gcc/ira.cc
> > index 885239d1b43..c32d4ceab88 100644
> > --- a/gcc/ira.cc
> > +++ b/gcc/ira.cc
> > @@ -2113,6 +2113,82 @@ ira_get_dup_out_num (int op_num, alternative_mask
> > alts,
> >
> > +/* Return true if a replacement of SRC by DEST does not lead to
> > unsatisfiable
> > + asm. Thus, a replacement is valid if and only if SRC and DEST are not
> > + constrained in asm inputs of a single asm statement. See
> > + match_asm_constraints_2() for more details. TODO: As in
> > + match_asm_constraints_2() consider alternatives more precisely. */
> > +
> > +static bool
> > +valid_replacement_for_asm_input_p_1 (const_rtx asmops, const_rtx src,
> > const_rtx dest)
> > +{
> > + int ninputs = ASM_OPERANDS_INPUT_LENGTH (asmops);
> > + rtvec inputs = ASM_OPERANDS_INPUT_VEC (asmops);
> > + for (int i = 0; i < ninputs; ++i)
> > + {
> > + rtx input_src = RTVEC_ELT (inputs, i);
> > + const char *constraint_src
> > + = ASM_OPERANDS_INPUT_CONSTRAINT (asmops, i);
> > + if (rtx_equal_p (input_src, src)
> > + && strchr (constraint_src, '{') != nullptr)
> > + for (int j = 0; j < ninputs; ++j)
> > + {
> > + rtx input_dest = RTVEC_ELT (inputs, j);
> > + const char *constraint_dest
> > + = ASM_OPERANDS_INPUT_CONSTRAINT (asmops, j);
> > + if (rtx_equal_p (input_dest, dest)
> > + && strchr (constraint_dest, '{') != nullptr)
> > + return false;
> > + }
> > + }
> > + return true;
> > +}
> > +
> > +static bool
> > +valid_replacement_for_asm_input_p (const_rtx src, const_rtx dest)
> > +{
> > + /* Bail out early if there is no asm statement. */
> > + if (!crtl->has_asm_statement)
> > + return true;
> > + for (df_ref use = DF_REG_USE_CHAIN (REGNO (src));
> > + use;
> > + use = DF_REF_NEXT_REG (use))
> > + {
> > + struct df_insn_info *use_info = DF_REF_INSN_INFO (use);
> > + /* Only check real uses, not artificial ones. */
> > + if (use_info)
> > + {
> > + rtx_insn *insn = DF_REF_INSN (use);
> > + rtx pat = PATTERN (insn);
> > + if (asm_noperands (pat) <= 0)
> > + continue;
> > + if (GET_CODE (pat) == SET)
> > + {
> > + if (!valid_replacement_for_asm_input_p_1 (SET_SRC (pat), src,
> > dest))
> > + return false;
> > + }
> > + else if (GET_CODE (pat) == PARALLEL)
> > + for (int i = 0, len = XVECLEN (pat, 0); i < len; ++i)
> > + {
> > + rtx asmops = XVECEXP (pat, 0, i);
> > + if (GET_CODE (asmops) == SET)
> > + asmops = SET_SRC (asmops);
> > + if (GET_CODE (asmops) == ASM_OPERANDS
> > + && !valid_replacement_for_asm_input_p_1 (asmops, src, dest))
> > + return false;
> > + }
> > + else if (GET_CODE (pat) == ASM_OPERANDS)
> > + {
> > + if (!valid_replacement_for_asm_input_p_1 (pat, src, dest))
> > + return false;
> > + }
> > + else
> > + gcc_unreachable ();
> > + }
> > + }
> > + return true;
> > +}
> > +
> > /* Search forward to see if the source register of a copy insn dies
> > before either it or the destination register is modified, but don't
> > scan past the end of the basic block. If so, we can replace the
> > @@ -2162,7 +2238,8 @@ decrease_live_ranges_number (void)
> > auto-inc memory reference, so we must disallow this
> > optimization on them. */
> > || sregno == STACK_POINTER_REGNUM
> > - || dregno == STACK_POINTER_REGNUM)
> > + || dregno == STACK_POINTER_REGNUM
> > + || !valid_replacement_for_asm_input_p (src, dest))
> > continue;
> > dest_death = NULL_RTX;
> > diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc
> > index 7dbc7fe1e00..689a12b2c71 100644
> > --- a/gcc/lra-constraints.cc
> > +++ b/gcc/lra-constraints.cc
> > @@ -114,6 +114,7 @@
> > #include "target.h"
> > #include "rtl.h"
> > #include "tree.h"
> > +#include "stmt.h"
> > #include "predict.h"
> > #include "df.h"
> > #include "memmodel.h"
> > @@ -2175,6 +2176,7 @@ process_alt_operands (int only_alternative)
> > bool costly_p;
> > enum reg_class cl;
> > const HARD_REG_SET *cl_filter;
> > + HARD_REG_SET hard_reg_constraint;
> > /* Calculate some data common for all alternatives to speed up the
> > function. */
> > @@ -2551,6 +2553,17 @@ process_alt_operands (int only_alternative)
> > cl_filter = nullptr;
> > goto reg;
> > + case '{':
> > + {
> > + int regno = decode_hard_reg_constraint (p);
> > + gcc_assert (regno >= 0);
> > + cl = REGNO_REG_CLASS (regno);
> > + CLEAR_HARD_REG_SET (hard_reg_constraint);
> > + SET_HARD_REG_BIT (hard_reg_constraint, regno);
> > + cl_filter = &hard_reg_constraint;
> > + goto reg;
> > + }
> > +
> > default:
> > cn = lookup_constraint (p);
> > switch (get_constraint_type (cn))
>
>
> The RA part of the patch is OK for me. The changes are pretty obvious. It
> would be nice to add a short comment to valid_replacement_for_asm_input_p
> mentioning valid_replacement_for_asm_input_p_1 but it is not obligatory.
>
> Thank you for your work on this new GCC feature.
Thanks for the review. Very much appreciated!
I added a comment to valid_replacement_for_asm_input_p().
Out of curiosity, do you have any idea how to tackle fixed registers?
This is the last remaining piece for a full fledged solution. Certainly
not required for this patch but something I would like to look into in
the future.
Cheers,
Stefan