-
Notifications
You must be signed in to change notification settings - Fork 70
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 INLINE syntax #1290
base: main
Are you sure you want to change the base?
Add INLINE syntax #1290
Conversation
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.
Mostly nits
src/codegen/optimizer.lisp
Outdated
@@ -421,8 +424,10 @@ requires direct constructor calls." | |||
(alexandria:when-let* | |||
((name (node-rator-name node)) | |||
(code (tc:lookup-code env name :no-error t)) | |||
(fun-env-entry (tc:lookup-function env name :no-error t)) | |||
(inline-p (when fun-env-entry (tc:function-env-entry-inline-p fun-env-entry))) |
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.
when
not needed here. If fun-env-entry
is nil
, the the whole when-let*
form will be nil
and the form bound to inline-p
will never be evaluated.
src/codegen/optimizer.lisp
Outdated
(_ (and (node-abstraction-p code) | ||
(funcall heuristic code) | ||
(or inline-p (funcall heuristic code)) |
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.
Similarly, inline-p
will always be non-nil at this point if this code is evaluated at all.
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.
Would it make sense to rewrite this condition as the following?
(fun-env-entry (tc:lookup-function env name :no-error t))
(_ (and (node-abstraction-p code)
(or (tc:function-env-entry-inline-p fun-env-entry)
(funcall heuristic code))
(<= (length call-stack)
max-depth)
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.
Yeah, I think that is a good way to rewrite it so that it will work with the when-let*
.
The only thing I'm unsure of is if there ever can be a case when there is an entry in the code-environment
but not in the function-environment
. (I can't tell easily just from looking at the code, since the code entries and function entries are added at very different places in the code.) If so, then in order to allow heuristic inlining of functions with code env entries but not function env entries, it seems like a separate let statement might be necessary, like
(_ (and (node-abstraction-p code)
(or (alexandria:when-let (fun-env-entry (tc:lookup-function env name :no-error t))
(tc:function-env-entry-inline-p fun-env-entry))
(funcall heuristic code))
(<= (length call-stack)
max-depth)
or if not, then your suggestion should work exactly as written, or even without the :no-error 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.
If I remove :no-error t
in my suggestion, I obtain the error "Internal coalton bug: Unknown function TREE:INCREASING-ORDER" while compiling library/ord-map.lisp
. So, there indeed seem to be cases with code env entries but not function env entries.
However, I note that your suggestion works even without the :no-error t
. My hypothesis is there are fun-env-entries only when code is an abstraction node.
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.
In fact, in those cases, code
is an application node.
(fun-env-entry (let ((fun-env-entry (tc:lookup-function env name :no-error t)))
(unless fun-env-entry (print (type-of code)))
fun-env-entry))
(_ (and (node-abstraction-p code)
(or (tc:function-env-entry-inline-p fun-env-entry)
(funcall heuristic code))
With the above code, I obtain COALTON-IMPL/CODEGEN/AST:NODE-APPLICATION
as print statements while compiling library/ord-map.lisp
and library/seq.lisp
.
I'm inclined to commit your suggestion without :no-error t
to better understand internal behavior. :no-error t
feels like a hack here and I think it would rather be used as such.
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.
Committed in 849af1f
nil) | ||
|
||
((coalton:define) | ||
(let ((define (parse-define form source)) | ||
monomorphize | ||
monomorphize-form) | ||
monomorphize-form | ||
|
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.
nit: superfluous newline
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.
Is there a preference for the newlines under the (coalton:declare)
clause below? Should I remove them?
(setf (instance-method-definition-inline-p method) inline-p)) | ||
(setq forms (cst:rest forms)) | ||
method)))) | ||
|
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.
:for inline-p := (and (should-inline-p forms)
(prog1 (parse-inline (cst:first forms) source)
(setf forms (cst:rest forms))))
:for method := (parse-instance-method-definition (cst:first forms) (cst:second form) source)
:when inline-p :do (setf (instance-method-definition-inline-p method) inline-p)
:collect :method
:do (setf forms (cst:rest forms))
nit: this seems easier to follow to me. managing the state of forms
is a little confusing to follow, I think something like the above makes it clearer.
In something like the above, error signalling would be moved into parse-inline
. The should-inline-p
wouldn't need to exist, I just hate writing code in github comment boxes so I replaced the check with that.
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.
nit: this seems easier to follow to me. managing the state of forms is a little confusing to follow, I think something like the above makes it clearer.
Unless I'm missing something, the suggested code still manually manipulates the state of forms
. But I understand, this part of the code is a bit complicated to follow.
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.
that's correct. It's just a nit. Changes are not necessary
This is a general comment, probably for future work. As the optimizer gets more sophisticated, there'll be more context like |
"(inline) | ||
(define (factorial-1 n) | ||
(if (== n 0) | ||
1 | ||
(* n (factorial-2 (- n 1))))) | ||
(inline) | ||
(define (factorial-2 n) | ||
(if (== n 0) | ||
1 | ||
(* n (factorial-1 (- n 1)))))")) |
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 know what style guidelines we have for multi-line strings, but removing some indents here might make it nicer to read:
"(inline) | |
(define (factorial-1 n) | |
(if (== n 0) | |
1 | |
(* n (factorial-2 (- n 1))))) | |
(inline) | |
(define (factorial-2 n) | |
(if (== n 0) | |
1 | |
(* n (factorial-1 (- n 1)))))")) | |
"(inline) | |
(define (factorial-1 n) | |
(if (== n 0) | |
1 | |
(* n (factorial-2 (- n 1))))) | |
(inline) | |
(define (factorial-2 n) | |
(if (== n 0) | |
1 | |
(* n (factorial-1 (- n 1)))))")) |
(deftest function-inline-error () | ||
(signals coalton-impl/parser:parse-error | ||
(check-coalton-types | ||
"(inline myfun) | ||
(define (myfun x) x)"))) | ||
|
||
(deftest method-inline-error () | ||
(signals coalton-impl/parser:parse-error | ||
(check-coalton-types | ||
"(define-class (C :a) | ||
(m (:a -> :a -> :a))) | ||
(define-instance (m Double-Float) | ||
(inline m) | ||
(define (m x y) | ||
(lisp Double-Float (x y) (cl:+ x y))))"))) |
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.
You could add another test for duplicate inline attributes to match the tests for monomorphize
( https://github.com/search?q=repo%3Acoalton-lang%2Fcoalton+monomorphize+path%3A%2F%5Etests%5C%2Ftest-files%5C%2F%2F&type=code ) but other than that I think this looks pretty good and complete
The final PR towards adding inlining support in coalton. The earlier ones include:
This PR adds support for
(inline)
syntax in (i) coalton toplevel (ii) inside define-instance before methods. See the filetests/inliner-tests.lisp
for a number of examples.Particular aspects I can think of reviewing in this PR include:
inline
toinline-p
at some placesBut yes, let's address any other worries or issues others spot!