diff --git a/src/lisp/kernel/cleavir/cmpintrinsics.lisp b/src/lisp/kernel/cleavir/cmpintrinsics.lisp index a536def97f..b1555f3c62 100644 --- a/src/lisp/kernel/cleavir/cmpintrinsics.lisp +++ b/src/lisp/kernel/cleavir/cmpintrinsics.lisp @@ -646,10 +646,13 @@ Boehm and MPS use a single pointer" ;; or the vaslist is used to access the arguments ;; one after the other with calling-convention.va-arg (defstruct calling-convention + ;; LLVM value: the closure. This is only used to feed errors, e.g. + ;; cc_wrong_number_of_arguments, so it can be a function name rather + ;; than an actual function or closure. closure - nargs - register-args ; The arguments that were passed in registers - vaslist* ; The address of the vaslist, or NIL + nargs ; LLVM value: number of arguments + register-args ; List of LLVM values: The arguments that were passed in registers + vaslist* ; LLVM Value: The address of the vaslist, or NIL cleavir-lambda-list-analysis ; analysis of cleavir-lambda-list rest-alloc ; whether we can dx or ignore a &rest argument ) diff --git a/src/lisp/kernel/cleavir/compile-bytecode.lisp b/src/lisp/kernel/cleavir/compile-bytecode.lisp index bf83127a41..b4ec92fa46 100644 --- a/src/lisp/kernel/cleavir/compile-bytecode.lisp +++ b/src/lisp/kernel/cleavir/compile-bytecode.lisp @@ -157,6 +157,25 @@ (build:begin inserter (binfo-irblock binfo)) (context-new-block context (binfo-context binfo))))) +;;; Note a function as a module entry point. +;;; KLUDGE: this should just be an nadjoinf, but Cleavir behaves poorly +;;; if a closure is an entry point and its parent is not. +;;; That's a FIXME for Cleavir. +(defun mark-entry-point (irfun funmap + &optional (bcfun + (finfo-bcfun + (find-irfun irfun funmap)))) + (cleavir-set:nadjoinf (bir:entry-points (bir:module irfun)) + irfun) + (when (and (bir:enclose irfun) + ;; if it doesn't actually close over anything + ;; we don't need the parent. + ;; This is an important case for e.g. DEFUN'd functions, + ;; which in bytecode are closed over by the function + ;; that does (setf fdefinition). + (> (length (bcfun/nvars bcfun)) 0)) + (mark-entry-point (bir:function (bir:enclose irfun)) funmap))) + ;;; Given a bytecode function, return a compiled native function. ;;; Used for CL:COMPILE. (defun compile-function (function @@ -165,18 +184,20 @@ (disassemble nil)) (multiple-value-bind (module funmap) (compile-bcmodule (core:simple-fun-code function)) - (bir:verify module) - (when disassemble - (cleavir-bir-disassembler:display module)) - (clasp-cleavir::bir-transformations module system) - (dissociate-inappropriate-closures (fmap funmap)) - (let (;; Ensure any closures have the same layout as original - ;; bytecode closures, so the simple fun can be swapped - ;; out transparently. - (clasp-cleavir::*fixed-closures* - (fixed-closures-map (fmap funmap))) - (bir (finfo-irfun (find-bcfun function funmap)))) - (clasp-cleavir::bir->function bir :abi abi)))) + (let ((bir (finfo-irfun (find-bcfun function funmap)))) + (mark-entry-point bir funmap function) + (bir:remove-unused-values module) + (bir:verify module) + (when disassemble + (cleavir-bir-disassembler:display module)) + (clasp-cleavir::bir-transformations module system) + (dissociate-inappropriate-closures (fmap funmap)) + (let (;; Ensure any closures have the same layout as original + ;; bytecode closures, so the simple fun can be swapped + ;; out transparently. + (clasp-cleavir::*fixed-closures* + (fixed-closures-map (fmap funmap)))) + (clasp-cleavir::bir->function bir :abi abi))))) ;;; Given a bytecode module, compute native functions for all bytecode functions ;;; in it, and install them as new simple funs. Return value irrelevant. @@ -185,6 +206,14 @@ &key (abi clasp-cleavir::*abi-x86-64*) (system clasp-cleavir:*clasp-system*)) (multiple-value-bind (irmodule funmap) (compile-bcmodule module) + (loop for info across (core:bytecode-module/debug-info module) + when (typep info 'core:bytecode-simple-fun) + do (let ((finfo (find-bcfun info funmap))) + (when finfo + (mark-entry-point (finfo-irfun finfo) + funmap + (finfo-bcfun finfo))))) + (bir:remove-unused-values irmodule) (clasp-cleavir::bir-transformations irmodule system) (dissociate-inappropriate-closures (fmap funmap)) (multiple-value-bind (function-infos constants ctable fvector) @@ -218,7 +247,7 @@ ;;; from the funmap. ;;; This has to be called after bir-transformations, or more ;;; specifically, after determine-function-environments. -;;; (simple example: (lambda (x) (flet ((foo () x)) (lambda () foo))) +;;; (simple example: (lambda (x) (flet ((foo () x)) (lambda () (foo)))) ;;; the inner lambda is optimized to close over x not #'foo.) (defun dissociate-inappropriate-closures (fmap) (loop for entry in fmap @@ -426,8 +455,7 @@ :policy cmp:*policy* ; FIXME :attributes nil :module module)) - (start (make-start-block inserter function bytecode-function))) - (setf (bir:start function) start) + (start (make-start-block function bytecode-function))) (set:nadjoinf (bir:functions module) function) function)) @@ -462,12 +490,11 @@ (assert (stack context)) (pop (stack context))) -(defun make-start-block (inserter irfun bcfun) - (build:make-iblock - inserter +(defun make-start-block (irfun bcfun) + (build:make-start-iblock + irfun :name (symbolicate (write-to-string (bcfun/fname bcfun)) - '#:-start) - :function irfun :dynamic-environment irfun)) + '#:-start))) (defun symbolicate (&rest components) ;; FIXME: Probably just use concatenate @@ -1728,6 +1755,15 @@ (let* ((irmodule (make-instance 'bir:module)) (literals (compute-compiled-literals literals-info irmodule)) (funmap (compile-bytecode-into bytecode debug-info literals irmodule))) + (loop for info across debug-info + when (typep info 'cmp:cfunction) + do (let ((finfo (find-bcfun info funmap))) + (when finfo + (mark-entry-point (finfo-irfun finfo) + funmap + (finfo-bcfun finfo))))) + (bir:remove-unused-values irmodule) + (bir:verify irmodule) ;;(cleavir-bir-disassembler:display irmodule) (terpri) (clasp-cleavir::bir-transformations irmodule clasp-cleavir:*clasp-system*) (dissociate-inappropriate-closures (fmap funmap)) diff --git a/src/lisp/kernel/cleavir/representation-selection.lisp b/src/lisp/kernel/cleavir/representation-selection.lisp index 5e3426c1f0..8582e60514 100644 --- a/src/lisp/kernel/cleavir/representation-selection.lisp +++ b/src/lisp/kernel/cleavir/representation-selection.lisp @@ -162,7 +162,9 @@ (let ((rt '())) (cleavir-set:doset (call calls rt) (let* ((call-arg (nth pos (rest (bir:inputs call)))) - (next-rt (definition-rtype call-arg)) + (next-rt (if call-arg + (definition-rtype call-arg) + nil)) (real-next-rt (cond ((null next-rt) nil) ((member next-rt '(:vaslist @@ -451,16 +453,15 @@ (when (member returni-input *chasing-rtypes-of* :test #'eq) (return-from return-use-rtype '())) (let ((*chasing-rtypes-of* (cons returni-input *chasing-rtypes-of*)) - (rt nil) - (local-calls (bir:local-calls function))) - (if (or (bir:enclose function) (cleavir-set:empty-set-p local-calls)) - ;; The function is enclosed, so it could be called from anywhere, and - ;; we need to use the pessimistic protocol. No enclose and no local - ;; calls means it's the top level function, so the same situation. + (rt nil)) + (if (or (bir:enclose function) (bir:entry-point-p function)) + ;; The function is enclosed or an entry point, + ;; so it could be called from anywhere, + ;; and we need to use the pessimistic protocol. :multiple-values ;; No enclose, so we can look at all the call sites, and if they're ;; amenable, do something smarter. - (cleavir-set:doset (call local-calls rt) + (cleavir-set:doset (call (bir:local-calls function) rt) (setf rt (max-rtype rt (use-rtype (bir:output call)))))))) (defgeneric compute-rtype (datum)) @@ -728,7 +729,9 @@ (let ((args (rest (bir:inputs instruction)))) (loop for item in (bir:lambda-list (bir:callee instruction)) while (typep item 'bir:argument) - do (maybe-cast-before instruction (pop args) (cc-bmir:rtype item))) + do (let ((arg (pop args))) + (when arg ; there may not be enough arguments + (maybe-cast-before instruction arg (cc-bmir:rtype item))))) (loop until (null args) do (maybe-cast-before instruction (pop args) '(:object)))) (cast-local-call-output instruction)) diff --git a/src/lisp/kernel/cleavir/translate.lisp b/src/lisp/kernel/cleavir/translate.lisp index bc0f7d658d..c267fdc4af 100644 --- a/src/lisp/kernel/cleavir/translate.lisp +++ b/src/lisp/kernel/cleavir/translate.lisp @@ -17,38 +17,8 @@ ;; NIL if there's no XEP. (%prototype :initarg :prototype :reader prototype))) -(defun lambda-list-too-hairy-p (lambda-list) - (multiple-value-bind (reqargs optargs rest-var key-flag keyargs aok aux varest-p) - (cmp:process-bir-lambda-list lambda-list) - (declare (ignore reqargs optargs keyargs aok aux rest-var varest-p)) - key-flag)) - -(defun nontrivial-mv-local-call-p (call) - (cond ((typep call 'cc-bmir:fixed-mv-local-call) - ;; Could still be nontrivial if the number of arguments is wrong - (multiple-value-bind (req opt rest) - (cmp:process-bir-lambda-list (bir:lambda-list (bir:callee call))) - (let ((lreq (length (cc-bmir:rtype (second (bir:inputs call)))))) - (or (< lreq (car req)) - (and (not rest) (> lreq (+ (car req) (car opt)))))))) - ((typep call 'bir:mv-local-call) t) - (t nil))) - (defun xep-needed-p (function) - (or (bir:enclose function) - ;; We need a XEP for more involved lambda lists. - (lambda-list-too-hairy-p (bir:lambda-list function)) - ;; or for mv-calls that might need to signal an error. - (and (cleavir-set:some #'nontrivial-mv-local-call-p - (bir:local-calls function)) - (multiple-value-bind (req opt rest) - (cmp:process-bir-lambda-list (bir:lambda-list function)) - (declare (ignore opt)) - (or (plusp (car req)) (not rest)))) - ;; Assume that a function with no enclose and no local calls is - ;; toplevel and needs an XEP. Else it would have been removed or - ;; deleted as it is unreferenced otherwise. - (cleavir-set:empty-set-p (bir:local-calls function)))) + (or (bir:enclose function) (bir:entry-point-p function))) (defun argument-rtype->llvm (arg) (let ((rtype (cc-bmir:rtype arg))) @@ -935,56 +905,63 @@ function-or-placeholder - the llvm function or a placeholder for :vaslist :object)) -(defun gen-local-call (callee arguments outputrt) - (let ((callee-info (find-llvm-function-info callee))) - (cond ((lambda-list-too-hairy-p (bir:lambda-list callee)) - ;; Has &key or something, so use the normal call protocol. - ;; We allocate a fresh closure for every call. Hopefully this - ;; isn't too expensive. We can always use stack allocation since - ;; there's no possibility of this closure being stored in a closure - ;; (If we local-call a self-referencing closure, the closure cell - ;; will get its value from some enclose. - ;; FIXME we could use that instead?) - (translate-cast (closure-call-or-invoke - (enclose callee :dynamic nil) - arguments) - :multiple-values outputrt)) - (t - ;; Call directly. - (multiple-value-bind (req opt rest-var key-flag keyargs aok aux - varest-p) - (cmp:process-bir-lambda-list (bir:lambda-list callee)) - (declare (ignore keyargs aok aux)) - (assert (not key-flag)) - (let ((largs (length arguments))) - (when (or (< largs (car req)) - (and (not rest-var) - (> largs (+ (car req) (car opt))))) - ;; too many or too few args; we can get here from - ;; fixed-mv-local-calls for instance. - (return-from gen-local-call - (translate-cast (closure-call-or-invoke - (enclose callee :dynamic nil) - arguments) - :multiple-values outputrt)))) - (let* ((rest-id (cond ((null rest-var) nil) - ((bir:unused-p rest-var) :unused) - (varest-p :va-rest) - (t t))) - (rest-vrtype (rest-vrtype rest-var)) - (subargs - (parse-local-call-arguments - req opt rest-id rest-vrtype arguments)) - (args (append (environment-arguments - (environment callee-info)) - subargs)) - (function (main-function callee-info)) - (function-type (llvm-sys:get-function-type function)) - (result-in-registers - (cmp::irc-call-or-invoke function-type function args))) - #+(or) - (llvm-sys:set-calling-conv result-in-registers 'llvm-sys:fastcc) - (local-call-rv->inputs result-in-registers outputrt))))))) +(defun gen-local-call (callee arguments output-name outputrt) + ;; LLVM whines if we provide a name for a call returning void FIXME + (declare (ignore output-name)) + (let* ((callee-info (find-llvm-function-info callee)) + (parameters (arguments callee-info)) + (environment (environment callee-info)) + (function (main-function callee-info)) + (function-type (llvm-sys:get-function-type function)) + (ll-analysis (cmp:calculate-cleavir-lambda-list-analysis + (bir:lambda-list callee))) + (calling-convention + (cmp:make-calling-convention + :rest-alloc (compute-rest-alloc ll-analysis) + :cleavir-lambda-list-analysis ll-analysis + :register-args arguments + :nargs (%size_t (length arguments)) + :closure (literal (bir:name callee)))) + (paramvalues ()) + (ll-result + (cmp:compile-lambda-list-code + ll-analysis calling-convention + (length arguments) + :argument-out (lambda (value param) + (push (cons param value) paramvalues)))) + (_ + (when (not ll-result) + ;; compile-lambda-list-code returned nil, which means we + ;; have an argcount mismatch and it has inserted an error + ;; call. Everything past this is unreachable, so don't + ;; call the function. TODO: poison instead of undef? + ;; also TODO: just delete these calls + (cmp:irc-begin-block + (cmp:irc-basic-block-create "unreachable")) + (return-from gen-local-call + (local-call-rv->inputs + (llvm-sys:undef-value-get + (llvm-sys:function-type-return-type function-type)) + outputrt)))) + (arguments + (nconc (environment-arguments environment) + (loop with nreq = (cmp::cleavir-lambda-list-analysis-min-nargs ll-analysis) + for param in parameters + for i from 0 + for v = (cdr (assoc param paramvalues)) + unless v + do (error "BUG: Missing argument ~a" param) + collect (if (< i nreq) + ;; required argument, so the param + ;; is just the argument and thus + ;; of the correct rtype already + v + (translate-cast v '(:object) + (cc-bmir:rtype param)))))) + (call + (cmp:irc-call-or-invoke function-type function arguments))) + (declare (ignore _)) + (local-call-rv->inputs call outputrt))) (defmethod translate-simple-instruction ((instruction bir:local-call) abi) @@ -992,7 +969,9 @@ function-or-placeholder - the llvm function or a placeholder for (let* ((callee (bir:callee instruction)) (args (mapcar #'in (rest (bir:inputs instruction)))) (output (bir:output instruction)) - (call (gen-local-call callee args (cc-bmir:rtype output)))) + (call (gen-local-call callee args + (datum-name-as-string output) + (cc-bmir:rtype output)))) (out call output))) (defmethod translate-simple-instruction ((instruction bir:call) abi) @@ -1006,123 +985,6 @@ function-or-placeholder - the llvm function or a placeholder for :label (datum-name-as-string output)) output))) -(defun general-mv-local-call-vas (callee vaslist label outputrt) - (translate-cast (cmp:irc-apply (enclose callee :dynamic nil) - (cmp:irc-vaslist-nvals vaslist) - (cmp:irc-vaslist-values vaslist) - label) - :multiple-values outputrt)) - -(defun direct-mv-local-call-vas (vaslist callee req opt rest-var varest-p - label outputrt) - (let* ((callee-info (find-llvm-function-info callee)) - (nreq (car req)) - (nopt (car opt)) - (rnret (cmp:irc-vaslist-nvals vaslist)) - (rvalues (cmp:irc-vaslist-values vaslist)) - (nfixed (+ nreq nopt)) - (mismatch - (unless (and (zerop nreq) rest-var) - (cmp:irc-basic-block-create "lmvc-arg-mismatch"))) - (mte (if rest-var - (cmp:irc-basic-block-create "lmvc-more-than-enough") - mismatch)) - (merge (cmp:irc-basic-block-create "lmvc-after")) - (sw (cmp:irc-switch rnret mte (+ 1 nreq nopt))) - (environment (environment callee-info)) - (rest-vaboxp (not (eq (rest-vrtype rest-var) :vaslist)))) - (labels ((load-return-value (n) - (cmp:irc-t*-load (cmp:irc-typed-gep cmp:%t*% rvalues (list n)))) - (load-return-values (low high) - (loop for i from low below high - collect (load-return-value i))) - (optionals (n) - (parse-local-call-optional-arguments - opt (load-return-values nreq (+ nreq n))))) - ;; Generate phis for the merge block's call. - (cmp:irc-begin-block merge) - (let ((opt-phis - (loop for (op s-p) on (rest opt) by #'cdddr - for op-ty = (argument-rtype->llvm op) - for s-p-ty = (argument-rtype->llvm s-p) - collect (cmp:irc-phi op-ty (1+ nopt)) - collect (cmp:irc-phi s-p-ty (1+ nopt)))) - (rest-phi - (cond ((null rest-var) nil) - ((bir:unused-p rest-var) - (cmp:irc-undef-value-get cmp:%t*%)) - (t (cmp:irc-phi (argument-rtype->llvm rest-var) - (1+ nopt)))))) - ;; Generate the mismatch block, if it exists. - (when mismatch - (cmp:irc-begin-block mismatch) - (cmp::irc-intrinsic-call-or-invoke - "cc_wrong_number_of_arguments" - (list (enclose callee :indefinite nil) rnret - (%size_t nreq) (%size_t nfixed))) - (cmp:irc-unreachable)) - ;; Generate not-enough-args cases. - (loop for i below nreq - do (cmp:irc-add-case sw (%size_t i) mismatch)) - ;; Generate optional arg cases, including the exactly-enough case. - (loop for i upto nopt - for b = (cmp:irc-basic-block-create - (format nil "lmvc-optional-~d" i)) - do (cmp:irc-add-case sw (%size_t (+ nreq i)) b) - (cmp:irc-begin-block b) - (loop for phi in opt-phis - for val in (optionals i) - do (cmp:irc-phi-add-incoming phi val b)) - (when (and rest-var (not (bir:unused-p rest-var))) - (cmp:irc-phi-add-incoming - rest-phi - (if varest-p - (maybe-boxed-vaslist - rest-vaboxp (%size_t 0) - (llvm-sys:constant-pointer-null-get cmp:%t**%)) - (%nil)) - b)) - (cmp:irc-br merge)) - ;; If there's a &rest, generate the more-than-enough arguments case. - (when rest-var - (cmp:irc-begin-block mte) - (loop for phi in opt-phis - for val in (optionals nopt) - do (cmp:irc-phi-add-incoming phi val mte)) - (unless (bir:unused-p rest-var) - (cmp:irc-phi-add-incoming - rest-phi - (if varest-p - (maybe-boxed-vaslist - rest-vaboxp - (cmp:irc-sub rnret (%size_t nfixed)) - (cmp:irc-typed-gep cmp:%t*% rvalues (list nfixed))) - (%intrinsic-invoke-if-landing-pad-or-call - "cc_mvcGatherRest2" - (list (cmp:irc-typed-gep cmp:%t*% rvalues (list nfixed)) - (cmp:irc-sub rnret (%size_t nfixed))))) - mte)) - (cmp:irc-br merge)) - ;; Generate the call, in the merge block. - (cmp:irc-begin-block merge) - (let* ((arguments - (nconc - (environment-arguments environment) - (loop for r in (rest req) - for j from 0 - collect (translate-cast (load-return-value j) '(:object) - (cc-bmir:rtype r))) - opt-phis - (when rest-var (list rest-phi)))) - (function (main-function callee-info)) - (function-type (llvm-sys:get-function-type function)) - (call - (cmp:irc-call-or-invoke function-type function arguments - cmp:*current-unwind-landing-pad-dest* - label))) - #+(or)(llvm-sys:set-calling-conv call 'llvm-sys:fastcc) - (local-call-rv->inputs call outputrt)))))) - (defmethod translate-simple-instruction ((instruction bir:mv-local-call) abi) (declare (ignore abi)) @@ -1130,20 +992,55 @@ function-or-placeholder - the llvm function or a placeholder for (outputrt (cc-bmir:rtype output)) (oname (datum-name-as-string output)) (callee (bir:callee instruction)) + (callee-info (find-llvm-function-info callee)) (mvarg (second (bir:inputs instruction))) - (mvargrt (cc-bmir:rtype mvarg)) - (mvargi (in mvarg))) - (assert (eq mvargrt :vaslist)) - (out - (multiple-value-bind (req opt rest-var key-flag keyargs - aok aux varest-p) - (cmp::process-bir-lambda-list (bir:lambda-list callee)) - (declare (ignore keyargs aok aux)) - (if key-flag - (general-mv-local-call-vas callee mvargi oname outputrt) - (direct-mv-local-call-vas - mvargi callee req opt rest-var varest-p oname outputrt))) - output))) + (_1 (assert (eq (cc-bmir:rtype mvarg) :vaslist))) + (mvargi (in mvarg)) + (nargs (cmp:irc-vaslist-nvals mvargi)) + (ll-analysis (cmp:calculate-cleavir-lambda-list-analysis + (bir:lambda-list callee))) + (vaslist* (cmp:alloca-vaslist)) + (calling-convention + (cmp:make-calling-convention + :rest-alloc (compute-rest-alloc ll-analysis) + :cleavir-lambda-list-analysis ll-analysis + :vaslist* vaslist* + :register-args () + ;; FIXME: the vaslist already has this so what gives + :nargs nargs + :closure (literal (bir:name callee)))) + ;; An alist from BIR:ARGUMENTs to LLVM values for them. + ;; We use this instead of going through OUT/IN as we do for + ;; XEPs because there may be multiple calls to the same + ;; function (which thus use the same ARGUMENTs). + (argvalues ()) + (arglist (arguments callee-info)) + (environment (environment callee-info)) + (_2 + (cmp:vaslist-start vaslist* nargs + (cmp:irc-vaslist-values mvargi))) + (_3 + (cmp:compile-lambda-list-code + ll-analysis calling-convention + :general-entry + :argument-out (lambda (value arg) + (push (cons arg value) argvalues)))) + (arguments + (nconc (environment-arguments environment) + (loop for arg in arglist + for v = (cdr (assoc arg argvalues)) + unless v + do (error "BUG: Missing argument ~a" arg) + collect (translate-cast v '(:object) + (cc-bmir:rtype arg))))) + (function (main-function callee-info)) + (function-type (llvm-sys:get-function-type function)) + (call + (cmp:irc-call-or-invoke function-type function arguments + cmp:*current-unwind-landing-pad-dest* + oname))) + (declare (ignore _1 _2 _3)) + (out (local-call-rv->inputs call outputrt) output))) (defmethod translate-simple-instruction ((instruction cc-bmir:fixed-mv-local-call) abi) @@ -1159,6 +1056,7 @@ function-or-placeholder - the llvm function or a placeholder for (gen-local-call callee (if (= (length mvargrt) 1) (list mvargi) mvargi) + (datum-name-as-string output) (cc-bmir:rtype output)) output))) @@ -2343,6 +2241,7 @@ function-or-placeholder - the llvm function or a placeholder for :name (make-symbol (format nil "~a-CALLER-START" signature)) :function caller :dynamic-environment caller))) (cleavir-set:nadjoinf (bir:functions module) caller) + (cleavir-set:nadjoinf (bir:entry-points module) caller) (setf (bir:start caller) iblock (bir:lambda-list caller) arguments) (build:begin inserter iblock) diff --git a/src/lisp/kernel/clos/conditions.lisp b/src/lisp/kernel/clos/conditions.lisp index 72cd53c2e1..0d865df5d9 100644 --- a/src/lisp/kernel/clos/conditions.lisp +++ b/src/lisp/kernel/clos/conditions.lisp @@ -1079,7 +1079,11 @@ The conflict resolver must be one of ~s" chosen-symbol candidates)) (let* ((min (min-nargs condition)) (max (max-nargs condition)) (function (called-function condition)) - (name (and function (core:function-name function))) + (name (typecase function + (null 'cl:lambda) + (function (core:function-name function)) + ;; assume it's a name, e.g. symbol + (t function))) (dname (if (eq name 'cl:lambda) "anonymous function" name))) (format stream "~@[Calling ~a - ~]Got ~d arguments, but expected ~@?" dname (given-nargs condition) @@ -1115,18 +1119,24 @@ The conflict resolver must be one of ~s" chosen-symbol candidates)) (define-condition core:odd-keywords (program-error) ((%called-function :initarg :called-function :reader called-function)) (:report (lambda (condition stream) - (format stream "Odd number of keyword arguments~:[~; for ~s~]." - (called-function condition) - (core:function-name (called-function condition)))))) + (let* ((function (called-function condition)) + (name (if (functionp function) + (core:function-name function) + function))) + (format stream "Odd number of keyword arguments~@[ for ~s~]." + name))))) (define-condition core:unrecognized-keyword-argument-error (program-error) ((called-function :initarg :called-function :reader called-function :initform nil) (unrecognized-keywords :initarg :unrecognized-keywords :reader unrecognized-keywords)) (:report (lambda (condition stream) - (format stream "Unrecognized keyword arguments ~S~:[~; for ~S~]." - (unrecognized-keywords condition) - (called-function condition) - (core:function-name (called-function condition)))))) + (let* ((function (called-function condition)) + (name (if (functionp function) + (core:function-name function) + function))) + (format stream "Unrecognized keyword arguments ~S~@[ for ~S~]." + (unrecognized-keywords condition) + name))))) (define-condition print-not-readable (error) ((object :INITARG :OBJECT :READER print-not-readable-object)) diff --git a/src/lisp/kernel/cmp/arguments.lisp b/src/lisp/kernel/cmp/arguments.lisp index f9d21ce3f1..29311ab323 100644 --- a/src/lisp/kernel/cmp/arguments.lisp +++ b/src/lisp/kernel/cmp/arguments.lisp @@ -236,8 +236,6 @@ a_p = a_p_temp; a = a_temp; (irc-cond-br evenp kw-loop odd-kw) ;; There have been an odd number of arguments, so signal an error. (irc-begin-block odd-kw) - (unless (calling-convention-closure calling-conv) - (error "The calling-conv ~s does not have a closure" calling-conv)) (irc-intrinsic "cc_oddKeywordException" (calling-convention-closure calling-conv)) (irc-unreachable)) diff --git a/src/llvmo/link_intrinsics.cc b/src/llvmo/link_intrinsics.cc index 2bf9f9c444..5ef1896f80 100644 --- a/src/llvmo/link_intrinsics.cc +++ b/src/llvmo/link_intrinsics.cc @@ -236,19 +236,10 @@ __attribute__((visibility("default"))) core::T_O* cc_gatherDynamicExtentRestArgu NO_UNWIND_END(); } -void badKeywordArgumentError(core::T_sp keyword, core::T_sp functionName, core::T_sp lambdaList) { - if (functionName.nilp()) { - SIMPLE_ERROR("When calling an unnamed function with the lambda list {} the bad keyword argument {} was passed", - _rep_(lambdaList), _rep_(keyword)); - } - SIMPLE_ERROR("When calling {} with the lambda-list {} the bad keyword argument {} was passed", _rep_(functionName), - _rep_(lambdaList), _rep_(keyword)); -} - void cc_ifBadKeywordArgumentException(core::T_O* allowOtherKeys, core::T_O* kw, core::T_O* tclosure) { - core::Function_sp closure((gc::Tagged)tclosure); + core::T_sp closure((gc::Tagged)tclosure); if (gctools::tagged_nilp(allowOtherKeys)) - badKeywordArgumentError(core::T_sp((gc::Tagged)kw), closure->functionName(), closure->lambdaList()); + throwUnrecognizedKeywordArgumentError(closure, core::T_sp((gc::Tagged)kw)); } }; diff --git a/src/llvmo/llvmoExpose.cc b/src/llvmo/llvmoExpose.cc index 477790f323..1fef917e60 100644 --- a/src/llvmo/llvmoExpose.cc +++ b/src/llvmo/llvmoExpose.cc @@ -3605,8 +3605,14 @@ CL_DEFUN core::T_sp FunctionType_O::get(llvm::Type* result_type, core::T_sp para return translate::to_object::convert(result); }; -// I can't get the following to work yet -// CL_EXTERN_DEFMETHOD(FunctionType_O, &llvm::FunctionType::getReturnType); +// Doesn't work. Clang complains it can't instantiate std::invoke: +// note: candidate template ignored: substitution failure [with _Callable = llvm::Type *(llvm::FunctionType::*)() const, _Args = ]: no type named 'type' in 'std::invoke_result' +// I don't know why we're giving it a Type rather than a FunctionType. +//CL_EXTERN_DEFMETHOD(FunctionType_O, &llvm::FunctionType::getReturnType); +CL_DEFUN core::T_sp llvm_sys__function_type_return_type(llvmo::FunctionType_sp ftype) { + llvm::FunctionType* fty = ftype->wrapped(); + return translate::to_object::convert(fty->getReturnType()); +} DOCGROUP(clasp); CL_DEFUN core::T_sp llvm_sys__function_type_param_types(llvmo::FunctionType_sp ftype) {