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.
