https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122716

--- Comment #3 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Tamar Christina <[email protected]>:

https://gcc.gnu.org/g:f90f1468590ad46c0a64a3ba4a72ff7967d7c498

commit r17-6105-gf90f1468590ad46c0a64a3ba4a72ff7967d7c498
Author: Tamar Christina <[email protected]>
Date:   Tue Nov 10 11:34:33 2026 +0000

    middle-end: support multi-character output operand modifiers [PR122716]

    Today output operand modifiers are limited to a single character, as in %w0
or
    %c1.  That works, but it makes the modifier namespace very small and
encourages
    target ports either to use cryptic letters or to fall back to C output
blocks
    for cases that are really just target-specific printing.

    This patch adds a longer spelling for the same mechanism:

      %[name:0]

    The bracketed spelling is intentionally familiar rather than completely
new:
    extended asm already uses %[Value] to refer to an operand with a symbolic
name,
    as in:

      asm ("add %[out], %[in], %[imm]"
           : [out] "=r" (out)
           : [in] "r" (in), [imm] "I" (1));

    That existing form keeps its meaning.  A bare %[Value] is still resolved by
the
    front end as a symbolic operand reference.  The new print-operand form puts
the
    modifier name before a colon and the operand number inside the brackets, as
in
    %[name:0].  The form %[0] also lets a template separate an operand number
from
    any literal digits that follow.

    The modifier syntax can also be combined with symbolic operand names.  In
user
    asm, %[modifier:Value] means "print operand Value using the multi-character
    modifier named modifier".  The front end resolves Value to an operand
number, so
    final output sees the same thing it would have seen for %[modifier:N].  For
    example:

      asm ("mov %[w:out], %[w:in]"
           : [out] "=r" (out)
           : [in] "r" (in));

    is resolved as if the template had used %[w:0] and %[w:1].

    GCC parses the bracketed modifier name and asks the new
    TARGET_PRINT_OPERAND_MODIFIER hook for the integer code to pass to
    PRINT_OPERAND.  The target owns the names and codes, which must be outside
the
    single-character range.  Old-style modifiers keep their existing values, so
    existing target hooks continue to see 'w', 'c', etc. for those forms.

    For example, a machine description can now write something like:

      "extract\t%[lowpart:0], %1"

    and the target's PRINT_OPERAND hook can handle "lowpart" as a named
modifier.
    The parser also allows comma-separated nonempty components in the brackets,
but
    deliberately leaves the interpretation of those components to the target.

    A named modifier can also take several operands, as in %[name:0,1].
    PRINT_OPERAND receives the first operand as usual, and can use
    output_operand_modifier_operand (code, i) to get the others.  All operands
in
    the list are recorded as referenced, including those that the target prints
    through this helper.  This requires the use of a temporary global variable.
    current_modifier_opnums which is my least favorite part of this but I don't
    see another way around it...

    The new hook also receives a flag saying whether the modifier came from
user asm
    or an internal machine-description output template.  Targets can reject
    internal-only names in user-facing asm while still using the clearer names
    internally.  The front end checks named modifiers too, so invalid user asm
is
    rejected even if it would later be optimized away.

    This addresses Richard Earnshaw's suggestion by keeping the target hook
    interface as an int code and mapping the longer spelling onto values
outside the
    single-character range.  The default hook rejects named modifiers, so
targets
    that do not opt in keep the existing syntax.  Existing hard-coded character
uses
    continue to work.

    It also addresses Richard Sandiford's feedback by giving the new %[...]
syntax
    its own namespace rather than automatically exposing every single-letter
    modifier through the new spelling.  The user-asm flag lets a target decide
which
    named modifiers are public and which are only for compiler-generated
templates.
    The comma-separated spelling is accepted as a target-defined modifier
string, so
    a port can later treat, say, %[gpr,zero:0] as a composition of
target-specific
    printing choices without requiring more middle-end syntax.

    I also used a little bit of C++ to clean up the parsing code, the diff
shows
    a lot of movements but the final code is simpler.

    I decided to support the multiple operands case now, as that allowed me to
clean
    up the CONST_INT cases and while doing so fixing the existing ambiguity
with
    %[foo]0 being able to resolve to %10.

    gcc/ChangeLog:

            PR target/122716
            * doc/extend.texi: Document named asm operand modifiers.
            * doc/md.texi: Document bracketed operands and operand lists.
            * doc/tm.texi: Regenerate.
            * doc/tm.texi.in (PRINT_OPERAND): Document named modifier codes and
            output_operand_modifier_operand.
            (TARGET_PRINT_OPERAND_MODIFIER): Add hook reference.
            * final.cc: Include selftest.h.
            (current_modifier_operands, current_modifier_opnums): New
variables.
            (output_operand_modifier_operand, output_bracketed_operand): New
            functions.
            (output_asm_insn): Handle bracketed operands.
            (selftest::test_parse_bracketed_operand): New test.
            (selftest::test_referenced_operands): Likewise.
            (selftest::test_output_operand_modifier_operand): Likewise.
            (selftest::final_cc_tests): Run them.
            * output.h (PRINT_OPERAND_MODIFIER_BASE): New constant.
            (output_operand_modifier_operand): Declare.
            * recog.cc (parse_bracketed_operand): New function.
            (get_referenced_operands): Handle bracketed operands and operand
lists.
            Handle %ccN and a trailing percent sign.
            * recog.h (bracketed_operand): New structure.
            (parse_bracketed_operand): Declare.
            * selftest-run-tests.cc (selftest::run_tests): Call final_cc_tests
and
            stmt_cc_tests.
            * selftest.h (final_cc_tests, stmt_cc_tests): Declare.
            * stmt.cc: Include selftest.h when checking is enabled.
            (resolve_operand_name_1): Remove.
            (asm_operand_name_number, asm_obstack_grow_opnum): New functions.
            (resolve_asm_operand_names): Resolve bracketed operand lists and
check
            named modifiers.  Share bracket parsing and build strings from
obstack
            lengths.
            (selftest::build_asm_operand, selftest::build_asm_label): New
helpers.
            (selftest::test_asm_operand_modifier): Likewise.
            (selftest::test_resolve_asm_operand_names): New test.
            (selftest::stmt_cc_tests): Run it.
            * target.def (print_operand_modifier): New hook.
            * targhooks.cc (default_print_operand_modifier): New function.
            * targhooks.h (default_print_operand_modifier): Declare.

Reply via email to