[committed] contrib: add mdcompact

Message ID 20231005154745.2663497-1-andrea.corallo@arm.com
State Accepted
Headers
Series [committed] contrib: add mdcompact |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Andrea Corallo Oct. 5, 2023, 3:47 p.m. UTC
  Hello all,

this patch checks in mdcompact, the tool written in elisp that I used
to mass convert all the multi choice pattern in the aarch64 back-end to
the new compact syntax.

I tested it on Emacs 29 (might run on older versions as well not
sure), also I verified it runs cleanly on a few other back-ends (arm,
loongarch).

The tool can be used to convert a single pattern, an open buffer or
all md files in a directory.

The tool might need further adjustment to run on some specific
back-end, in case very happy to help.

This patch was pre-approved here [1].

Best Regards

  Andrea Corallo

[1] <https://gcc.gnu.org/pipermail/gcc-patches/2023-October/631830.html>

contrib/ChangeLog

	* mdcompact/mdcompact-testsuite.el: New file.
	* mdcompact/mdcompact.el: Likewise.
	* mdcompact/tests/1.md: Likewise.
	* mdcompact/tests/1.md.out: Likewise.
	* mdcompact/tests/2.md: Likewise.
	* mdcompact/tests/2.md.out: Likewise.
	* mdcompact/tests/3.md: Likewise.
	* mdcompact/tests/3.md.out: Likewise.
	* mdcompact/tests/4.md: Likewise.
	* mdcompact/tests/4.md.out: Likewise.
	* mdcompact/tests/5.md: Likewise.
	* mdcompact/tests/5.md.out: Likewise.
	* mdcompact/tests/6.md: Likewise.
	* mdcompact/tests/6.md.out: Likewise.
	* mdcompact/tests/7.md: Likewise.
	* mdcompact/tests/7.md.out: Likewise.
---
 contrib/mdcompact/mdcompact-testsuite.el |  56 +++++
 contrib/mdcompact/mdcompact.el           | 296 +++++++++++++++++++++++
 contrib/mdcompact/tests/1.md             |  36 +++
 contrib/mdcompact/tests/1.md.out         |  32 +++
 contrib/mdcompact/tests/2.md             |  25 ++
 contrib/mdcompact/tests/2.md.out         |  21 ++
 contrib/mdcompact/tests/3.md             |  16 ++
 contrib/mdcompact/tests/3.md.out         |  17 ++
 contrib/mdcompact/tests/4.md             |  17 ++
 contrib/mdcompact/tests/4.md.out         |  17 ++
 contrib/mdcompact/tests/5.md             |  12 +
 contrib/mdcompact/tests/5.md.out         |  11 +
 contrib/mdcompact/tests/6.md             |  11 +
 contrib/mdcompact/tests/6.md.out         |  11 +
 contrib/mdcompact/tests/7.md             |  11 +
 contrib/mdcompact/tests/7.md.out         |  11 +
 16 files changed, 600 insertions(+)
 create mode 100644 contrib/mdcompact/mdcompact-testsuite.el
 create mode 100644 contrib/mdcompact/mdcompact.el
 create mode 100644 contrib/mdcompact/tests/1.md
 create mode 100644 contrib/mdcompact/tests/1.md.out
 create mode 100644 contrib/mdcompact/tests/2.md
 create mode 100644 contrib/mdcompact/tests/2.md.out
 create mode 100644 contrib/mdcompact/tests/3.md
 create mode 100644 contrib/mdcompact/tests/3.md.out
 create mode 100644 contrib/mdcompact/tests/4.md
 create mode 100644 contrib/mdcompact/tests/4.md.out
 create mode 100644 contrib/mdcompact/tests/5.md
 create mode 100644 contrib/mdcompact/tests/5.md.out
 create mode 100644 contrib/mdcompact/tests/6.md
 create mode 100644 contrib/mdcompact/tests/6.md.out
 create mode 100644 contrib/mdcompact/tests/7.md
 create mode 100644 contrib/mdcompact/tests/7.md.out
  

Comments

Richard Biener Oct. 6, 2023, 6:43 a.m. UTC | #1
On Thu, Oct 5, 2023 at 5:49 PM Andrea Corallo <andrea.corallo@arm.com> wrote:
>
> Hello all,
>
> this patch checks in mdcompact, the tool written in elisp that I used
> to mass convert all the multi choice pattern in the aarch64 back-end to
> the new compact syntax.
>
> I tested it on Emacs 29 (might run on older versions as well not
> sure), also I verified it runs cleanly on a few other back-ends (arm,
> loongarch).
>
> The tool can be used to convert a single pattern, an open buffer or
> all md files in a directory.
>
> The tool might need further adjustment to run on some specific
> back-end, in case very happy to help.
>
> This patch was pre-approved here [1].

Does the result generate identical insn-*.cc files?

