Preserve address spaces of global objects while generating 'atexit' stub.
Details
Diff Detail
- Repository
- rL LLVM
Event Timeline
lib/CodeGen/CGDeclCXX.cpp | ||
---|---|---|
132 ↗ | (On Diff #201293) | Should this code be conditional to OpenCL? And why does _cxa_atexit take a __global pointer instead of, say, a __generic one? |
lib/CodeGen/CGDeclCXX.cpp | ||
---|---|---|
132 ↗ | (On Diff #201293) | The only objects that are destructible globally in OpenCL are __global and __constant. However __constant isn't convertible to __generic. Therefore, I am adding __global directly to avoid extra conversion. I am not yet sure how to handle __constantthough and how much destructing objects in read-only memory segments would make sense anyway. I think I will address this separately. |
lib/CodeGen/CGDeclCXX.cpp | ||
---|---|---|
132 ↗ | (On Diff #201293) | The pointer argument to __cxa_atexit is just an arbitrary bit of context and doesn't have to actually be the address of a global. It's *convenient* to use the address of a global sometimes; e.g. you can use the global as the pointer and its destructor as the function, and then __cxa_atexit will just call the destructor for you without any additional code. But as far as the runtime is concerned, the pointer could be malloc'ed or something; we've never had a need to do that in the ABI, but it's good future-proofing to allow it. So there are three ways to get a global destructor to destroy a variable in __constant:
Obviously you should go with the one of the first two, but you should make sure your ABI doesn't preclude doing the latter in case it's useful for some future language feature. In other words, it doesn't really matter whether this argument is notionally in __global as long as that's wide enough to pass a more-or-less arbitrary pointer through. |
lib/CodeGen/CGDeclCXX.cpp | ||
---|---|---|
132 ↗ | (On Diff #201293) | Ok, I see. I guess option 1 would be fine since we can't setup pointer width per address space in clang currently. However, spec doesn't provide any clarifications in this regard. So I guess using either __global or __generic for the pointer parameter would be fine... Or perhaps even leave it without any address space (i.e. _`_private`) and just addrspacecast from either __global or __constant. Do you have any preferences? As for malloc I am not sure that will work for OpenCL since we don't allow mem allocation on the device. Unless you mean the memory is allocated on a host... then I am not sure how it should work. |
lib/CodeGen/CGDeclCXX.cpp | ||
---|---|---|
132 ↗ | (On Diff #201293) |
Really? What's missing there? It looks to me like getPointerSize does take an address space.
__private is likely to be a smaller address space, right? I would recommend using the fattest pointer that you want to actually support at runtime — you shouldn't go all the way to __generic if the target relies on eliminating that statically. If you want a target hook for the address space of the notional __cxa_atexit_context_pointer typedef, I think that would be reasonable.
Well, maybe not actually heap-allocated. I just think you should design the ABI so that it's reasonably future-proof against taking any specific sort of reasonable pointer. |
lib/CodeGen/TargetInfo.h | ||
---|---|---|
274 ↗ | (On Diff #207574) | This target hook should just return the address space of the __cxa_atexit argument, not to claim anything specific about the relation between that address space and others. That is a global and permanent property of the target ABI. We should *advise* targets to use an address space that other major address spaces can be bitcast to, but ultimately that's just advisory. This would be a good thing to include in a PR to the Itanium C++ ABI, but it would be reasonable to bundle all the address-space-related changes you need in one PR. |
lib/CodeGen/TargetInfo.h | ||
---|---|---|
274 ↗ | (On Diff #207574) |
I can try to do it but I would need some explanation of the process. :) |
lib/CodeGen/CGDeclCXX.cpp | ||
---|---|---|
132 ↗ | (On Diff #201293) | This cast only works if the address space is a subspace of the __cxa_atexit address space, right? Should we be checking that and emitting a diagnostic if that's not true? I think an IRGen-level diagnostic is fine here. |
lib/CodeGen/CGDeclCXX.cpp | ||
---|---|---|
132 ↗ | (On Diff #201293) | Then it would fail to compile for __constant.
Do you think I should leave a bitcast then? Not sure if something might assert in LLVM though if there is a bitcast between pointers to different address space... so I am confused... |
lib/CodeGen/CGDeclCXX.cpp | ||
---|---|---|
132 ↗ | (On Diff #201293) | I think LLVM doesn't allow direct bitcasts between different address spaces (to help eliminate obvious bugs), but you can do it with ptrtoint. For generality, though, you should emit a diagnostic if the __cxa_atexit pointer size is actually smaller than the target pointer. Alternatively, I'm not sure we actually rely on this pointer for anything right now, so you might be able to just use null if the address spaces are different. That decision will eventually need to be able to affect how we generate the global destructor function, though. |
lib/CodeGen/CGDeclCXX.cpp | ||
---|---|---|
132 ↗ | (On Diff #201293) | Thanks! I will go for NULL for now to prevent ICE and unblock some further work. But I added a FIXME to make sure to come back to this. I would then either change the dtor generation of emit some meaningful non-NULL value as an argument. |
If you're interested in working on this, great. I actually think there's zero reason to emit a non-null argument here on any target unless we're going to use the destructor as the function pointer — but we can do that on every Itanium target, so we should. So where we want to be is probably:
- use the complete-object destructor and the object pointer as its argument when destroying a (non-array) object of C++ class type
- otherwise use a custom function that materializes the object pointer on its own and uses a null pointer as the argument
And then the address-spaces tweak to that is that we use the second option when we either (1) the destructor isn't in the __cxa_atexit address space or (2) the object pointer can't be converted to that address space.