On Thu, Sep 12, 2024 at 04:03:33PM +0200, Georg-Johann Lay wrote:
> 
> 
> Am 10.09.24 um 16:20 schrieb Stefan Schulze Frielinghaus:
> > This series introduces hard register constraints.  The first patch
> > enables hard register constraints for asm statements and for
> > machine descriptions.  The subsequent patch adds some basic error
> > handling for asm statements.  The third patch adds some verification of
> > register names used in machine description.  The fourth and last patch
> > adds the feature of rewriting local register asm into hard register
> > constraints.
> > 
> > This series was bootstrapped and regtested on s390.  Furthermore, the
> > new dg-compile tests were verified via cross compilers for the enabled
> > targets.  There is still some fallout if -fdemote-register-asm is used
> > since a couple of features are missing as e.g. erroring out during
> > gimplification if the clobber set of registers intersects with
> > input/output registers.
> > 
> > As a larger test vehicle I've compiled and regtested glibc on s390 using
> > -fdemote-register-asm without any fallout.  On x86_64 this fails due to
> > the limitation that fixed registers are currently not supported for hard
> > register constraints (see commit message of the first patch).  This is
> > also the reason why I'm posting this series already since I was hoping
> > to get some feedback about this limitation.
> > 
> > Furthermore, I've compiled the Linux kernel on s390 and x86_64 with
> > -fdemote-register-asm.  Interestingly, the Linux kernel for x86_64 makes
> > use of the following asm statement:
> > 
> > #define call_on_stack(stack, func, asm_call, argconstr...)              \
> > {                                                                       \
> >          register void *tos asm("r11");                                  \
> >                                                                          \
> >          tos = ((void *)(stack));                                        \
> >                                                                          \
> >          asm_inline volatile(                                            \
> >          "movq   %%rsp, (%[tos])                         \n"             \
> >          "movq   %[tos], %%rsp                           \n"             \
> >                                                                          \
> >          asm_call                                                        \
> >                                                                          \
> >          "popq   %%rsp                                   \n"             \
> >                                                                          \
> >          : "+r" (tos), ASM_CALL_CONSTRAINT                               \
> >          : [__func] "i" (func), [tos] "r" (tos) argconstr                \
> >          : "cc", "rax", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10",   \
> >            "memory"                                                      \
> >          );                                                              \
> > }
> > 
> > Note the output
> >    "+r" (tos)
> > and the input
> >    [tos] "r" (tos)
> > Currently I error out for this since I consider this as two inputs using
> > the same hard register.  One time an implicit input via '+' and a second
> > time via the explicit input.  Thus, actually I would expect a '='
> 
> Would you explain why the two operands are supposed to live in the same
> hard register?
> 
> From my understanding of asm semantics, this gives you two copies of
> tos:  The 1st one may be altered by the asm, and the 2nd one may not be
> changed.  As the operands neither refer to each other by "0" nor don't
> they use the same (single-register) register constraint, there is no
> reason / requirement to allocate the two operands to the same reg, no?

During gimplification an inout operand is canonicalized into one output
and one input operand.  The input operand refers via a digit to the
output operand.  For example

asm ("" : "+r" (x));

is rewritten into

asm ("" : "=r" (x) : "0" (x));

I didn't find documentation how "digit references" behave in combination
with register asm.  At least it is not defined here
https://gcc.gnu.org/onlinedocs/gcc/Simple-Constraints.html#index-0-in-constraint
https://gcc.gnu.org/onlinedocs/gcc/Explicit-Register-Variables.html
which is why I broad this up.

In combination with an explicit input, the situation is a bit unclear to
me:

asm ("" : "+r" (x) : "r" (x));

becomes

asm ("" : "=r" (x) : "0" (x), "r" (x));

If x is a register asm, do all three operands end up in the same
register (N.B. this is exactly the situation from above)?  At least this
is the current implementation and I think this also aligns with how
"aliases" are implemented which puzzled me first:

register int x asm ("0") = 42;
register int y asm ("0") = 24;
asm ("" : "=r" (x) : "r" (y));

Anyway, I digress.  I haven't made up my mind how hard register
constraints should behave in those cases, i.e., in cases where multiple
inputs share the same register.  If the inputs are different or may be
different, then we can reject those programs.

asm ("" : "={r4}" (x) : "{r5}" (42), "{r5}" (24));

Whereas if the operands are provable equal (assuming y is not volatile)

asm ("" : "={r4}" (x) : "{r5}" (y), "{r5}" (y));

we could accept those programs.  Currently, I error out even for
programs of the latter form which may be a bit to restrictive.

At the moment I'm using -fdemote-register-asm in order to find those
corner cases I haven't thought about a priori.  Therefore, any input is
highly welcomed.

I will also come up with some documentation in the coming days.

Cheers,
Stefan

> 
> Johann
> 
> 
> > instead of a '+' for the output constraint since the input is explicitly
> > mentioned, or remove the input entirely and just use the inoutput
> >     [tos] "+r" (tos)
> > If you consider this valid asm I would have to adjust the error
> > handling.  Either way, this is just about error handling and doesn't
> > really affect code generation.
> > 
> > Stefan Schulze Frielinghaus (4):
> >    Hard register constraints
> >    Error handling for hard register constraints
> >    genoutput: Verify hard register constraints
> >    Rewrite register asm into hard register constraints
> > 
> >   gcc/cfgexpand.cc                              |  42 ---
> >   gcc/common.opt                                |   4 +
> >   gcc/function.cc                               | 116 ++++++++
> >   gcc/genoutput.cc                              |  60 ++++
> >   gcc/genpreds.cc                               |   4 +-
> >   gcc/gimplify.cc                               | 151 +++++++++-
> >   gcc/gimplify_reg_info.h                       | 130 +++++++++
> >   gcc/ira.cc                                    |  79 +++++-
> >   gcc/lra-constraints.cc                        |  13 +
> >   gcc/output.h                                  |   2 +
> >   gcc/recog.cc                                  |  11 +-
> >   gcc/stmt.cc                                   | 268 +++++++++++++++++-
> >   gcc/stmt.h                                    |   9 +-
> >   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.dg/asm-hard-reg-demotion-1.c          |  19 ++
> >   .../gcc.dg/asm-hard-reg-demotion-2.c          |  19 ++
> >   gcc/testsuite/gcc.dg/asm-hard-reg-demotion.h  |  52 ++++
> >   gcc/testsuite/gcc.dg/asm-hard-reg-error-1.c   |  83 ++++++
> >   gcc/testsuite/gcc.dg/asm-hard-reg-error-2.c   |  20 ++
> >   gcc/testsuite/gcc.dg/asm-hard-reg-error-3.c   |  21 ++
> >   gcc/testsuite/gcc.dg/pr87600-2.c              |  30 +-
> >   gcc/testsuite/gcc.dg/pr87600-3.c              |  35 +++
> >   gcc/testsuite/gcc.dg/pr87600-3.s              |   0
> >   .../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/testsuite/lib/scanasm.exp                 |   4 +
> >   gcc/toplev.cc                                 |   4 +
> >   35 files changed, 1656 insertions(+), 87 deletions(-)
> >   create mode 100644 gcc/gimplify_reg_info.h
> >   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.dg/asm-hard-reg-demotion-1.c
> >   create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-demotion-2.c
> >   create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-demotion.h
> >   create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-error-1.c
> >   create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-error-2.c
> >   create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-error-3.c
> >   create mode 100644 gcc/testsuite/gcc.dg/pr87600-3.c
> >   create mode 100644 gcc/testsuite/gcc.dg/pr87600-3.s
> >   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
> > 

Reply via email to