llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.58k stars 11.81k forks source link

[OpaquePointers] ElementType only legal on intrinsics and inline asm #64459

Open wsmoses opened 1 year ago

wsmoses commented 1 year ago

@nikic

I'm trying to adapt some Julia + Enzyme (autodiff) code to opaque pointers and hitting an issue.

For a given differentiable argument, we'll duplicate that argument. If that argument is an sret that means there are now two "sret"-like arguments (sret have special semantics for julia's GC). Obviously two arguments marked sret is invalid. Therefore in a non-opaque pointer land I just added a special "enzyme_sret" string attribute, and all was well.

Unfortunately, this of course loses the inner sret type which presents issues when using Opaque pointers (Julia is only experimenting with that now). As string attributes (since Enzyme is presently out of tree) do not permit type arguments, I looked to preserve the type in a different way. To remedy this I tried using an elementtype attribute at that location. However, unfortunately I hit the issue that " Attribute 'elementtype' can only be applied to intrinsics and inline asm".

What would you recommend here to support opaque pointers in this context.

cc @vchuravy

llvmbot commented 1 year ago

@llvm/issue-subscribers-julialang

nikic commented 1 year ago

Can you please clarify what you actually need the type for? Do you really need it, or do you just need some type properties (like the size or alignment)?

If you just need the type to later lower to sret or so, we can probably drop the sret type argument entirely. I don't think sret actually needs the type, it's a historical leftover.

wsmoses commented 1 year ago

Please forgive my partial Julia internals knowledge, as I'm coming about this from the Enzyme AD side, but helping the Julia bindings for. @vchuravy and co please correct any incorrect Julia info.

Julia uses sret for garbage collection. In particular it looks at the elements of the type, and any inner pointers of address space 10 will be used by Julia's LLVM passes for garbage collection.

E.g. a type of { i64, {} addrspace(10)*, [2 x {} addrspace(10)*] } inside an sret will have the 1st struct element, and the two elements of the array used in garbage collection.

This is determined by descending into the type definition in the sret.

In our (Enzyme differentiation) case, when acting on Julia code, since we need to duplicate the original arguments to have a differentiable shadow, we need to preserve what original type was used for its garbage collection. This is where I earlier attempted to use the elementtype attribute. This is necessary for us to restore the Julia GC ABI via an sret (and potential extra rooted arg) in a postprocessing rewriting.

wsmoses commented 1 year ago

bumping this, since I believe having a type attribute to preserve information will be required for Julia to move to opaque pointers here

wsmoses commented 1 year ago

bumping also cc'ing @gbaraldi