[LLVMdev] Address space extension
Michele Scandale
michele.scandale at gmail.com
Thu Aug 8 05:03:08 PDT 2013
On 08/08/2013 11:04 AM, David Chisnall wrote:
> What happens when I link together two IR modules from different front ends that have different language-specific address spaces?
I agree with Micah: if during the linking two IR modules there are
incoherences (e.g. in module1 2 -> 1 and in module2 2 -> 3) then the
modules are incompatible and the link process should fail.
> I would be very hesitant about using address spaces until we've fixed their semantics to disallow bitcasts between different address spaces and require an explicit address space cast. To illustrate the problem, consider the following trivial example:
>
> typedef __attribute__((address_space(256))) int* gsptr;
>
> int *toglobal(gsptr foo)
> {
> return (int*)foo;
> }
>
> int load(int *foo)
> {
> return *foo;
> }
>
> int loadgs(gsptr foo)
> {
> return *foo;
> }
>
> int loadgs2(gsptr foo)
> {
> return *toglobal(foo);
> }
>
> When we compile this to LLVM IR with clang (disabling asynchronous unwind tables for clarity), at -O2 we get this:
>
> define i32* @toglobal(i32 addrspace(256)* %foo) nounwind readnone ssp {
> %1 = bitcast i32 addrspace(256)* %foo to i32*
> ret i32* %1
> }
>
> define i32 @load(i32* nocapture %foo) nounwind readonly ssp {
> %1 = load i32* %foo, align 4, !tbaa !0
> ret i32 %1
> }
>
> define i32 @loadgs(i32 addrspace(256)* nocapture %foo) nounwind readonly ssp {
> %1 = load i32 addrspace(256)* %foo, align 4, !tbaa !0
> ret i32 %1
> }
>
> define i32 @loadgs2(i32 addrspace(256)* nocapture %foo) nounwind readonly ssp {
> %1 = bitcast i32 addrspace(256)* %foo to i32*
> %2 = load i32* %1, align 4, !tbaa !0
> ret i32 %2
> }
>
> Note that in loadgs2, the call to toglobal has been inlined and so the back end will just see a bitcast, which SelectionDAG treats as a no-op. The assembly we get from this is:
>
> _toglobal: ## @toglobal
> ## BB#0:
> pushq %rbp
> movq %rsp, %rbp
> movq %rdi, %rax
> popq %rbp
> ret
> load: ## @load
> ## BB#0:
> pushq %rbp
> movq %rsp, %rbp
> movl (%rdi), %eax
> popq %rbp
> ret
>
> .globl _loadgs
> .align 4, 0x90
> loadgs: ## @loadgs
> ## BB#0:
> pushq %rbp
> movq %rsp, %rbp
> movl %gs:(%rdi), %eax
> popq %rbp
> ret
>
> .globl _loadgs2
> .align 4, 0x90
> loadgs2: ## @loadgs2
> ## BB#0:
> pushq %rbp
> movq %rsp, %rbp
> movl (%rdi), %eax
> popq %rbp
> ret
>
> loadgs() has been compiled correctly. It uses the parameter as a gs-relative address and performs the load. The assembly for load() and loadgs2(), however, are identical: both are treating the parameter as a linear (not gs-relative) address. The cast has been lost. This is even simpler when you look at toglobal(), which has just become a noop. The correct code for this should be (I believe):
>
> _toglobal: ## @toglobal
> ## BB#0:
> pushq %rbp
> movq %rsp, %rbp
> lea %gs:(%rdi), %rax
> popq %rbp
> ret
>
> In the inlined version, the lea and movl should be combined into a single gs-relativel movl.
>
> Until we can generate correct code from IR containing address spaces, discussion of how to optimise this IR seems premature.
I've done a quick test: the problem is that the BITCAST node is not
generated during the SelectionDAG building. If you look in
SelectionDAGBuilder::visitBitCast, you will see that the node is
generated only if the operand value of the bitcast operation and the
result value have different EVTs: the address space information is not
handled in EVT and so pointers in different address spaces are mapped to
the same EVT that imply a missing BITCAST node.
Maybe rethinking the way address spaces are handled at the interface
between middle-end and backend would allow to fix also these kind of
problems. BTW, I think this specific problem can be used for a bug
report :-).
Thanks.
-Michele
More information about the llvm-dev
mailing list