1 ;;; -*- lexical-binding: t; -*-
3 ;; Author: Andrea Corallo <andrea.corallo@arm.com>
5 ;; Keywords: languages, extensions
6 ;; Package-Requires: ((emacs "29"))
8 ;; This file is part of GCC.
10 ;; GCC is free software: you can redistribute it and/or modify it
11 ;; under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
15 ;; GCC is distributed in the hope that it will be useful, but WITHOUT
16 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
18 ;; License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GCC. If not, see <https://www.gnu.org/licenses/>.
25 ;; Convert multi choice GCC machine description patterns to compact
30 ;; With the point on a pattern run 'M-x mdcomp-run-at-point' to
31 ;; convert that pattern.
33 ;; Run 'M-x mdcomp-run-buffer' to convert all convertible patterns in
34 ;; the current buffer.
36 ;; Run 'M-x mdcomp-run-directory' to convert all convertible patterns
39 ;; One can invoke the tool from shell as well, ex for running it on
40 ;; the arm backend from the GCC checkout directory:
41 ;; emacs -batch -l ./contrib/mdcompact/mdcompact.el -f mdcomp-run-directory ./gcc/config/arm/
50 (rx "(match_operand" (?
":" (1+ (or punct alnum
)))
51 (1+ space
) (group-n 1 num
) (1+ space
) "\""
52 (1+ (or alnum
"_" "<" ">")) "\""
53 (group-n 2 (1+ space
) "\"" (group-n 3 (0+ (not "\""))) "\"")
56 (cl-defstruct mdcomp-operand
60 (cl-defstruct mdcomp-attr
65 (rx-define mdcomp-name
(1+ (or alnum
"_")))
67 (defconst mdcomp-attr-rx
68 (rx "(set_attr" (1+ space
) "\""
69 (group-n 1 mdcomp-name
)
71 (group-n 2 (1+ (not ")")))
74 (defun mdcomp-parse-delete-attr ()
76 (when (re-search-forward mdcomp-attr-rx nil t
)
77 (let ((res (save-match-data
79 :name
(match-string-no-properties 1)
80 :vals
(cl-delete-if #'string-empty-p
82 (replace-regexp-in-string
84 (match-string-no-properties 2))
85 (rx (1+ (or space
",")))))))))
86 (if (length= (mdcomp-attr-vals res
) 1)
88 (delete-region (match-beginning 0) (match-end 0))
91 (defun mdcomp-parse-attrs ()
93 (let* ((res (cl-loop for x
= (mdcomp-parse-delete-attr)
96 (beg (re-search-backward (rx bol
(1+ space
) "["))))
97 (unless (memq 'short res
)
99 (delete-region beg
(re-search-forward (rx "]")))))
100 (cl-delete 'short res
))))
102 (defun mdcomp-remove-quoting (beg)
105 (replace-regexp-in-region (regexp-quote "\\\\") "\\\\" beg
(point-max))
106 (replace-regexp-in-region (regexp-quote "\\\"") "\"" beg
(point-max)))))
108 (defun mdcomp-remove-escaped-newlines (beg)
111 (replace-regexp-in-region (rx "\\" eol
(0+ space
)) " " beg
(point-max)))))
113 (defun mdcomp-parse-delete-cstr ()
114 (cl-loop while
(re-search-forward mdcomp-constr-rx nil t
)
115 unless
(string= "" (match-string-no-properties 3))
116 collect
(save-match-data
118 :num
(string-to-number (match-string-no-properties 1))
119 :cstr
(cl-delete-if #'string-empty-p
121 (replace-regexp-in-string " " ""
122 (match-string-no-properties 3))
124 do
(delete-region (match-beginning 2) (match-end 2))))
126 (defun mdcomp-run* ()
127 (let* ((ops (mdcomp-parse-delete-cstr))
128 (attrs (mdcomp-parse-attrs))
129 (beg (re-search-forward "\"@")))
130 (cl-sort ops
(lambda (x y
)
131 (< (mdcomp-operand-num x
) (mdcomp-operand-num y
))))
132 (mdcomp-remove-escaped-newlines beg
)
140 (mdcomp-remove-quoting beg
)
142 (re-search-forward (rx (or "\"" ")")))
143 (re-search-backward "@")
148 when
(string-match "=" (cl-first (mdcomp-operand-cstr op
)))
150 do
(insert (number-to-string (mdcomp-operand-num op
)) ", ")
153 ;; In case add attributes names
157 (cl-loop for attr in attrs
158 do
(insert (mdcomp-attr-name attr
) ", ")))
162 while
(re-search-forward (rx bol
(0+ space
) (or (group-n 1 "* return")
167 when
(match-string 2)
169 when
(match-string 1)
171 (delete-region (match-beginning 1) (+ (match-beginning 1) (length "* return")))
178 initially
(insert " [ ")
180 for c
= (nth i
(mdcomp-operand-cstr op
))
183 do
(insert (if (string-match "=" c
)
191 (cl-loop for attr in attrs
192 for str
= (nth i
(mdcomp-attr-vals attr
))
198 (move-end-of-line 1)))))
199 ;; remove everything after ] align what needs to be aligned
200 ;; and re-add the asm template
201 (re-search-backward (regexp-quote "@[ cons:"))
202 (let* ((n (length (mdcomp-operand-cstr (car ops
))))
204 initially
(re-search-forward "]")
206 collect
(let* ((beg (re-search-forward "]"))
207 (end (re-search-forward (rx eol
)))
208 (str (buffer-substring-no-properties beg end
)))
209 (delete-region beg end
)
211 (beg (re-search-backward (regexp-quote "@[ cons:")))
212 (indent-tabs-mode nil
))
213 (re-search-forward "}")
214 (align-regexp beg
(point) (rx (group-n 1 "") "["))
215 (align-regexp beg
(point) (rx (group-n 1 "") (or "," ";")) nil nil t
)
216 (align-regexp beg
(point) (rx (group-n 1 "") "]"))
219 initially
(re-search-forward "]")
222 (re-search-forward "]")
223 (insert (nth i asms
))))
224 (when (re-search-forward (rx (1+ (or space eol
)) ")") nil t
)
225 (replace-match "\n)" nil t
)))))
227 (defun mdcomp-narrow-to-md-pattern ()
229 (let ((beg (re-search-forward "\n("))
230 (end (re-search-forward (rx bol
(1+ ")")))))
231 (narrow-to-region beg end
))
235 (defun mdcomp-run-at-point ()
236 "Convert the multi choice top-level form around point to compact syntax."
239 (save-mark-and-excursion
240 (mdcomp-narrow-to-md-pattern)
241 (goto-char (point-min))
242 (let ((pattern-name (save-excursion
243 (re-search-forward (rx "\"" (group-n 1 (1+ (not "\""))) "\""))
244 (match-string-no-properties 1)))
245 (orig-text (buffer-substring-no-properties (point-min) (point-max))))
249 (message "Converted: %s" pattern-name
))
251 (message "Skipping convertion for: %s" pattern-name
)
252 (delete-region (point-min) (point-max))
256 (defun mdcomp-run-buffer ()
257 "Convert the multi choice top-level forms in the buffer to compact syntax."
260 (message "Conversion for buffer %s started" (buffer-file-name))
261 (goto-char (point-min))
262 (while (re-search-forward
263 (rx "match_operand" (1+ any
) letter
(0+ space
) "," (0+ space
) letter
) nil t
)
264 (when (eq (mdcomp-run-at-point) 'fail
)
268 ;; If forward-sexp fails falls back.
269 (re-search-forward (rx ")" eol eol
))))))
270 (message "Conversion done")))
272 (defconst mdcomp-file-rx
(rx bol alpha
(0+ not-newline
) ".md" eol
))
274 (defun mdcomp-run-directory (folder &optional recursive
)
275 "Run el mdcompact on a FOLDER possibly in a RECURSIVE fashion."
277 (let ((before-save-hook nil
)
278 (init-time (current-time)))
281 (message "Working on %s" f
)
282 (insert-file-contents f
)
284 (message "Done with %s" f
)))
286 (directory-files-recursively folder mdcomp-file-rx
)
287 (directory-files folder t mdcomp-file-rx
)))
288 (message "Converted in %f sec" (float-time (time-since init-time
)))))
290 (defun mdcomp-batch-run-directory ()
291 "Same as `mdcomp-run-directory' but use cmd line args."
292 (mdcomp-run-directory (nth 0 argv
) (nth 1 argv
)))
296 ;;; mdcompact.el ends here