-
Notifications
You must be signed in to change notification settings - Fork 955
transform: PtrToInt and IntToPtr do not escape #4889
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
base: dev
Are you sure you want to change the base?
Conversation
In Each of such cases potentially unnecessarily allocates. |
From a conservation on Slack: I think we need a bit more; for example if you have a pointer conversion between two pointer types, we want to make sure the first one "escapes" if the second pointer "escapes" too. |
As far as I can read the NRF code In other words, I can't see how this optimization can be done even with perfect tracking of the As a side note, I believe code such as the NRF |
Agreed. The value does escape here. We could possibly do something tricky like telling the compiler "please keep the value alive until this point (after the DMA transfer completed), but don't consider this pointer escaped". That would be correct, and also avoid the heap allocation. But I'm not entirely sure how to do that - perhaps some tricks with inline assembly can be used. EDIT: actually, |
Isn't that what |
Pedantically, |
No, that's to avoid moving the object (which doesn't currently happen and realistically is unlikely to happen in the future). A quick look at |
Well you are technically correct. Do note that
In TinyGo, I think it is unlikely we'll ever have a moving garbage collector that would require pinning. Not just because of DMA, but also because it means interrupts can't run while the GC moves the heap. |
I've seen this comment before, but I'd like to say I find the current garbage collector too unreliable for dynamic allocation because of memory fragmentation. I frequently run into out-of-memory issues before even half of available memory (512kB) has been filled because of fragmentation. Coupled with the escape analyzer missing key allocations I find myself spending significant effort (and API contortions) to avoid allocations altogether. I don't see any other way of fixing fragmentation and making the GC reliable than making it moving. |
DMA code as well as interrupts can mark objects pinned, no? I realize this is not done today, but I don't see a fundamental reason that's impossible. |
This hints compiler that constructs like
uintptr(unsafe.Pointer(&x))
do not escape. Handled byllvm.PtrToInt
case.(I've also added
llvm.IntToPtr
, for completeness, but I'm not sure what code matches it. Feel free to reject.)Disclaimer
This change may very well be completely wrong; can such constructs escape?
Hence a draft, merely a conversation starter.
Context
I2C implementations on RP2040 and NRF52 behave differently regarding allocation behavior.
NRF52 implementation escapes to heap while RP2040 does not.
The issue was tracked down to lines 52 and 61 of this file: https://github.com/tinygo-org/tinygo/blob/release/src/machine/machine_nrf528xx.go
Reproducer
And this does not escape at all
After this change both do not escape anymore.I was over-optimistic and probably tired, it still escapes in NRF52 case, but I don't understand why.
Thanks @dgryski for pointing at
allocs.go