<div dir="ltr">Hi Paulo,<div><br></div><div>I believe the motivation for having the global reside in address space 1 was to prevent its address from being bitcast to an integer. Any non-integral address space would work for that, though; it doesn't have to be the same address space as the externref itself. If we can't enforce the use of a non-integral address space for the globals, though, (i.e. we can't prevent folks from having an externref global in address space 0 anyway) then perhaps it doesn't matter and we can just use address space 0 and error out on bitcasts somewhere in the backend rather than at the LLVM IR level.</div><div><br></div><div>Thomas</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Feb 5, 2021 at 5:48 AM Paulo Matos <<a href="mailto:pmatos@igalia.com">pmatos@igalia.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
Thomas Lively via llvm-dev writes:<br>
<br>
> Paulo,<br>
><br>
> It looks like you need to have WebAssemblyTargetLowering override the<br>
> `getPointerTy` method to return MVT::externref when the address space is 1.<br>
> From my brief local experiments, it also looks like you will have to fix up<br>
> a bunch of places where having loads and stores produce and<br>
> use externrefs violate various assumptions. `getPointerTy` only gets the<br>
> data layout string and the address space as arguments, so we will have to<br>
> figure out how best to differentiate between externref and funcref at some<br>
> point. Using separate address spaces would be the simplest solution, but I<br>
> haven't thought through whether there would be any downsides to that.<br>
<br>
Hi Thomas,<br>
<br>
Thanks for the comments on this. I have followed up on this idea of<br>
overriding getPointerTy. I have also looked at David's backend. I think<br>
the largest different between reference types and the CHERI backend fat<br>
pointers is that fat pointers are not 0-size, while reference types are.<br>
<br>
So, I did go through all the bits and pieces of the optimizations to<br>
ensure that after returning MVT::externref (leaving aside funcref for<br>
now) for pointers in address 1, we do not attempt to optimize<br>
load/stores of zero bits.<br>
<br>
There's an issue that, in hindsight, I should have seen coming. I am<br>
storing in address space 1, not only the reference type itself:<br>
%extern = type opaque;<br>
%externref = type %extern addrspace(1)*;<br>
<br>
but also the global to which we store the externref.<br>
The global definition looks like:<br>
@externref_global = local_unnamed_addr addrspace(1) global %externref undef<br>
<br>
Which means that getPointerTy, which doesn't get the Node, but just the<br>
address space, will return MVT::externref for the type of<br>
@externref_global which is incorrect.<br>
<br>
While thinking about it, I cannot remember the reasoning for having the<br>
externref_global also in addrspace(1) alongside externrefs. If there's<br>
no good reason to do so, I could probably keep it in the default address<br>
space and define it instead as <br>
@externref_global = local_unnamed_addr global %externref undef<br>
<br>
Do you have any opinions on this?<br>
<br>
Paulo<br>
<br>
><br>
> Thomas<br>
><br>
> On Wed, Jan 27, 2021 at 6:48 AM David Chisnall via llvm-dev <<br>
> <a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a>> wrote:<br>
><br>
>> Hi Paulo,<br>
>><br>
>> In the CHERI port of LLVM, we have added a bunch of fat pointer MVT<br>
>> types (iFATPTR64, iFATPTR128, and so on) and lower CHERI capabilities<br>
>> (which, in the IR, we represent as pointers with address space 200) to<br>
>> them in the relevant back ends (MIPS / RISC-V / AArch64).  We also add<br>
>> explicit PTRADD DAG nodes for pointer arithmetic (GEP lowering)<br>
>><br>
>> We can load and store an iFATPTR{width} via a normal load and store,<br>
>> just as we can any other type.<br>
>><br>
>> Would this address your use case?<br>
>><br>
>> David<br>
>><br>
>><br>
>> On 27/01/2021 13:21, Paulo Matos via llvm-dev wrote:<br>
>> ><br>
>> > Hi all,<br>
>> ><br>
>> > Through my work on implementing the reference types WebAssembly proposal<br>
>> > in LLVM IR, I have hit a blocker and would be keen to have suggestions<br>
>> > on how to proceed or similar cases from which to draw inspiration. The<br>
>> > current WIP patch is at <a href="https://reviews.llvm.org/D95425" rel="noreferrer" target="_blank">https://reviews.llvm.org/D95425</a><br>
>> ><br>
>> > The current design to represent the externref type is to use LLVM type<br>
>> > opaque in address space 1. Therefore an externref looks like:<br>
>> ><br>
>> > %extern = type opaque<br>
>> > %externref = type %extern addrspace(1)* ;; addrspace 1 is nonintegral<br>
>> ><br>
>> > To represent storing and loading of externref from globals, we use store<br>
>> > and load from LLVM globals. So, a store of externref would look like:<br>
>> ><br>
>> > @externref_global = local_unnamed_addr addrspace(1) global %externref<br>
>> undef<br>
>> > define void @set_externref_global(%externref %g) {<br>
>> >    ;; this generates a global.set of @externref.global<br>
>> >    store %externref %g, %externref addrspace(1)* @externref_global<br>
>> >    ret void<br>
>> > }<br>
>> ><br>
>> > What's currently happening is that we lower the store into a new DAG<br>
>> > node GLOBAL_SET and then pattern match it into a GLOBAL_SET_EXTERNREF<br>
>> > that generates the proper global.set Wasm instruction.<br>
>> ><br>
>> > // Global SET<br>
>> > def wasm_global_set_t : SDTypeProfile<0, 2, [SDTCisPtrTy<1>]>;<br>
>> > def wasm_global_set : SDNode<"WebAssemblyISD::GLOBAL_SET",<br>
>> wasm_global_set_t,<br>
>> >                          [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>;<br>
>> > def : Pat<(wasm_global_set externref:$v, (WebAssemblywrapper<br>
>> tglobaladdr:$addr)),<br>
>> >            (GLOBAL_SET_EXTERNREF global_op:$addr, EXTERNREF:$v)>,<br>
>> >        Requires<[HasReferenceTypes]>;<br>
>> ><br>
>> > The problem I am finding is that the pattern matcher is not being able<br>
>> > to match the new node with (wasm_global_set externref:$v,<br>
>> > (WebAssemblywrapper tglobaladdr:$addr))<br>
>> ><br>
>> > Further analysis shows that the problem is in matching externref:$v.<br>
>> ><br>
>> > The issue is that in IR, $v has type opaque addrspace(1)*, but the MVT<br>
>> > we re trying to match it to is externref. Initially I assumed, we could<br>
>> > somehow lower the type and instruct LLVM to lower all type opaque<br>
>> > addrspace(1)* to MVT::externref but I was not able to achieve that. I<br>
>> > welcome any suggestions/comments on the approach and ways to proceed.<br>
>> ><br>
>> > Regards,<br>
>> ><br>
>> _______________________________________________<br>
>> LLVM Developers mailing list<br>
>> <a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a><br>
>> <a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br>
>><br>
> _______________________________________________<br>
> LLVM Developers mailing list<br>
> <a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a><br>
> <a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br>
<br>
<br>
-- <br>
Paulo Matos<br>
</blockquote></div>