> Best Regards
>
>   Andrea Corallo
>
> [1] <https://gcc.gnu.org/pipermail/gcc-patches/2023-October/631830.html>
>
> contrib/ChangeLog
>
>         * mdcompact/mdcompact-testsuite.el: New file.
>         * mdcompact/mdcompact.el: Likewise.
>         * mdcompact/tests/1.md: Likewise.
>         * mdcompact/tests/1.md.out: Likewise.
>         * mdcompact/tests/2.md: Likewise.
>         * mdcompact/tests/2.md.out: Likewise.
>         * mdcompact/tests/3.md: Likewise.
>         * mdcompact/tests/3.md.out: Likewise.
>         * mdcompact/tests/4.md: Likewise.
>         * mdcompact/tests/4.md.out: Likewise.
>         * mdcompact/tests/5.md: Likewise.
>         * mdcompact/tests/5.md.out: Likewise.
>         * mdcompact/tests/6.md: Likewise.
>         * mdcompact/tests/6.md.out: Likewise.
>         * mdcompact/tests/7.md: Likewise.
>         * mdcompact/tests/7.md.out: Likewise.
> ---
>  contrib/mdcompact/mdcompact-testsuite.el |  56 +++++
>  contrib/mdcompact/mdcompact.el           | 296 +++++++++++++++++++++++
>  contrib/mdcompact/tests/1.md             |  36 +++
>  contrib/mdcompact/tests/1.md.out         |  32 +++
>  contrib/mdcompact/tests/2.md             |  25 ++
>  contrib/mdcompact/tests/2.md.out         |  21 ++
>  contrib/mdcompact/tests/3.md             |  16 ++
>  contrib/mdcompact/tests/3.md.out         |  17 ++
>  contrib/mdcompact/tests/4.md             |  17 ++
>  contrib/mdcompact/tests/4.md.out         |  17 ++
>  contrib/mdcompact/tests/5.md             |  12 +
>  contrib/mdcompact/tests/5.md.out         |  11 +
>  contrib/mdcompact/tests/6.md             |  11 +
>  contrib/mdcompact/tests/6.md.out         |  11 +
>  contrib/mdcompact/tests/7.md             |  11 +
>  contrib/mdcompact/tests/7.md.out         |  11 +
>  16 files changed, 600 insertions(+)
>  create mode 100644 contrib/mdcompact/mdcompact-testsuite.el
>  create mode 100644 contrib/mdcompact/mdcompact.el
>  create mode 100644 contrib/mdcompact/tests/1.md
>  create mode 100644 contrib/mdcompact/tests/1.md.out
>  create mode 100644 contrib/mdcompact/tests/2.md
>  create mode 100644 contrib/mdcompact/tests/2.md.out
>  create mode 100644 contrib/mdcompact/tests/3.md
>  create mode 100644 contrib/mdcompact/tests/3.md.out
>  create mode 100644 contrib/mdcompact/tests/4.md
>  create mode 100644 contrib/mdcompact/tests/4.md.out
>  create mode 100644 contrib/mdcompact/tests/5.md
>  create mode 100644 contrib/mdcompact/tests/5.md.out
>  create mode 100644 contrib/mdcompact/tests/6.md
>  create mode 100644 contrib/mdcompact/tests/6.md.out
>  create mode 100644 contrib/mdcompact/tests/7.md
>  create mode 100644 contrib/mdcompact/tests/7.md.out
>
> diff --git a/contrib/mdcompact/mdcompact-testsuite.el b/contrib/mdcompact/mdcompact-testsuite.el
> new file mode 100644
> index 00000000000..494c0b5cd68
> --- /dev/null
> +++ b/contrib/mdcompact/mdcompact-testsuite.el
> @@ -0,0 +1,56 @@
> +;;; -*- lexical-binding: t; -*-
> +
> +;; This file is part of GCC.
> +
> +;; GCC is free software: you can redistribute it and/or modify it
> +;; under the terms of the GNU General Public License as published by
> +;; the Free Software Foundation, either version 3 of the License, or
> +;; (at your option) any later version.
> +
> +;; GCC is distributed in the hope that it will be useful, but WITHOUT
> +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> +;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> +;; License for more details.
> +
> +;; You should have received a copy of the GNU General Public License
> +;; along with GCC.  If not, see <https://www.gnu.org/licenses/>.
> +
> +;;; Commentary:
> +
> +;;; Usage:
> +;; $ emacs -batch -l mdcompact.el -l mdcompact-testsuite.el -f ert-run-tests-batch-and-exit
> +
> +;;; Code:
> +
> +(require 'mdcompact)
> +(require 'ert)
> +
> +(defconst mdcompat-test-directory (concat (file-name-directory
> +                                          (or load-file-name
> +                                               buffer-file-name))
> +                                         "tests/"))
> +
> +(defun mdcompat-test-run (f)
> +  (with-temp-buffer
> +    (insert-file-contents f)
> +    (mdcomp-run-at-point)
> +    (let ((a (buffer-string))
> +         (b (with-temp-buffer
> +              (insert-file-contents (concat f ".out"))
> +              (buffer-string))))
> +      (should (string= a b)))))
> +
> +(defmacro mdcompat-gen-tests ()
> +  `(progn
> +     ,@(cl-loop
> +      for f in (directory-files mdcompat-test-directory t "md$")
> +      collect
> +      `(ert-deftest ,(intern (concat "mdcompat-test-"
> +                                    (file-name-sans-extension
> +                                     (file-name-nondirectory f))))
> +          ()
> +        (mdcompat-test-run ,f)))))
> +
> +(mdcompat-gen-tests)
> +
> +;;; mdcompact-testsuite.el ends here
> diff --git a/contrib/mdcompact/mdcompact.el b/contrib/mdcompact/mdcompact.el
> new file mode 100644
> index 00000000000..9b639f53188
> --- /dev/null
> +++ b/contrib/mdcompact/mdcompact.el
> @@ -0,0 +1,296 @@
> +;;; -*- lexical-binding: t; -*-
> +
> +;; Author: Andrea Corallo <andrea.corallo@arm.com>
> +;; Package: mdcompact
> +;; Keywords: languages, extensions
> +;; Package-Requires: ((emacs "29"))
> +
> +;; This file is part of GCC.
> +
> +;; GCC is free software: you can redistribute it and/or modify it
> +;; under the terms of the GNU General Public License as published by
> +;; the Free Software Foundation, either version 3 of the License, or
> +;; (at your option) any later version.
> +
> +;; GCC is distributed in the hope that it will be useful, but WITHOUT
> +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> +;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> +;; License for more details.
> +
> +;; You should have received a copy of the GNU General Public License
> +;; along with GCC.  If not, see <https://www.gnu.org/licenses/>.
> +
> +;;; Commentary:
> +
> +;; Convert multi choice GCC machine description patterns to compact
> +;; syntax.
> +
> +;;; Usage:
> +
> +;; With the point on a pattern run 'M-x mdcomp-run-at-point' to
> +;; convert that pattern.
> +
> +;; Run 'M-x mdcomp-run-buffer' to convert all convertible patterns in
> +;; the current buffer.
> +
> +;; Run 'M-x mdcomp-run-directory' to convert all convertible patterns
> +;; in a directory.
> +
> +;; One can invoke the tool from shell as well, ex for running it on
> +;; the arm backend from the GCC checkout directory:
> +;; emacs -batch -l ./contrib/mdcompact/mdcompact.el -f mdcomp-run-directory ./gcc/config/arm/
> +
> +;;; Code:
> +
> +(require 'cl-lib)
> +(require 'rx)
> +
> +(defconst
> +  mdcomp-constr-rx
> +  (rx "(match_operand" (? ":" (1+ (or punct alnum)))
> +      (1+ space) (group-n 1 num) (1+ space) "\""
> +      (1+ (or alnum "_" "<" ">")) "\""
> +      (group-n 2 (1+ space) "\"" (group-n 3 (0+ (not "\""))) "\"")
> +      ")"))
> +
> +(cl-defstruct mdcomp-operand
> +  num
> +  cstr)
> +
> +(cl-defstruct mdcomp-attr
> +  name
> +  vals)
> +
> +;; A reasonable name
> +(rx-define mdcomp-name (1+ (or alnum "_")))
> +
> +(defconst mdcomp-attr-rx
> +  (rx "(set_attr" (1+ space) "\""
> +      (group-n 1 mdcomp-name)
> +      "\"" (1+ space) "\""
> +      (group-n 2 (1+ (not ")")))
> +      "\"" (0+ space) ")"))
> +
> +(defun mdcomp-parse-delete-attr ()
> +  (save-match-data
> +    (when (re-search-forward mdcomp-attr-rx nil t)
> +      (let ((res (save-match-data
> +                  (make-mdcomp-attr
> +                   :name (match-string-no-properties 1)
> +                   :vals (cl-delete-if #'string-empty-p
> +                                       (split-string
> +                                        (replace-regexp-in-string
> +                                         (rx "\\") ""
> +                                         (match-string-no-properties 2))
> +                                                     (rx (1+ (or space ",")))))))))
> +       (if (length= (mdcomp-attr-vals res) 1)
> +           'short
> +         (delete-region (match-beginning 0) (match-end 0))
> +         res)))))
> +
> +(defun mdcomp-parse-attrs ()
> +  (save-excursion
> +    (let* ((res (cl-loop for x = (mdcomp-parse-delete-attr)
> +                        while x
> +                        collect x))
> +          (beg (re-search-backward (rx bol (1+ space) "["))))
> +      (unless (memq 'short res)
> +       (when res
> +         (delete-region beg (re-search-forward (rx "]")))))
> +      (cl-delete 'short res))))
> +
> +(defun mdcomp-remove-quoting (beg)
> +  (save-excursion
> +    (save-match-data
> +      (replace-regexp-in-region (regexp-quote "\\\\") "\\\\" beg (point-max))
> +      (replace-regexp-in-region (regexp-quote "\\\"") "\"" beg (point-max)))))
> +
> +(defun mdcomp-remove-escaped-newlines (beg)
> +  (save-excursion
> +    (save-match-data
> +      (replace-regexp-in-region (rx "\\" eol (0+ space)) " " beg (point-max)))))
> +
> +(defun mdcomp-parse-delete-cstr ()
> +  (cl-loop while (re-search-forward mdcomp-constr-rx nil t)
> +          unless (string= "" (match-string-no-properties 3))
> +            collect (save-match-data
> +                      (make-mdcomp-operand
> +                       :num (string-to-number (match-string-no-properties 1))
> +                       :cstr (cl-delete-if #'string-empty-p
> +                                           (split-string
> +                                            (replace-regexp-in-string " " ""
> +                                                                      (match-string-no-properties 3))
> +                                            (rx (1+ ","))))))
> +          do (delete-region (match-beginning 2) (match-end 2))))
> +
> +(defun mdcomp-run* ()
> +  (let* ((ops (mdcomp-parse-delete-cstr))
> +            (attrs (mdcomp-parse-attrs))
> +            (beg (re-search-forward "\"@")))
> +       (cl-sort ops (lambda (x y)
> +                      (< (mdcomp-operand-num x) (mdcomp-operand-num y))))
> +       (mdcomp-remove-escaped-newlines beg)
> +       (save-match-data
> +         (save-excursion
> +           (left-char 2)
> +           (forward-sexp)
> +           (left-char 1)
> +           (delete-char 1)
> +           (insert "\n  }")))
> +       (mdcomp-remove-quoting beg)
> +       (replace-match "{@")
> +       (re-search-forward (rx (or "\"" ")")))
> +       (re-search-backward "@")
> +       (right-char 1)
> +       (insert "[ cons: ")
> +       (cl-loop
> +        for op in ops
> +        when (string-match "=" (cl-first (mdcomp-operand-cstr op)))
> +        do (insert "=")
> +        do (insert (number-to-string (mdcomp-operand-num op)) ", ")
> +        finally
> +        (progn
> +          ;; In case add attributes names
> +          (when attrs
> +            (delete-char -2)
> +            (insert "; attrs: ")
> +            (cl-loop for attr in attrs
> +                     do (insert (mdcomp-attr-name attr) ", ")))
> +          (delete-char -2)
> +          (insert "]")))
> +       (cl-loop
> +        while (re-search-forward (rx bol (0+ space) (or (group-n 1 "* return")
> +                                                        (group-n 2 "}")
> +                                                        "#" alpha "<"))
> +                                 nil t)
> +        for i from 0
> +        when (match-string 2)
> +          do (cl-return)
> +        when (match-string 1)
> +          do (progn
> +               (delete-region (match-beginning 1) (+ (match-beginning 1) (length "* return")))
> +               (insert "<<")
> +               (left-char 1))
> +        do
> +        (progn
> +          (left-char 1)
> +          (cl-loop
> +           initially (insert " [ ")
> +           for op in ops
> +           for c = (nth i (mdcomp-operand-cstr op))
> +           unless c
> +             do (cl-return)
> +           do (insert (if (string-match "=" c)
> +                          (substring c 1 nil)
> +                        c)
> +                      ", ")
> +           finally (progn
> +                     (when attrs
> +                       (delete-char -2)
> +                       (insert "; ")
> +                       (cl-loop for attr in attrs
> +                                for str = (nth i (mdcomp-attr-vals attr))
> +                                when str
> +                                  do (insert str)
> +                                do (insert ", ")))
> +                     (delete-char -2)
> +                     (insert " ] ")
> +                     (move-end-of-line 1)))))
> +       ;; remove everything after ] align what needs to be aligned
> +       ;; and re-add the asm template
> +       (re-search-backward (regexp-quote "@[ cons:"))
> +       (let* ((n (length (mdcomp-operand-cstr (car ops))))
> +              (asms (cl-loop
> +                     initially (re-search-forward "]")
> +                     repeat n
> +                     collect (let* ((beg (re-search-forward "]"))
> +                                    (end (re-search-forward (rx eol)))
> +                                    (str (buffer-substring-no-properties beg end)))
> +                               (delete-region beg end)
> +                               str)))
> +              (beg (re-search-backward (regexp-quote "@[ cons:")))
> +              (indent-tabs-mode nil))
> +         (re-search-forward "}")
> +         (align-regexp beg (point) (rx  (group-n 1 "") "["))
> +         (align-regexp beg (point) (rx  (group-n 1 "") (or "," ";")) nil nil t)
> +         (align-regexp beg (point) (rx  (group-n 1 "") "]"))
> +         (goto-char beg)
> +         (cl-loop
> +          initially (re-search-forward "]")
> +          for i below n
> +          do (progn
> +               (re-search-forward "]")
> +               (insert (nth i asms))))
> +         (when (re-search-forward (rx (1+ (or space eol)) ")") nil t)
> +           (replace-match "\n)" nil t)))))
> +
> +(defun mdcomp-narrow-to-md-pattern ()
> +  (condition-case nil
> +      (let ((beg (re-search-forward "\n("))
> +           (end (re-search-forward (rx bol (1+ ")")))))
> +       (narrow-to-region beg end))
> +    (error
> +     (narrow-to-defun))))
> +
> +(defun mdcomp-run-at-point ()
> +  "Convert the multi choice top-level form around point to compact syntax."
> +  (interactive)
> +  (save-restriction
> +    (save-mark-and-excursion
> +      (mdcomp-narrow-to-md-pattern)
> +      (goto-char (point-min))
> +      (let ((pattern-name (save-excursion
> +                           (re-search-forward (rx "\"" (group-n 1 (1+ (not "\""))) "\""))
> +                           (match-string-no-properties 1)))
> +           (orig-text (buffer-substring-no-properties (point-min) (point-max))))
> +       (condition-case nil
> +           (progn
> +             (mdcomp-run*)
> +             (message "Converted: %s" pattern-name))
> +         (error
> +          (message "Skipping convertion for: %s" pattern-name)
> +          (delete-region (point-min) (point-max))
> +          (insert orig-text)
> +          'fail))))))
> +
> +(defun mdcomp-run-buffer ()
> +  "Convert the multi choice top-level forms in the buffer to compact syntax."
> +  (interactive)
> +  (save-excursion
> +    (message "Conversion for buffer %s started" (buffer-file-name))
> +    (goto-char (point-min))
> +    (while (re-search-forward
> +           (rx "match_operand" (1+ any) letter (0+ space) "," (0+ space) letter) nil t)
> +      (when (eq (mdcomp-run-at-point) 'fail)
> +       (condition-case nil
> +           (forward-sexp)
> +         (error
> +          ;; If forward-sexp fails falls back.
> +          (re-search-forward (rx ")" eol eol))))))
> +    (message "Conversion done")))
> +
> +(defconst mdcomp-file-rx (rx bol alpha (0+ not-newline) ".md" eol))
> +
> +(defun mdcomp-run-directory (folder &optional recursive)
> +  "Run el mdcompact on a FOLDER possibly in a RECURSIVE fashion."
> +  (interactive "D")
> +  (let ((before-save-hook nil)
> +       (init-time (current-time)))
> +    (mapc (lambda (f)
> +           (with-temp-file f
> +             (message "Working on %s" f)
> +             (insert-file-contents f)
> +             (mdcomp-run-buffer)
> +             (message "Done with %s" f)))
> +         (if recursive
> +             (directory-files-recursively folder mdcomp-file-rx)
> +           (directory-files folder t mdcomp-file-rx)))
> +    (message "Converted in %f sec" (float-time (time-since init-time)))))
> +
> +(defun mdcomp-batch-run-directory ()
> +  "Same as `mdcomp-run-directory' but use cmd line args."
> +  (mdcomp-run-directory (nth 0 argv) (nth 1 argv)))
> +
> +(provide 'mdcompact)
> +
> +;;; mdcompact.el ends here
> diff --git a/contrib/mdcompact/tests/1.md b/contrib/mdcompact/tests/1.md
> new file mode 100644
> index 00000000000..8f57ab487a5
> --- /dev/null
> +++ b/contrib/mdcompact/tests/1.md
> @@ -0,0 +1,36 @@
> +(define_insn_and_split "*movsi_aarch64"
> +  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,k,r,r,r,r, r,w, m, m,  r,  r,  r, w,r,w, w")
> +       (match_operand:SI 1 "aarch64_mov_operand"  " r,r,k,M,n,Usv,m,m,rZ,w,Usw,Usa,Ush,rZ,w,w,Ds"))]
> +  "(register_operand (operands[0], SImode)
> +    || aarch64_reg_or_zero (operands[1], SImode))"
> +  "@
> +   mov\\t%w0, %w1
> +   mov\\t%w0, %w1
> +   mov\\t%w0, %w1
> +   mov\\t%w0, %1
> +   #
> +   * return aarch64_output_sve_cnt_immediate (\"cnt\", \"%x0\", operands[1]);
> +   ldr\\t%w0, %1
> +   ldr\\t%s0, %1
> +   str\\t%w1, %0
> +   str\\t%s1, %0
> +   adrp\\t%x0, %A1\;ldr\\t%w0, [%x0, %L1]
> +   adr\\t%x0, %c1
> +   adrp\\t%x0, %A1
> +   fmov\\t%s0, %w1
> +   fmov\\t%w0, %s1
> +   fmov\\t%s0, %s1
> +   * return aarch64_output_scalar_simd_mov_immediate (operands[1], SImode);"
> +  "CONST_INT_P (operands[1]) && !aarch64_move_imm (INTVAL (operands[1]), SImode)
> +    && REG_P (operands[0]) && GP_REGNUM_P (REGNO (operands[0]))"
> +   [(const_int 0)]
> +   "{
> +       aarch64_expand_mov_immediate (operands[0], operands[1]);
> +       DONE;
> +    }"
> +  [(set_attr "type" "mov_reg,mov_reg,mov_reg,mov_imm,mov_imm,mov_imm,load_4,
> +                   load_4,store_4,store_4,load_4,adr,adr,f_mcr,f_mrc,fmov,neon_move")
> +   (set_attr "arch"   "*,*,*,*,*,sve,*,fp,*,fp,*,*,*,fp,fp,fp,simd")
> +   (set_attr "length" "4,4,4,4,*,  4,4, 4,4, 4,8,4,4, 4, 4, 4,   4")
> +]
> +)
> diff --git a/contrib/mdcompact/tests/1.md.out b/contrib/mdcompact/tests/1.md.out
> new file mode 100644
> index 00000000000..24f280dd29e
> --- /dev/null
> +++ b/contrib/mdcompact/tests/1.md.out
> @@ -0,0 +1,32 @@
> +(define_insn_and_split "*movsi_aarch64"
> +  [(set (match_operand:SI 0 "nonimmediate_operand")
> +       (match_operand:SI 1 "aarch64_mov_operand"))]
> +  "(register_operand (operands[0], SImode)
> +    || aarch64_reg_or_zero (operands[1], SImode))"
> +  {@ [ cons: =0 , 1   ; attrs: type , arch , length ]
> +     [ r        , r   ; mov_reg     , *    , 4      ] mov\t%w0, %w1
> +     [ k        , r   ; mov_reg     , *    , 4      ] mov\t%w0, %w1
> +     [ r        , k   ; mov_reg     , *    , 4      ] mov\t%w0, %w1
> +     [ r        , M   ; mov_imm     , *    , 4      ] mov\t%w0, %1
> +     [ r        , n   ; mov_imm     , *    , *      ] #
> +     [ r        , Usv ; mov_imm     , sve  , 4      ] << aarch64_output_sve_cnt_immediate ("cnt", "%x0", operands[1]);
> +     [ r        , m   ; load_4      , *    , 4      ] ldr\t%w0, %1
> +     [ w        , m   ; load_4      , fp   , 4      ] ldr\t%s0, %1
> +     [ m        , rZ  ; store_4     , *    , 4      ] str\t%w1, %0
> +     [ m        , w   ; store_4     , fp   , 4      ] str\t%s1, %0
> +     [ r        , Usw ; load_4      , *    , 8      ] adrp\t%x0, %A1\;ldr\t%w0, [%x0, %L1]
> +     [ r        , Usa ; adr         , *    , 4      ] adr\t%x0, %c1
> +     [ r        , Ush ; adr         , *    , 4      ] adrp\t%x0, %A1
> +     [ w        , rZ  ; f_mcr       , fp   , 4      ] fmov\t%s0, %w1
> +     [ r        , w   ; f_mrc       , fp   , 4      ] fmov\t%w0, %s1
> +     [ w        , w   ; fmov        , fp   , 4      ] fmov\t%s0, %s1
> +     [ w        , Ds  ; neon_move   , simd , 4      ] << aarch64_output_scalar_simd_mov_immediate (operands[1], SImode);
> +  }
> +  "CONST_INT_P (operands[1]) && !aarch64_move_imm (INTVAL (operands[1]), SImode)
> +    && REG_P (operands[0]) && GP_REGNUM_P (REGNO (operands[0]))"
> +   [(const_int 0)]
> +   "{
> +       aarch64_expand_mov_immediate (operands[0], operands[1]);
> +       DONE;
> +    }"
> +)
> diff --git a/contrib/mdcompact/tests/2.md b/contrib/mdcompact/tests/2.md
> new file mode 100644
> index 00000000000..61fba28af95
> --- /dev/null
> +++ b/contrib/mdcompact/tests/2.md
> @@ -0,0 +1,25 @@
> +(define_insn "*movti_aarch64"
> +  [(set (match_operand:TI 0
> +        "nonimmediate_operand"  "=   r,w,w,w, r,w,r,m,m,w,m")
> +       (match_operand:TI 1
> +        "aarch64_movti_operand" " rUti,Z,Z,r, w,w,m,r,Z,m,w"))]
> +  "(register_operand (operands[0], TImode)
> +    || aarch64_reg_or_zero (operands[1], TImode))"
> +  "@
> +   #
> +   movi\\t%0.2d, #0
> +   fmov\t%d0, xzr
> +   #
> +   #
> +   mov\\t%0.16b, %1.16b
> +   ldp\\t%0, %H0, %1
> +   stp\\t%1, %H1, %0
> +   stp\\txzr, xzr, %0
> +   ldr\\t%q0, %1
> +   str\\t%q1, %0"
> +  [(set_attr "type" "multiple,neon_move,f_mcr,f_mcr,f_mrc,neon_logic_q, \
> +                            load_16,store_16,store_16,\
> +                             load_16,store_16")
> +   (set_attr "length" "8,4,4,8,8,4,4,4,4,4,4")
> +   (set_attr "arch" "*,simd,*,*,*,simd,*,*,*,fp,fp")]
> +)
> diff --git a/contrib/mdcompact/tests/2.md.out b/contrib/mdcompact/tests/2.md.out
> new file mode 100644
> index 00000000000..b3d5402df78
> --- /dev/null
> +++ b/contrib/mdcompact/tests/2.md.out
> @@ -0,0 +1,21 @@
> +(define_insn "*movti_aarch64"
> +  [(set (match_operand:TI 0
> +        "nonimmediate_operand")
> +       (match_operand:TI 1
> +        "aarch64_movti_operand"))]
> +  "(register_operand (operands[0], TImode)
> +    || aarch64_reg_or_zero (operands[1], TImode))"
> +  {@ [ cons: =0 , 1    ; attrs: type  , length , arch  ]
> +     [ r        , rUti ; multiple     , 8      , *     ] #
> +     [ w        , Z    ; neon_move    , 4      , simd  ] movi\t%0.2d, #0
> +     [ w        , Z    ; f_mcr        , 4      , *     ] fmov\t%d0, xzr
> +     [ w        , r    ; f_mcr        , 8      , *     ] #
> +     [ r        , w    ; f_mrc        , 8      , *     ] #
> +     [ w        , w    ; neon_logic_q , 4      , simd  ] mov\t%0.16b, %1.16b
> +     [ r        , m    ; load_16      , 4      , *     ] ldp\t%0, %H0, %1
> +     [ m        , r    ; store_16     , 4      , *     ] stp\t%1, %H1, %0
> +     [ m        , Z    ; store_16     , 4      , *     ] stp\txzr, xzr, %0
> +     [ w        , m    ; load_16      , 4      , fp    ] ldr\t%q0, %1
> +     [ m        , w    ; store_16     , 4      , fp    ] str\t%q1, %0
> +  }
> +)
> diff --git a/contrib/mdcompact/tests/3.md b/contrib/mdcompact/tests/3.md
> new file mode 100644
> index 00000000000..79f3a1a88f8
> --- /dev/null
> +++ b/contrib/mdcompact/tests/3.md
> @@ -0,0 +1,16 @@
> +(define_insn "*add<mode>3_compareV_cconly_imm"
> +  [(set (reg:CC_V CC_REGNUM)
> +       (compare:CC_V
> +         (plus:<DWI>
> +           (sign_extend:<DWI> (match_operand:GPI 0 "register_operand" "r,r"))
> +           (match_operand:<DWI> 1 "const_scalar_int_operand" ""))
> +         (sign_extend:<DWI>
> +          (plus:GPI
> +           (match_dup 0)
> +           (match_operand:GPI 2 "aarch64_plus_immediate" "I,J")))))]
> +  "INTVAL (operands[1]) == INTVAL (operands[2])"
> +  "@
> +  cmn\\t%<w>0, %<w>1
> +  cmp\\t%<w>0, #%n1"
> +  [(set_attr "type" "alus_imm")]
> +)
> diff --git a/contrib/mdcompact/tests/3.md.out b/contrib/mdcompact/tests/3.md.out
> new file mode 100644
> index 00000000000..1ea25ee44f0
> --- /dev/null
> +++ b/contrib/mdcompact/tests/3.md.out
> @@ -0,0 +1,17 @@
> +(define_insn "*add<mode>3_compareV_cconly_imm"
> +  [(set (reg:CC_V CC_REGNUM)
> +       (compare:CC_V
> +         (plus:<DWI>
> +           (sign_extend:<DWI> (match_operand:GPI 0 "register_operand"))
> +           (match_operand:<DWI> 1 "const_scalar_int_operand"))
> +         (sign_extend:<DWI>
> +          (plus:GPI
> +           (match_dup 0)
> +           (match_operand:GPI 2 "aarch64_plus_immediate")))))]
> +  "INTVAL (operands[1]) == INTVAL (operands[2])"
> +  {@ [ cons: 0 , 2  ]
> +     [ r       , I  ] cmn\t%<w>0, %<w>1
> +     [ r       , J  ] cmp\t%<w>0, #%n1
> +  }
> +  [(set_attr "type" "alus_imm")]
> +)
> diff --git a/contrib/mdcompact/tests/4.md b/contrib/mdcompact/tests/4.md
> new file mode 100644
> index 00000000000..360f63b42e1
> --- /dev/null
> +++ b/contrib/mdcompact/tests/4.md
> @@ -0,0 +1,17 @@
> +(define_insn "*sibcall_insn"
> +  [(call (mem:DI (match_operand:DI 0 "aarch64_call_insn_operand" "Ucs, Usf"))
> +        (match_operand 1 ""))
> +   (unspec:DI [(match_operand:DI 2 "const_int_operand")] UNSPEC_CALLEE_ABI)
> +   (return)]
> +  "SIBLING_CALL_P (insn)"
> +  {
> +    if (which_alternative == 0)
> +      {
> +       output_asm_insn ("br\\t%0", operands);
> +       return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ());
> +      }
> +    return "b\\t%c0";
> +  }
> +  [(set_attr "type" "branch, branch")
> +   (set_attr "sls_length" "retbr,none")]
> +)
> \ No newline at end of file
> diff --git a/contrib/mdcompact/tests/4.md.out b/contrib/mdcompact/tests/4.md.out
> new file mode 100644
> index 00000000000..360f63b42e1
> --- /dev/null
> +++ b/contrib/mdcompact/tests/4.md.out
> @@ -0,0 +1,17 @@
> +(define_insn "*sibcall_insn"
> +  [(call (mem:DI (match_operand:DI 0 "aarch64_call_insn_operand" "Ucs, Usf"))
> +        (match_operand 1 ""))
> +   (unspec:DI [(match_operand:DI 2 "const_int_operand")] UNSPEC_CALLEE_ABI)
> +   (return)]
> +  "SIBLING_CALL_P (insn)"
> +  {
> +    if (which_alternative == 0)
> +      {
> +       output_asm_insn ("br\\t%0", operands);
> +       return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ());
> +      }
> +    return "b\\t%c0";
> +  }
> +  [(set_attr "type" "branch, branch")
> +   (set_attr "sls_length" "retbr,none")]
> +)
> \ No newline at end of file
> diff --git a/contrib/mdcompact/tests/5.md b/contrib/mdcompact/tests/5.md
> new file mode 100644
> index 00000000000..100dffbc8b1
> --- /dev/null
> +++ b/contrib/mdcompact/tests/5.md
> @@ -0,0 +1,12 @@
> +(define_insn "<optab><mode>3"
> +  [(set (match_operand:GPI 0 "register_operand" "=r,rk,w")
> +       (LOGICAL:GPI (match_operand:GPI 1 "register_operand" "%r,r,w")
> +                    (match_operand:GPI 2 "aarch64_logical_operand" "r,<lconst>,w")))]
> +  ""
> +  "@
> +  <logical>\\t%<w>0, %<w>1, %<w>2
> +  <logical>\\t%<w>0, %<w>1, %2
> +  <logical>\\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>"
> +  [(set_attr "type" "logic_reg,logic_imm,neon_logic")
> +   (set_attr "arch" "*,*,simd")]
> +)
> diff --git a/contrib/mdcompact/tests/5.md.out b/contrib/mdcompact/tests/5.md.out
> new file mode 100644
> index 00000000000..ed460ee1530
> --- /dev/null
> +++ b/contrib/mdcompact/tests/5.md.out
> @@ -0,0 +1,11 @@
> +(define_insn "<optab><mode>3"
> +  [(set (match_operand:GPI 0 "register_operand")
> +       (LOGICAL:GPI (match_operand:GPI 1 "register_operand")
> +                    (match_operand:GPI 2 "aarch64_logical_operand")))]
> +  ""
> +  {@ [ cons: =0 , 1  , 2        ; attrs: type , arch  ]
> +     [ r        , %r , r        ; logic_reg   , *     ] <logical>\t%<w>0, %<w>1, %<w>2
> +     [ rk       , r  , <lconst> ; logic_imm   , *     ] <logical>\t%<w>0, %<w>1, %2
> +     [ w        , w  , w        ; neon_logic  , simd  ] <logical>\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>
> +  }
> +)
> diff --git a/contrib/mdcompact/tests/6.md b/contrib/mdcompact/tests/6.md
> new file mode 100644
> index 00000000000..a9f609503e2
> --- /dev/null
> +++ b/contrib/mdcompact/tests/6.md
> @@ -0,0 +1,11 @@
> +(define_insn "aarch64_wrffr"
> +  [(set (reg:VNx16BI FFR_REGNUM)
> +       (match_operand:VNx16BI 0 "aarch64_simd_reg_or_minus_one"))
> +   (set (reg:VNx16BI FFRT_REGNUM)
> +       (unspec:VNx16BI [(match_dup 0)] UNSPEC_WRFFR))]
> +  "TARGET_SVE"
> +  {@ [ cons: 0 ]
> +     [ Dm      ] setffr
> +     [ Upa     ] wrffr\t%0.b
> +  }
> +)
> diff --git a/contrib/mdcompact/tests/6.md.out b/contrib/mdcompact/tests/6.md.out
> new file mode 100644
> index 00000000000..a9f609503e2
> --- /dev/null
> +++ b/contrib/mdcompact/tests/6.md.out
> @@ -0,0 +1,11 @@
> +(define_insn "aarch64_wrffr"
> +  [(set (reg:VNx16BI FFR_REGNUM)
> +       (match_operand:VNx16BI 0 "aarch64_simd_reg_or_minus_one"))
> +   (set (reg:VNx16BI FFRT_REGNUM)
> +       (unspec:VNx16BI [(match_dup 0)] UNSPEC_WRFFR))]
> +  "TARGET_SVE"
> +  {@ [ cons: 0 ]
> +     [ Dm      ] setffr
> +     [ Upa     ] wrffr\t%0.b
> +  }
> +)
> diff --git a/contrib/mdcompact/tests/7.md b/contrib/mdcompact/tests/7.md
> new file mode 100644
> index 00000000000..6616deaa8db
> --- /dev/null
> +++ b/contrib/mdcompact/tests/7.md
> @@ -0,0 +1,11 @@
> +(define_insn "and<mode>3<vczle><vczbe>"
> +  [(set (match_operand:VDQ_I 0 "register_operand" "=w,w")
> +       (and:VDQ_I (match_operand:VDQ_I 1 "register_operand" "w,0")
> +                  (match_operand:VDQ_I 2 "aarch64_reg_or_bic_imm" "w,Db")))]
> +  "TARGET_SIMD"
> +  "@
> +   and\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>
> +   * return aarch64_output_simd_mov_immediate (operands[2], <bitsize>,\
> +                                              AARCH64_CHECK_BIC);"
> +  [(set_attr "type" "neon_logic<q>")]
> +)
> diff --git a/contrib/mdcompact/tests/7.md.out b/contrib/mdcompact/tests/7.md.out
> new file mode 100644
> index 00000000000..199b37a810f
> --- /dev/null
> +++ b/contrib/mdcompact/tests/7.md.out
> @@ -0,0 +1,11 @@
> +(define_insn "and<mode>3<vczle><vczbe>"
> +  [(set (match_operand:VDQ_I 0 "register_operand")
> +       (and:VDQ_I (match_operand:VDQ_I 1 "register_operand")
> +                  (match_operand:VDQ_I 2 "aarch64_reg_or_bic_imm")))]
> +  "TARGET_SIMD"
> +  {@ [ cons: =0 , 1 , 2   ]
> +     [ w        , w , w   ] and\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>
> +     [ w        , 0 , Db  ] << aarch64_output_simd_mov_immediate (operands[2], <bitsize>, AARCH64_CHECK_BIC);
> +  }
> +  [(set_attr "type" "neon_logic<q>")]
> +)
> --
> 2.25.1
>
  
Andrea Corallo Oct. 6, 2023, 7:20 a.m. UTC | #2
Richard Biener <richard.guenther@gmail.com> writes:

> On Thu, Oct 5, 2023 at 5:49 PM Andrea Corallo <andrea.corallo@arm.com> wrote:
>>
>> Hello all,
>>
>> this patch checks in mdcompact, the tool written in elisp that I used
>> to mass convert all the multi choice pattern in the aarch64 back-end to
>> the new compact syntax.
>>
>> I tested it on Emacs 29 (might run on older versions as well not
>> sure), also I verified it runs cleanly on a few other back-ends (arm,
>> loongarch).
>>
>> The tool can be used to convert a single pattern, an open buffer or
>> all md files in a directory.
>>
>> The tool might need further adjustment to run on some specific
>> back-end, in case very happy to help.
>>
>> This patch was pre-approved here [1].
>
> Does the result generate identical insn-*.cc files?

No, there can be indentation/aesthetic differences.

BR

  Andrea
  

Patch

diff --git a/contrib/mdcompact/mdcompact-testsuite.el b/contrib/mdcompact/mdcompact-testsuite.el
new file mode 100644
index 00000000000..494c0b5cd68
--- /dev/null
+++ b/contrib/mdcompact/mdcompact-testsuite.el
@@ -0,0 +1,56 @@ 
+;;; -*- lexical-binding: t; -*-
+
+;; This file is part of GCC.
+
+;; GCC is free software: you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Usage:
+;; $ emacs -batch -l mdcompact.el -l mdcompact-testsuite.el -f ert-run-tests-batch-and-exit 
+
+;;; Code:
+
+(require 'mdcompact)
+(require 'ert)
+
+(defconst mdcompat-test-directory (concat (file-name-directory
+					   (or load-file-name
+                                               buffer-file-name))
+					  "tests/"))
+
+(defun mdcompat-test-run (f)
+  (with-temp-buffer
+    (insert-file-contents f)
+    (mdcomp-run-at-point)
+    (let ((a (buffer-string))
+	  (b (with-temp-buffer
+	       (insert-file-contents (concat f ".out"))
+	       (buffer-string))))
+      (should (string= a b)))))
+
+(defmacro mdcompat-gen-tests ()
+  `(progn
+     ,@(cl-loop
+      for f in (directory-files mdcompat-test-directory t "md$")
+      collect
+      `(ert-deftest ,(intern (concat "mdcompat-test-"
+				     (file-name-sans-extension
+				      (file-name-nondirectory f))))
+	   ()
+	 (mdcompat-test-run ,f)))))
+
+(mdcompat-gen-tests)
+
+;;; mdcompact-testsuite.el ends here
diff --git a/contrib/mdcompact/mdcompact.el b/contrib/mdcompact/mdcompact.el
new file mode 100644
index 00000000000..9b639f53188
--- /dev/null
+++ b/contrib/mdcompact/mdcompact.el
@@ -0,0 +1,296 @@ 
+;;; -*- lexical-binding: t; -*-
+
+;; Author: Andrea Corallo <andrea.corallo@arm.com>
+;; Package: mdcompact
+;; Keywords: languages, extensions
+;; Package-Requires: ((emacs "29"))
+
+;; This file is part of GCC.
+
+;; GCC is free software: you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Convert multi choice GCC machine description patterns to compact
+;; syntax.
+
+;;; Usage:
+
+;; With the point on a pattern run 'M-x mdcomp-run-at-point' to
+;; convert that pattern.
+
+;; Run 'M-x mdcomp-run-buffer' to convert all convertible patterns in
+;; the current buffer.
+
+;; Run 'M-x mdcomp-run-directory' to convert all convertible patterns
+;; in a directory.
+
+;; One can invoke the tool from shell as well, ex for running it on
+;; the arm backend from the GCC checkout directory:
+;; emacs -batch -l ./contrib/mdcompact/mdcompact.el -f mdcomp-run-directory ./gcc/config/arm/
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'rx)
+
+(defconst
+  mdcomp-constr-rx
+  (rx "(match_operand" (? ":" (1+ (or punct alnum)))
+      (1+ space) (group-n 1 num) (1+ space) "\""
+      (1+ (or alnum "_" "<" ">")) "\""
+      (group-n 2 (1+ space) "\"" (group-n 3 (0+ (not "\""))) "\"")
+      ")"))
+
+(cl-defstruct mdcomp-operand
+  num
+  cstr)
+
+(cl-defstruct mdcomp-attr
+  name
+  vals)
+
+;; A reasonable name
+(rx-define mdcomp-name (1+ (or alnum "_")))
+
+(defconst mdcomp-attr-rx
+  (rx "(set_attr" (1+ space) "\""
+      (group-n 1 mdcomp-name)
+      "\"" (1+ space) "\""
+      (group-n 2 (1+ (not ")")))
+      "\"" (0+ space) ")"))
+
+(defun mdcomp-parse-delete-attr ()
+  (save-match-data
+    (when (re-search-forward mdcomp-attr-rx nil t)
+      (let ((res (save-match-data
+		   (make-mdcomp-attr
+		    :name (match-string-no-properties 1)
+		    :vals (cl-delete-if #'string-empty-p
+					(split-string
+					 (replace-regexp-in-string
+					  (rx "\\") ""
+					  (match-string-no-properties 2))
+						      (rx (1+ (or space ",")))))))))
+	(if (length= (mdcomp-attr-vals res) 1)
+	    'short
+	  (delete-region (match-beginning 0) (match-end 0))
+	  res)))))
+
+(defun mdcomp-parse-attrs ()
+  (save-excursion
+    (let* ((res (cl-loop for x = (mdcomp-parse-delete-attr)
+			 while x
+			 collect x))
+	   (beg (re-search-backward (rx bol (1+ space) "["))))
+      (unless (memq 'short res)
+	(when res
+	  (delete-region beg (re-search-forward (rx "]")))))
+      (cl-delete 'short res))))
+
+(defun mdcomp-remove-quoting (beg)
+  (save-excursion
+    (save-match-data
+      (replace-regexp-in-region (regexp-quote "\\\\") "\\\\" beg (point-max))
+      (replace-regexp-in-region (regexp-quote "\\\"") "\"" beg (point-max)))))
+
+(defun mdcomp-remove-escaped-newlines (beg)
+  (save-excursion
+    (save-match-data
+      (replace-regexp-in-region (rx "\\" eol (0+ space)) " " beg (point-max)))))
+
+(defun mdcomp-parse-delete-cstr ()
+  (cl-loop while (re-search-forward mdcomp-constr-rx nil t)
+	   unless (string= "" (match-string-no-properties 3))
+	     collect (save-match-data
+		       (make-mdcomp-operand
+			:num (string-to-number (match-string-no-properties 1))
+			:cstr (cl-delete-if #'string-empty-p
+					    (split-string
+					     (replace-regexp-in-string " " ""
+								       (match-string-no-properties 3))
+					     (rx (1+ ","))))))
+	   do (delete-region (match-beginning 2) (match-end 2))))
+
+(defun mdcomp-run* ()
+  (let* ((ops (mdcomp-parse-delete-cstr))
+	     (attrs (mdcomp-parse-attrs))
+	     (beg (re-search-forward "\"@")))
+	(cl-sort ops (lambda (x y)
+		       (< (mdcomp-operand-num x) (mdcomp-operand-num y))))
+	(mdcomp-remove-escaped-newlines beg)
+	(save-match-data
+	  (save-excursion
+	    (left-char 2)
+	    (forward-sexp)
+	    (left-char 1)
+	    (delete-char 1)
+	    (insert "\n  }")))
+	(mdcomp-remove-quoting beg)
+	(replace-match "{@")
+	(re-search-forward (rx (or "\"" ")")))
+	(re-search-backward "@")
+	(right-char 1)
+	(insert "[ cons: ")
+	(cl-loop
+	 for op in ops
+	 when (string-match "=" (cl-first (mdcomp-operand-cstr op)))
+	 do (insert "=")
+	 do (insert (number-to-string (mdcomp-operand-num op)) ", ")
+	 finally
+	 (progn
+	   ;; In case add attributes names
+	   (when attrs
+	     (delete-char -2)
+	     (insert "; attrs: ")
+	     (cl-loop for attr in attrs
+		      do (insert (mdcomp-attr-name attr) ", ")))
+	   (delete-char -2)
+	   (insert "]")))
+	(cl-loop
+	 while (re-search-forward (rx bol (0+ space) (or (group-n 1 "* return")
+							 (group-n 2 "}")
+							 "#" alpha "<"))
+				  nil t)
+	 for i from 0
+	 when (match-string 2)
+	   do (cl-return)
+	 when (match-string 1)
+	   do (progn
+		(delete-region (match-beginning 1) (+ (match-beginning 1) (length "* return")))
+		(insert "<<")
+		(left-char 1))
+	 do
+	 (progn
+	   (left-char 1)
+	   (cl-loop
+	    initially (insert " [ ")
+	    for op in ops
+	    for c = (nth i (mdcomp-operand-cstr op))
+	    unless c
+	      do (cl-return)
+	    do (insert (if (string-match "=" c)
+			   (substring c 1 nil)
+			 c)
+		       ", ")
+	    finally (progn
+		      (when attrs
+			(delete-char -2)
+			(insert "; ")
+			(cl-loop for attr in attrs
+				 for str = (nth i (mdcomp-attr-vals attr))
+				 when str
+				   do (insert str)
+				 do (insert ", ")))
+		      (delete-char -2)
+		      (insert " ] ")
+		      (move-end-of-line 1)))))
+	;; remove everything after ] align what needs to be aligned
+	;; and re-add the asm template
+	(re-search-backward (regexp-quote "@[ cons:"))
+	(let* ((n (length (mdcomp-operand-cstr (car ops))))
+	       (asms (cl-loop
+		      initially (re-search-forward "]")
+		      repeat n
+		      collect (let* ((beg (re-search-forward "]"))
+				     (end (re-search-forward (rx eol)))
+				     (str (buffer-substring-no-properties beg end)))
+				(delete-region beg end)
+				str)))
+	       (beg (re-search-backward (regexp-quote "@[ cons:")))
+	       (indent-tabs-mode nil))
+	  (re-search-forward "}")
+	  (align-regexp beg (point) (rx  (group-n 1 "") "["))
+	  (align-regexp beg (point) (rx  (group-n 1 "") (or "," ";")) nil nil t)
+	  (align-regexp beg (point) (rx  (group-n 1 "") "]"))
+	  (goto-char beg)
+	  (cl-loop
+	   initially (re-search-forward "]")
+	   for i below n
+	   do (progn
+		(re-search-forward "]")
+		(insert (nth i asms))))
+	  (when (re-search-forward (rx (1+ (or space eol)) ")") nil t)
+	    (replace-match "\n)" nil t)))))
+
+(defun mdcomp-narrow-to-md-pattern ()
+  (condition-case nil
+      (let ((beg (re-search-forward "\n("))
+	    (end (re-search-forward (rx bol (1+ ")")))))
+	(narrow-to-region beg end))
+    (error
+     (narrow-to-defun))))
+
+(defun mdcomp-run-at-point ()
+  "Convert the multi choice top-level form around point to compact syntax."
+  (interactive)
+  (save-restriction
+    (save-mark-and-excursion
+      (mdcomp-narrow-to-md-pattern)
+      (goto-char (point-min))
+      (let ((pattern-name (save-excursion
+			    (re-search-forward (rx "\"" (group-n 1 (1+ (not "\""))) "\""))
+			    (match-string-no-properties 1)))
+	    (orig-text (buffer-substring-no-properties (point-min) (point-max))))
+	(condition-case nil
+	    (progn
+	      (mdcomp-run*)
+	      (message "Converted: %s" pattern-name))
+	  (error
+	   (message "Skipping convertion for: %s" pattern-name)
+	   (delete-region (point-min) (point-max))
+	   (insert orig-text)
+	   'fail))))))
+
+(defun mdcomp-run-buffer ()
+  "Convert the multi choice top-level forms in the buffer to compact syntax."
+  (interactive)
+  (save-excursion
+    (message "Conversion for buffer %s started" (buffer-file-name))
+    (goto-char (point-min))
+    (while (re-search-forward
+	    (rx "match_operand" (1+ any) letter (0+ space) "," (0+ space) letter) nil t)
+      (when (eq (mdcomp-run-at-point) 'fail)
+	(condition-case nil
+	    (forward-sexp)
+	  (error
+	   ;; If forward-sexp fails falls back.
+	   (re-search-forward (rx ")" eol eol))))))
+    (message "Conversion done")))
+
+(defconst mdcomp-file-rx (rx bol alpha (0+ not-newline) ".md" eol))
+
+(defun mdcomp-run-directory (folder &optional recursive)
+  "Run el mdcompact on a FOLDER possibly in a RECURSIVE fashion."
+  (interactive "D")
+  (let ((before-save-hook nil)
+	(init-time (current-time)))
+    (mapc (lambda (f)
+	    (with-temp-file f
+	      (message "Working on %s" f)
+	      (insert-file-contents f)
+	      (mdcomp-run-buffer)
+	      (message "Done with %s" f)))
+	  (if recursive
+	      (directory-files-recursively folder mdcomp-file-rx)
+	    (directory-files folder t mdcomp-file-rx)))
+    (message "Converted in %f sec" (float-time (time-since init-time)))))
+
+(defun mdcomp-batch-run-directory ()
+  "Same as `mdcomp-run-directory' but use cmd line args."
+  (mdcomp-run-directory (nth 0 argv) (nth 1 argv)))
+
+(provide 'mdcompact)
+
+;;; mdcompact.el ends here
diff --git a/contrib/mdcompact/tests/1.md b/contrib/mdcompact/tests/1.md
new file mode 100644
index 00000000000..8f57ab487a5
--- /dev/null
+++ b/contrib/mdcompact/tests/1.md
@@ -0,0 +1,36 @@ 
+(define_insn_and_split "*movsi_aarch64"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,k,r,r,r,r, r,w, m, m,  r,  r,  r, w,r,w, w")
+	(match_operand:SI 1 "aarch64_mov_operand"  " r,r,k,M,n,Usv,m,m,rZ,w,Usw,Usa,Ush,rZ,w,w,Ds"))]
+  "(register_operand (operands[0], SImode)
+    || aarch64_reg_or_zero (operands[1], SImode))"
+  "@
+   mov\\t%w0, %w1
+   mov\\t%w0, %w1
+   mov\\t%w0, %w1
+   mov\\t%w0, %1
+   #
+   * return aarch64_output_sve_cnt_immediate (\"cnt\", \"%x0\", operands[1]);
+   ldr\\t%w0, %1
+   ldr\\t%s0, %1
+   str\\t%w1, %0
+   str\\t%s1, %0
+   adrp\\t%x0, %A1\;ldr\\t%w0, [%x0, %L1]
+   adr\\t%x0, %c1
+   adrp\\t%x0, %A1
+   fmov\\t%s0, %w1
+   fmov\\t%w0, %s1
+   fmov\\t%s0, %s1
+   * return aarch64_output_scalar_simd_mov_immediate (operands[1], SImode);"
+  "CONST_INT_P (operands[1]) && !aarch64_move_imm (INTVAL (operands[1]), SImode)
+    && REG_P (operands[0]) && GP_REGNUM_P (REGNO (operands[0]))"
+   [(const_int 0)]
+   "{
+       aarch64_expand_mov_immediate (operands[0], operands[1]);
+       DONE;
+    }"
+  [(set_attr "type" "mov_reg,mov_reg,mov_reg,mov_imm,mov_imm,mov_imm,load_4,
+		    load_4,store_4,store_4,load_4,adr,adr,f_mcr,f_mrc,fmov,neon_move")
+   (set_attr "arch"   "*,*,*,*,*,sve,*,fp,*,fp,*,*,*,fp,fp,fp,simd")
+   (set_attr "length" "4,4,4,4,*,  4,4, 4,4, 4,8,4,4, 4, 4, 4,   4")
+]
+)
diff --git a/contrib/mdcompact/tests/1.md.out b/contrib/mdcompact/tests/1.md.out
new file mode 100644
index 00000000000..24f280dd29e
--- /dev/null
+++ b/contrib/mdcompact/tests/1.md.out
@@ -0,0 +1,32 @@ 
+(define_insn_and_split "*movsi_aarch64"
+  [(set (match_operand:SI 0 "nonimmediate_operand")
+	(match_operand:SI 1 "aarch64_mov_operand"))]
+  "(register_operand (operands[0], SImode)
+    || aarch64_reg_or_zero (operands[1], SImode))"
+  {@ [ cons: =0 , 1   ; attrs: type , arch , length ]
+     [ r        , r   ; mov_reg     , *    , 4      ] mov\t%w0, %w1
+     [ k        , r   ; mov_reg     , *    , 4      ] mov\t%w0, %w1
+     [ r        , k   ; mov_reg     , *    , 4      ] mov\t%w0, %w1
+     [ r        , M   ; mov_imm     , *    , 4      ] mov\t%w0, %1
+     [ r        , n   ; mov_imm     , *    , *      ] #
+     [ r        , Usv ; mov_imm     , sve  , 4      ] << aarch64_output_sve_cnt_immediate ("cnt", "%x0", operands[1]);
+     [ r        , m   ; load_4      , *    , 4      ] ldr\t%w0, %1
+     [ w        , m   ; load_4      , fp   , 4      ] ldr\t%s0, %1
+     [ m        , rZ  ; store_4     , *    , 4      ] str\t%w1, %0
+     [ m        , w   ; store_4     , fp   , 4      ] str\t%s1, %0
+     [ r        , Usw ; load_4      , *    , 8      ] adrp\t%x0, %A1\;ldr\t%w0, [%x0, %L1]
+     [ r        , Usa ; adr         , *    , 4      ] adr\t%x0, %c1
+     [ r        , Ush ; adr         , *    , 4      ] adrp\t%x0, %A1
+     [ w        , rZ  ; f_mcr       , fp   , 4      ] fmov\t%s0, %w1
+     [ r        , w   ; f_mrc       , fp   , 4      ] fmov\t%w0, %s1
+     [ w        , w   ; fmov        , fp   , 4      ] fmov\t%s0, %s1
+     [ w        , Ds  ; neon_move   , simd , 4      ] << aarch64_output_scalar_simd_mov_immediate (operands[1], SImode);
+  }
+  "CONST_INT_P (operands[1]) && !aarch64_move_imm (INTVAL (operands[1]), SImode)
+    && REG_P (operands[0]) && GP_REGNUM_P (REGNO (operands[0]))"
+   [(const_int 0)]
+   "{
+       aarch64_expand_mov_immediate (operands[0], operands[1]);
+       DONE;
+    }"
+)
diff --git a/contrib/mdcompact/tests/2.md b/contrib/mdcompact/tests/2.md
new file mode 100644
index 00000000000..61fba28af95
--- /dev/null
+++ b/contrib/mdcompact/tests/2.md
@@ -0,0 +1,25 @@ 
+(define_insn "*movti_aarch64"
+  [(set (match_operand:TI 0
+	 "nonimmediate_operand"  "=   r,w,w,w, r,w,r,m,m,w,m")
+	(match_operand:TI 1
+	 "aarch64_movti_operand" " rUti,Z,Z,r, w,w,m,r,Z,m,w"))]
+  "(register_operand (operands[0], TImode)
+    || aarch64_reg_or_zero (operands[1], TImode))"
+  "@
+   #
+   movi\\t%0.2d, #0
+   fmov\t%d0, xzr
+   #
+   #
+   mov\\t%0.16b, %1.16b
+   ldp\\t%0, %H0, %1
+   stp\\t%1, %H1, %0
+   stp\\txzr, xzr, %0
+   ldr\\t%q0, %1
+   str\\t%q1, %0"
+  [(set_attr "type" "multiple,neon_move,f_mcr,f_mcr,f_mrc,neon_logic_q, \
+		             load_16,store_16,store_16,\
+                             load_16,store_16")
+   (set_attr "length" "8,4,4,8,8,4,4,4,4,4,4")
+   (set_attr "arch" "*,simd,*,*,*,simd,*,*,*,fp,fp")]
+)
diff --git a/contrib/mdcompact/tests/2.md.out b/contrib/mdcompact/tests/2.md.out
new file mode 100644
index 00000000000..b3d5402df78
--- /dev/null
+++ b/contrib/mdcompact/tests/2.md.out
@@ -0,0 +1,21 @@ 
+(define_insn "*movti_aarch64"
+  [(set (match_operand:TI 0
+	 "nonimmediate_operand")
+	(match_operand:TI 1
+	 "aarch64_movti_operand"))]
+  "(register_operand (operands[0], TImode)
+    || aarch64_reg_or_zero (operands[1], TImode))"
+  {@ [ cons: =0 , 1    ; attrs: type  , length , arch  ]
+     [ r        , rUti ; multiple     , 8      , *     ] #
+     [ w        , Z    ; neon_move    , 4      , simd  ] movi\t%0.2d, #0
+     [ w        , Z    ; f_mcr        , 4      , *     ] fmov\t%d0, xzr
+     [ w        , r    ; f_mcr        , 8      , *     ] #
+     [ r        , w    ; f_mrc        , 8      , *     ] #
+     [ w        , w    ; neon_logic_q , 4      , simd  ] mov\t%0.16b, %1.16b
+     [ r        , m    ; load_16      , 4      , *     ] ldp\t%0, %H0, %1
+     [ m        , r    ; store_16     , 4      , *     ] stp\t%1, %H1, %0
+     [ m        , Z    ; store_16     , 4      , *     ] stp\txzr, xzr, %0
+     [ w        , m    ; load_16      , 4      , fp    ] ldr\t%q0, %1
+     [ m        , w    ; store_16     , 4      , fp    ] str\t%q1, %0
+  }
+)
diff --git a/contrib/mdcompact/tests/3.md b/contrib/mdcompact/tests/3.md
new file mode 100644
index 00000000000..79f3a1a88f8
--- /dev/null
+++ b/contrib/mdcompact/tests/3.md
@@ -0,0 +1,16 @@ 
+(define_insn "*add<mode>3_compareV_cconly_imm"
+  [(set (reg:CC_V CC_REGNUM)
+	(compare:CC_V
+	  (plus:<DWI>
+	    (sign_extend:<DWI> (match_operand:GPI 0 "register_operand" "r,r"))
+	    (match_operand:<DWI> 1 "const_scalar_int_operand" ""))
+	  (sign_extend:<DWI>
+	   (plus:GPI
+	    (match_dup 0)
+	    (match_operand:GPI 2 "aarch64_plus_immediate" "I,J")))))]
+  "INTVAL (operands[1]) == INTVAL (operands[2])"
+  "@
+  cmn\\t%<w>0, %<w>1
+  cmp\\t%<w>0, #%n1"
+  [(set_attr "type" "alus_imm")]
+)
diff --git a/contrib/mdcompact/tests/3.md.out b/contrib/mdcompact/tests/3.md.out
new file mode 100644
index 00000000000..1ea25ee44f0
--- /dev/null
+++ b/contrib/mdcompact/tests/3.md.out
@@ -0,0 +1,17 @@ 
+(define_insn "*add<mode>3_compareV_cconly_imm"
+  [(set (reg:CC_V CC_REGNUM)
+	(compare:CC_V
+	  (plus:<DWI>
+	    (sign_extend:<DWI> (match_operand:GPI 0 "register_operand"))
+	    (match_operand:<DWI> 1 "const_scalar_int_operand"))
+	  (sign_extend:<DWI>
+	   (plus:GPI
+	    (match_dup 0)
+	    (match_operand:GPI 2 "aarch64_plus_immediate")))))]
+  "INTVAL (operands[1]) == INTVAL (operands[2])"
+  {@ [ cons: 0 , 2  ]
+     [ r       , I  ] cmn\t%<w>0, %<w>1
+     [ r       , J  ] cmp\t%<w>0, #%n1
+  }
+  [(set_attr "type" "alus_imm")]
+)
diff --git a/contrib/mdcompact/tests/4.md b/contrib/mdcompact/tests/4.md
new file mode 100644
index 00000000000..360f63b42e1
--- /dev/null
+++ b/contrib/mdcompact/tests/4.md
@@ -0,0 +1,17 @@ 
+(define_insn "*sibcall_insn"
+  [(call (mem:DI (match_operand:DI 0 "aarch64_call_insn_operand" "Ucs, Usf"))
+	 (match_operand 1 ""))
+   (unspec:DI [(match_operand:DI 2 "const_int_operand")] UNSPEC_CALLEE_ABI)
+   (return)]
+  "SIBLING_CALL_P (insn)"
+  {
+    if (which_alternative == 0)
+      {
+	output_asm_insn ("br\\t%0", operands);
+	return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ());
+      }
+    return "b\\t%c0";
+  }
+  [(set_attr "type" "branch, branch")
+   (set_attr "sls_length" "retbr,none")]
+)
\ No newline at end of file
diff --git a/contrib/mdcompact/tests/4.md.out b/contrib/mdcompact/tests/4.md.out
new file mode 100644
index 00000000000..360f63b42e1
--- /dev/null
+++ b/contrib/mdcompact/tests/4.md.out
@@ -0,0 +1,17 @@ 
+(define_insn "*sibcall_insn"
+  [(call (mem:DI (match_operand:DI 0 "aarch64_call_insn_operand" "Ucs, Usf"))
+	 (match_operand 1 ""))
+   (unspec:DI [(match_operand:DI 2 "const_int_operand")] UNSPEC_CALLEE_ABI)
+   (return)]
+  "SIBLING_CALL_P (insn)"
+  {
+    if (which_alternative == 0)
+      {
+	output_asm_insn ("br\\t%0", operands);
+	return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ());
+      }
+    return "b\\t%c0";
+  }
+  [(set_attr "type" "branch, branch")
+   (set_attr "sls_length" "retbr,none")]
+)
\ No newline at end of file
diff --git a/contrib/mdcompact/tests/5.md b/contrib/mdcompact/tests/5.md
new file mode 100644
index 00000000000..100dffbc8b1
--- /dev/null
+++ b/contrib/mdcompact/tests/5.md
@@ -0,0 +1,12 @@ 
+(define_insn "<optab><mode>3"
+  [(set (match_operand:GPI 0 "register_operand" "=r,rk,w")
+	(LOGICAL:GPI (match_operand:GPI 1 "register_operand" "%r,r,w")
+		     (match_operand:GPI 2 "aarch64_logical_operand" "r,<lconst>,w")))]
+  ""
+  "@
+  <logical>\\t%<w>0, %<w>1, %<w>2
+  <logical>\\t%<w>0, %<w>1, %2
+  <logical>\\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>"
+  [(set_attr "type" "logic_reg,logic_imm,neon_logic")
+   (set_attr "arch" "*,*,simd")]
+)
diff --git a/contrib/mdcompact/tests/5.md.out b/contrib/mdcompact/tests/5.md.out
new file mode 100644
index 00000000000..ed460ee1530
--- /dev/null
+++ b/contrib/mdcompact/tests/5.md.out
@@ -0,0 +1,11 @@ 
+(define_insn "<optab><mode>3"
+  [(set (match_operand:GPI 0 "register_operand")
+	(LOGICAL:GPI (match_operand:GPI 1 "register_operand")
+		     (match_operand:GPI 2 "aarch64_logical_operand")))]
+  ""
+  {@ [ cons: =0 , 1  , 2        ; attrs: type , arch  ]
+     [ r        , %r , r        ; logic_reg   , *     ] <logical>\t%<w>0, %<w>1, %<w>2
+     [ rk       , r  , <lconst> ; logic_imm   , *     ] <logical>\t%<w>0, %<w>1, %2
+     [ w        , w  , w        ; neon_logic  , simd  ] <logical>\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>
+  }
+)
diff --git a/contrib/mdcompact/tests/6.md b/contrib/mdcompact/tests/6.md
new file mode 100644
index 00000000000..a9f609503e2
--- /dev/null
+++ b/contrib/mdcompact/tests/6.md
@@ -0,0 +1,11 @@ 
+(define_insn "aarch64_wrffr"
+  [(set (reg:VNx16BI FFR_REGNUM)
+	(match_operand:VNx16BI 0 "aarch64_simd_reg_or_minus_one"))
+   (set (reg:VNx16BI FFRT_REGNUM)
+	(unspec:VNx16BI [(match_dup 0)] UNSPEC_WRFFR))]
+  "TARGET_SVE"
+  {@ [ cons: 0 ]
+     [ Dm      ] setffr
+     [ Upa     ] wrffr\t%0.b
+  }
+)
diff --git a/contrib/mdcompact/tests/6.md.out b/contrib/mdcompact/tests/6.md.out
new file mode 100644
index 00000000000..a9f609503e2
--- /dev/null
+++ b/contrib/mdcompact/tests/6.md.out
@@ -0,0 +1,11 @@ 
+(define_insn "aarch64_wrffr"
+  [(set (reg:VNx16BI FFR_REGNUM)
+	(match_operand:VNx16BI 0 "aarch64_simd_reg_or_minus_one"))
+   (set (reg:VNx16BI FFRT_REGNUM)
+	(unspec:VNx16BI [(match_dup 0)] UNSPEC_WRFFR))]
+  "TARGET_SVE"
+  {@ [ cons: 0 ]
+     [ Dm      ] setffr
+     [ Upa     ] wrffr\t%0.b
+  }
+)
diff --git a/contrib/mdcompact/tests/7.md b/contrib/mdcompact/tests/7.md
new file mode 100644
index 00000000000..6616deaa8db
--- /dev/null
+++ b/contrib/mdcompact/tests/7.md
@@ -0,0 +1,11 @@ 
+(define_insn "and<mode>3<vczle><vczbe>"
+  [(set (match_operand:VDQ_I 0 "register_operand" "=w,w")
+	(and:VDQ_I (match_operand:VDQ_I 1 "register_operand" "w,0")
+		   (match_operand:VDQ_I 2 "aarch64_reg_or_bic_imm" "w,Db")))]
+  "TARGET_SIMD"
+  "@
+   and\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>
+   * return aarch64_output_simd_mov_immediate (operands[2], <bitsize>,\
+					       AARCH64_CHECK_BIC);"
+  [(set_attr "type" "neon_logic<q>")]
+)
diff --git a/contrib/mdcompact/tests/7.md.out b/contrib/mdcompact/tests/7.md.out
new file mode 100644
index 00000000000..199b37a810f
--- /dev/null
+++ b/contrib/mdcompact/tests/7.md.out
@@ -0,0 +1,11 @@ 
+(define_insn "and<mode>3<vczle><vczbe>"
+  [(set (match_operand:VDQ_I 0 "register_operand")
+	(and:VDQ_I (match_operand:VDQ_I 1 "register_operand")
+		   (match_operand:VDQ_I 2 "aarch64_reg_or_bic_imm")))]
+  "TARGET_SIMD"
+  {@ [ cons: =0 , 1 , 2   ]
+     [ w        , w , w   ] and\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>
+     [ w        , 0 , Db  ] << aarch64_output_simd_mov_immediate (operands[2], <bitsize>, AARCH64_CHECK_BIC);
+  }
+  [(set_attr "type" "neon_logic<q>")]
+)