-
Notifications
You must be signed in to change notification settings - Fork 9
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
Added support for compiling functions inline #69
base: master
Are you sure you want to change the base?
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.
Would it make more sense to have a builtin @inline
decorator that can be applied on a function-by-function basis, instead of a global switch?
Co-authored-by: Lonami <[email protected]>
Actually, yes, that's a great idea. I like that. I'll work on adding that instead. |
I'm not sure. I tend to prefer not having features we're not using. If you have any use cases in mind for the near future, sure. Otherwise I'd be inclined to remove it, as it also looks kind of funny in the tests, with all the kwargs and inspect usage. |
Fair. I was thinking for specifying functions to run at the end instead of using a stack pointer in a memory block, but we could just use function decorators for that as well. |
This is an optimization to avoid needing the
That's something else. This is needed to know where to return to. I don't think it's something we can remove. As soon as a function can call another function, you need a list of positions to return to. A single variable won't do, and sadly we can't refer to variables by a dynamic name. This can be removed for function parameters, as long as they are not recursive. But then again, I think this would be another decorator and not a global switch (perhaps assume functions don't recurse, and opt-in via
Do you mean different optimizer levels? I don't think pyndustric would reach the level of maturity where this matters. Even then, optimizing for size is probably the right call in most circumstances, again due to the game's limit.
I could see a flag to make the compiler fail if it can't produce code without having a stack available (because in some cases it does need one). But, the user can also just see if the output contains cell, so I don't know. Sadly in the order PRs are being merged this one has conflicts now. Please open or mark others as draft, if you'd prefer I don't merge those yet. |
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 guess you're right. I just keep thinking of the C++ compiler, and how many hundreds of command line parameters it has. I guess I can remove it, we can always just re-add it if it becomes relevant later.
@@ -172,6 +172,8 @@ print(Mem.cell1[63]) | |||
|
|||
> **Note**: if you are using function calls, *pyndustric* will use `cell1` as a call stack, so you might not want to use `cell1` in that case to store data in it. (If you aren't calling any functions in your code, using `cell1` should be fine.) | |||
|
|||
> Alternatively, you can mark your functions with the `@inline` decorator, and it will compile them *inline*, so the function code gets copied to each function call. It will make it less efficient, but allows you to not need a separate memory cell. |
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.
Since there's still conflicts to resolve, I'll nitpick more.
It will make it less efficient
As with many things development, this is all about tradeoffs. If it was a function extracted to make some code easier to read, but is actually only used once, it will save quite a bit of overhead. But as soon as it's used multiple times, it could quickly bloat code size indeed.
> Alternatively, you can mark your functions with the `@inline` decorator, and it will compile them *inline*, so the function code gets copied to each function call. It will make it less efficient, but allows you to not need a separate memory cell. | |
> Alternatively, you can mark your functions with the `@inline` decorator, and it will compile them *inline*, so the function code gets copied to each function call. This is faster and means you don't need a memory cell, but if the function is used more than once, it will quickly bloat the generated code size. |
@@ -613,3 +613,6 @@ def sleep(secs: float): | |||
""" | |||
Sleep for the given amount of seconds. | |||
""" | |||
|
|||
def inline(func: Callable[..., Any]) -> Callable[..., Any]: |
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.
Wonder if we should use a TypeVar
so that editors know that the returned function matches the input exactly. Or perhaps this works as it is? Haven't use Callable
that much.
"inline" coming from the C++ keyword that does the same thing