do any targets use address space modifiers to implement "near" or "far" pointers?

I’m attempting to implement a clang/llvm prototype of mixed mode x86 and x86_64 code. My intent is to be able to generate “32-bit” code that emulates another 32bit platform (without porting that code to 64-bit or intel, so that all the pointer references in that code can still be 32-bit), and run that code in a thread that explicitly allocates stack in “low memory”. I’ve hacked enough of clang and llvm to make this work in a limited fashion, defining two address spaces:


(and following the x64 linux model in some places (but not all, like the x64 specific ELF format)).

I’m now able to generate 32-bit memory model code and execute it in a 32-bit process. Pointers and stack and data references are all 32-bit, but the code is able to use 64-bit registers (like the x64 memory model, but all in the same process).

Now, I’m trying to see what’s required to call out to 64-bit code from this “32-bit” code, and access that “high” memory range for calls to runtime infrastructure implemented 64-bit shared libraries. I see that I can define types (and indirectly pointers to those types) in my “far” address space:

typedef int a1int attribute( ( address_space( 1 ) ) );

The int * references in the IR do have the desired(1) address space, and generated code accessing a 32-bit pointer vs. a 64-bit pointer looks about right:

00000000000001c0 :

1c0: 55 push %rbp

1c1: 89 e5 mov %esp,%ebp

1c3: 89 7d fc mov %edi,-0x4(%rbp)

1c6: 8b 7d fc mov -0x4(%rbp),%edi

1c9: 67 8b 07 mov (%edi),%eax

1cc: 5d pop %rbp

1cd: c3 retq

1ce: 66 90 xchg %ax,%ax

00000000000001d0 :

1d0: 55 push %rbp

1d1: 89 e5 mov %esp,%ebp

1d3: 48 89 7d f8 mov %rdi,-0x8(%rbp)

1d7: 48 8b 7d f8 mov -0x8(%rbp),%rdi

1db: 8b 07 mov (%rdi),%eax

1dd: 5d pop %rbp

1de: c3 retq

With IR:

; Function Attrs: nounwind uwtable

define i32 @addr0(i32* %p) #0 {


%p.addr = alloca i32*, align 4

store i32* %p, i32** %p.addr, align 4

%0 = load i32*, i32** %p.addr, align 4

%1 = load i32, i32* %0, align 4

ret i32 %1


; Function Attrs: nounwind uwtable

define i32 @addr1(i32 addrspace(1)* %p) #0 {


%p.addr = alloca i32 addrspace(1)*, align 4

store i32 addrspace(1)* %p, i32 addrspace(1)** %p.addr, align 4

%0 = load i32 addrspace(1)*, i32 addrspace(1)** %p.addr, align 4

%1 = load i32, i32 addrspace(1)* %0, align 4

ret i32 %1


However, sizeof() for such a pointer is still 4.

I find address spaces used in some GPU and opencl code. Are there any targets that utilize address spaces to generate the equivalent of “near” or “far” pointers, where the address range of a “near” pointer is less than that of a “far” pointer? If so, I’d like to look at that code, to see if I can model what I’m trying on that.

sizeof(), as in the C sizeof() operator? You probably need to override TargetInfo::getPointerWidthV() and TargetInfo::getPointerAlignV() for your target. See clang/lib/Basic/Targets.cpp.