-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add COALTON:DEFINE-INLINE to define inline functions and methods #1029
base: main
Are you sure you want to change the base?
Conversation
I haven't reviewed but I just wanted to leave a few pre-comments.
Excited to see this. Inlining will be such a huge performance lever in Coalton that could transform it from being "inadequate" to being "faster than Lisp by default". |
Thank you for the pre-review! I'm still thinking what the right thing to do would be. But yes, I definitely want to see inlining in coalton. One main concern (EDIT: Fixed below using a node-let) I have with this approach is that it depends on the implementation to perform the inlining - see the following changes in src/codegen/program.lisp : (loop :for (name . node) :in bindings
:if (node-abstraction-p node)
:append (list
(if (node-abstraction-inline-p node)
`(declaim (inline ,name))
`(declaim (notinline ,name)))
(compile-function name node env)
`(setf
,name This means that suppose As I understand, avoiding this would require some more work, so that inlining can be performed within coalton compilation without depending on the implementation. |
We should definitely attempt to inline ourselves (at the AST level) so that further type and monomorphizer/specializer optimizations. Maybe in specific last-mile optimizations we would use the Lisp inliner. (I'm happy Lisp has inlining, but it's a very sharp and specific tool.) |
Hey, thanks for working on this. Wether a function is marked inline should be tracked in the I would prefer to use attributes instead of adding a new toplevel form:
The inliner should be written as a separate optimization pass instead of being merged with the Lastly, the inliner should generate fresh variable names instead of reusing the names of the functions's parameter names. This way we avoid issues with overlapping variable name. You can generate variable names with |
Thanks for the extensive feedback! I will rework this over the next week or two and push the commits for further review. Yes, now, I'm in favour of attributes over a new toplevel form. If a user wants, they can write a macro which expands into the attribute+form: (defmacro define-inline (name &body body)
`(progn
(inline)
(define ,name ,@body))) However, in the longer run, if we wish to provide more granular SBCL-like control over inlining, we might need something akin to declarations. (declaim (inline foo))
(defun foo (a)
(+ a a))
(declaim (notinline foo))
(defun foo-inline-caller (b)
(declare (inline foo))
(foo b))
(defun foo-mixed-caller (b)
(declare (inline foo))
(+ (foo b)
(locally (declare (notinline foo)) ; <------ Are coalton attributes suitable for this?
(foo b)))) |
It looks like creating a Without that, it seems we will need to change Let me know if I should proceed by adding a |
In every place (define-env-updater set-function-arity (env symbol arity)
(declare (type environment env)
(type symbol symbol)
(type fixnum arity))
(let ((prev (lookup-function env symbol :no-error t)))
(update-environment
env
:function-environment (immutable-map-set
(environment-function-environment env)
symbol
(make-function-env-entry
:name symbol
:arity arity
:inline-p (and prev (function-env-entry-inline-p prev)))
#'make-function-environment)))) |
Sorry, I've been busy. It's been great to see lots of activity on coalton recently! I might be free to dive into this in detail in another month. Is there any suggestion to break the changes required for this into multiple parts? That way, each part will be easier to review and merge. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey! Don't worry about breaking this up, it's pretty reviewable.
Sorry I dropped the ball on reviewing this.
This needs some tests, but other than that and a couple nits this looks good to merge.
(node-type node)) | ||
:value name) | ||
:rands rands))))))) | ||
;; FIXME: What kind of frontend code evokes DIRECT-APPLICATION |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pass turns regular calls into direct calls when it's known that regular function calls can be used.
(when (node-variable-p rator) | ||
(let* ((name (node-variable-value rator)) | ||
(code (tc:lookup-code env name :no-error t)) | ||
;; FIXME: We need to lookup inline-p in the environment rather than the AST |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this FIXME is done
|
||
(assert (cst:consp form)) | ||
|
||
;; TODO: Parsing errors |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO
@@ -358,7 +360,9 @@ | |||
:if (not (zerop method-arity)) | |||
:do (setf env (tc:set-function env method-name (tc:make-function-env-entry | |||
:name method-name | |||
:arity method-arity))) | |||
:arity method-arity | |||
;; FIXME: Always declare methods to be inline? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should do this
@@ -334,7 +334,9 @@ | |||
:if (not (zerop class-arity)) | |||
:do (setf env (tc:set-function env codegen-sym (tc:make-function-env-entry | |||
:name codegen-sym | |||
:arity class-arity))) | |||
:arity class-arity | |||
;; FIXME: Under what circumstances would we want fundep to be inline? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Class constructor functions can't be inlined by the Coalton inliner because they don't appear in the code env.
@@ -532,7 +529,9 @@ | |||
:vars nil | |||
:var-names nil | |||
:body (list (util:runtime-quote (type-definition-runtime-type type))))) | |||
:source source)) | |||
:source source | |||
;; FIXME: Is NIL correct? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
(body (util:required 'body) :type node-body :read-only t)) | ||
(params (util:required 'vars) :type pattern-list :read-only t) | ||
(body (util:required 'body) :type node-body :read-only t) | ||
(inline-p (util:required 'inline-p) :type boolean :read-only t)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is unnecessary because it's tracked in the function environment.
This PR is a sketch to add inlinable functions and methods to coalton.
The intended use is as follows:
Without
foo
beinginline
, the disassembly offoo-caller
would have included a call tofoo
as follows:But now that
foo
can beinline
d, the disassembly offoo-caller
is:This not only extends to regular functions, but also to class method instances. Effectively, this brings us inlinable static dispatch with zero runtime overhead for calling simple functions.
In an earlier PR, it was suggested that aI am adding it as an attribute for the moment instead of any separate toplevel form. If someone has a preference for a toplevel form, they can always write a macro. The case for converting it into a CL-like declaration for more granular control remains.coalton:inline
declaration may be added to define inline functions and methods. I felt a slight inclination towards acoalton:define-inline
form instead of acoalton:inline
declaration. Nonetheless, if a declaration seems better, I will attempt to modify the PR accordingly.This is still a sketch since I haven't looked over every case carefully. I'd be also be delighted if this facility could be achieved by more minimal changes.