cmp: mcall: implement the type propagation, make similar to fcall

While there is less we can doc compared FCALL, we still can infer the function
type and propagate it. Both AST nodes FCALL and MCALL accept now the same set of
arguments and MCALL has a new type propagator.
This commit is contained in:
Daniel Kochmański 2023-09-11 17:04:17 +02:00
parent d014360836
commit 2a631151fd
4 changed files with 80 additions and 20 deletions

View file

@ -46,9 +46,7 @@
(:global (c2call-global c1form fun-val args))
(:unknown (c2call-unknown c1form fun args)))))
;;; FIXME now we could incorporate the call type for MCALL to faciliate the
;;; type propagation.
(defun c2mcall (c1form form args)
(defun c2mcall (c1form form args fun-val call-type)
(c2call-stack c1form form args t))
;;;

View file

@ -80,23 +80,76 @@
;; (FUNCALL lisp-expression ...) or (FUNCALL atomic-expression ...)
(unoptimized-funcall fun arguments))))
;;; Further optimization opportunities:
;;; - expand macros
;;; - expand compiler macros
;;; - rely on the function proclamations
;;; - rely on the inferred argument type
(defun try-spill-values-funcall (fun arguments)
(flet ((values-form (arg)
(setq arg (chk-symbol-macrolet arg))
(if (or (atom arg)
(eq (car arg) 'CL:VALUES))
arg
(return-from try-spill-values-funcall nil))))
(loop for arg in arguments
for val = (values-form arg)
if (atom val)
collect val into values
else
append (cdr val) into values
finally (return (c1funcall (list* fun values))))))
(defun try-macro-expression-mvc (fun arguments)
(unless (consp fun)
(return-from try-macro-expression-mvc nil))
(let* ((name (first fun))
(fd (and (symbolp name)
;; We do not want to macroexpand 'CL:THE
(not (eq name 'CL:THE))
(cmp-macro-function name))))
(if fd
(c1multiple-value-call (list* (cmp-expand-macro fd fun) arguments))
nil)))
(defun try-function-special-mvc (fun arguments)
(unless (function-form-p fun)
(return-from try-function-special-mvc nil))
(let ((fname (second fun)))
(if (si:valid-function-name-p fname)
(ext:if-let ((funob (local-function-ref fname)))
(make-c1form* 'MCALL
:sp-change t ; conservative estimate
:side-effects t ; conservative estimate
:args (c1expr fun) (c1args* arguments) funob :local)
(make-c1form* 'MCALL
:sp-change (function-may-change-sp fname)
:side-effects (function-may-have-side-effects fname)
:args (c1expr fun) (c1args* arguments) fname :global))
(if (lambda-form-p fun)
nil
(cmperr "Malformed function name: ~A." fname)))))
(defun unoptimized-mvc (fun arguments)
(let ((fun-form (c1expr fun))
(fun-args (c1args* arguments)))
(make-c1form* 'MCALL
:sp-change t
:side-effects t
:args fun-form fun-args nil :unknown)))
(defun c1multiple-value-call (args &aux forms)
(check-args-number 'CL:MULTIPLE-VALUE-CALL args 1)
(cond
;; (M-V-C #'FUNCTION) => (FUNCALL #'FUNCTION)
((endp (rest args))
(c1funcall args))
;; (M-V-C #'FUNCTION (VALUES A ... Z)) => (FUNCALL #'FUNCTION A ... Z)
((and (= (length args) 2)
(consp (setq forms (second args)))
(eq 'CL:VALUES (first forms)))
(c1funcall (list* (first args) (rest forms))))
;; More complicated case.
(t
(make-c1form* 'MCALL
:sp-change t
:side-effects t
:args (c1expr (first args)) (c1args* (rest args))))))
(destructuring-bind (fun . arguments) args
(or ;; (M-V-C expression (VALUES A B) (VALUES X Y Z) ...)
;; => (FUNCALL expression A B X Y Z ...)
(try-spill-values-funcall fun arguments)
;; (M-V-C macro-expression ...)
(try-macro-expression-mvc fun arguments)
;; (M-V-C (FUNCTION function-name) ...)
(try-function-special-mvc fun arguments)
;; (M-V-C lisp-expression ...) or (M-V-C atomic-expression ...)
(unoptimized-mvc fun arguments))))
(defun c1apply (args)
(check-args-number 'CL:APPLY args 2)

View file

@ -115,6 +115,15 @@
(:unknown
(p1trivial c1form))))
(defun p1mcall (c1form fun args fun-val call-type)
(declare (ignore fun))
(p1propagate fun)
(p1propagate-list args)
(ecase call-type
(:global (or (get-return-type fun-val) '(VALUES &REST T)))
(:local (or (get-local-return-type fun-val) '(VALUES &REST T)))
(:unknown (p1trivial c1form))))
(defun p1catch (c1form tag body)
(declare (ignore c1form))
(p1propagate tag)

View file

@ -33,7 +33,7 @@
(CL:TAGBODY tag-var tag-body :pure)
(CL:RETURN-FROM blk-var nonlocal value :side-effects)
(FCALL fun-form (arg-value*) fun-val call-type :side-effects)
(MCALL fun-form (arg-value*) :side-effects)
(MCALL fun-form (arg-value*) fun-val call-type :side-effects)
(CL:CATCH catch-value body :side-effects)
(CL:UNWIND-PROTECT protected-c1form body :side-effects)
@ -263,7 +263,7 @@
'((cl:block . p1block)
(cl:return-from . p1return-from)
(fcall . p1fcall)
(mcall . p1trivial)
(mcall . p1mcall)
(cl:catch . p1catch)
(cl:throw . p1throw)
(cl:if . p1if)