Thread overview
[dmd-internals] Help with dl_* functions in DMD
Dec 20, 2015
Jacob Carlborg
Dec 27, 2015
Martin Nowak
Dec 28, 2015
Jacob Carlborg
Dec 28, 2015
Daniel Murphy
Dec 29, 2015
Martin Nowak
Dec 29, 2015
Jacob Carlborg
December 20, 2015
I’m trying to generate code using the dl_* functions in DMD. The corresponding D code would be the following:

struct TLS
{
    int* function (TLS*) thunk;
    size_t key;
    size_t offset;
}

extern (C) __gshared TLS bar;

extern (C) int main (int i, char**)
{
    auto foo = *bar.thunk(&bar);

    return 0;
}

The code that DMD is generating, for the above “main” functions, is:

pushq	%rbp
movq	%rsp, %rbp
movq	_bar(%rip), %rdi
movq	%rdi, %rax
callq		*_main(%rax)
movl	_main(%rax), %ecx
xorl		%eax, %eax
popq	%rbp
retq

What I’ve got so far is the following code below, instead of [1]:

switch (op * 2 + x)
{
    case OPvar * 2 + 1:
        e = el_una(OPind, TYnptr, e);
        e = el_una(OPind, TYnptr, e);
        break;
    case OPvar * 2 + 0:
    case OPrelconst * 2 + 1:
        e = el_una(OPind, TYnptr, e);
        break;
    case OPrelconst * 2 + 0:
        break;
    default:
        assert(0);
        break;
}

e = el_una(OPaddr, TYnptr, e);
e = doptelem(e, GOALvalue | GOALflags);
e = el_una(OPind, TYnptr, e);
e = el_bin(OPcallns, TYnptr, e, e);
e = el_una(OPind, TYnptr, e);

With the above code DMD and for this example:

extern (C) int main (int i, char**)
{
    auto foo = bar;
    return 0;
}

DMD generates the following:

pushq	%rbp
movq	%rsp, %rbp
movq	_bar(%rip), %rax
movq	_main(%rax), %rdi
callq		*_bar(%rip)
movl	_main(%rax), %ecx
xorl		%eax, %eax
popq	%rbp
retq

Basically I have no idea what I’m doing and I don’t really understand how these el_* functions are working. Anyone could give me some help with this?

[1] https://github.com/D-Programming-Language/dmd/blob/master/src/backend/el.c#L1259-L1263

-- 
/Jacob Carlborg


_______________________________________________
dmd-internals mailing list
dmd-internals@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-internals
December 27, 2015
On 12/20/2015 09:11 PM, Jacob Carlborg via dmd-internals wrote:
> I’m trying to generate code using the dl_* functions in DMD. The corresponding D code would be the following:
> 
> struct TLS
> {
>     int* function (TLS*) thunk;
>     size_t key;
>     size_t offset;
> }
> 
> extern (C) __gshared TLS bar;
> 
> extern (C) int main (int i, char**)
> {
>     auto foo = *bar.thunk(&bar);
> 
>     return 0;
> }
> 
> The code that DMD is generating, for the above “main” functions, is:
> 
> pushq	%rbp
> movq	%rsp, %rbp
> movq	_bar(%rip), %rdi
> movq	%rdi, %rax
> callq		*_main(%rax)
> movl	_main(%rax), %ecx
> xorl		%eax, %eax
> popq	%rbp
> retq

What do you want to achieve? In general specific instructions such as
for TLS access should be implemented by the corresponding cd* function,
not in the intermediate representation.
The IR might be the right place for a low-level lowering though.

> Basically I have no idea what I’m doing and I don’t really understand how these el_* functions are working. Anyone could give me some help with this?

The simply construct an IR tree, no magic here.

OPind  (dereference a pointer)
OPadd  (+ int or pointer)
OPaddr (& take an address)
OPconst (a constant value)
OPcallns (call a function)

You can find the documentation here. https://github.com/D-Programming-Language/dmd/blob/fc9edc34c7d7403b8c69b49abfe4c5ec2ae66061/src/backend/oper.h#L22



December 28, 2015
> On 27 dec 2015, at 22:33, Martin Nowak via dmd-internals <dmd-internals@puremagic.com> wrote:
> 
> What do you want to achieve?

My overall goal is to implement native TLS on OS X in DMD. For this particular question I was trying to figure out how to get DMD to generate same assembly as the corresponding D code, when a TLS variable is accessed, using the el_* functions.

auto foo = *bar.thunk(&bar);

> In general specific instructions such as
> for TLS access should be implemented by the corresponding cd* function,
> not in the intermediate representation.
> The IR might be the right place for a low-level lowering though.

It looks like the lowering for a TLS variable access to a call to ___tls_get_addr occurs in el_picvar for OS X.

> The simply construct an IR tree, no magic here.


You make it sound so easy :). I guess my main problem is that I’m reading the assembly that Clang outputs then I have no idea how to get DMD to generate the same assembly.

Anyway, I think I managed to figure it out, this seems to work [1]. I basically traced all the el_* functions to see which were called and with what arguments when I compiled D code looking something like "auto foo = *bar.thunk(&bar);”.

[1] https://github.com/jacob-carlborg/dmd/commit/49ecd3ff7861e2eb5838e2b2cd14b18f7fe2e07b

-- 
/Jacob Carlborg

December 29, 2015
Debug DMD's secret '--b' switch will helpfully print out the elem tree for every function that reaches the backend, if you want to avoid manually tracing through e2ir.

On Mon, Dec 28, 2015 at 11:29 PM, Jacob Carlborg via dmd-internals <dmd-internals@puremagic.com> wrote:
> On 27 dec 2015, at 22:33, Martin Nowak via dmd-internals <dmd-internals@puremagic.com> wrote:
>
> What do you want to achieve?
>
>
> My overall goal is to implement native TLS on OS X in DMD. For this particular question I was trying to figure out how to get DMD to generate same assembly as the corresponding D code, when a TLS variable is accessed, using the el_* functions.
>
> auto foo = *bar.thunk(&bar);
>
> In general specific instructions such as
> for TLS access should be implemented by the corresponding cd* function,
> not in the intermediate representation.
> The IR might be the right place for a low-level lowering though.
>
>
> It looks like the lowering for a TLS variable access to a call to ___tls_get_addr occurs in el_picvar for OS X.
>
> The simply construct an IR tree, no magic here.
>
>
> You make it sound so easy :). I guess my main problem is that I’m reading the assembly that Clang outputs then I have no idea how to get DMD to generate the same assembly.
>
> Anyway, I think I managed to figure it out, this seems to work [1]. I basically traced all the el_* functions to see which were called and with what arguments when I compiled D code looking something like "auto foo = *bar.thunk(&bar);”.
>
> [1] https://github.com/jacob-carlborg/dmd/commit/49ecd3ff7861e2eb5838e2b2cd14b18f7fe2e07b
>
> --
> /Jacob Carlborg
>
> _______________________________________________
> dmd-internals mailing list
> dmd-internals@puremagic.com
> http://lists.puremagic.com/mailman/listinfo/dmd-internals

_______________________________________________
dmd-internals mailing list
dmd-internals@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-internals
December 29, 2015
On Monday, 28 December 2015 at 12:29:41 UTC, Jacob Carlborg wrote:
>> On 27 dec 2015, at 22:33, Martin Nowak via dmd-internals <dmd-internals@puremagic.com> wrote:
>> 
>> What do you want to achieve?
>
> My overall goal is to implement native TLS on OS X in DMD. For this particular question I was trying to figure out how to get DMD to generate same assembly as the corresponding D code, when a TLS variable is accessed, using the el_* functions.
>
> auto foo = *bar.thunk(&bar);

If you point us to some documentation of the native TLS, we might be able to help guide you a bit better.

> It looks like the lowering for a TLS variable access to a call to ___tls_get_addr occurs in el_picvar for OS X.

That's b/c our emulated TLS is simply a function call, no linker recognition and dedicated relocations are involved. Look at the native TLS implementation for linux, it works very differently, and I'd expect OSX' implementation to be somewhat similar.

>> They simply construct an IR tree, no magic here.
>
>
> You make it sound so easy :). I guess my main problem is that I’m reading the assembly that Clang outputs then I have no idea how to get DMD to generate the same assembly.

Well it is fairly easy, https://en.wikipedia.org/wiki/Binary_expression_tree, but it's still quite difficult to construct the correct IR tree. As Daniel said, try to print your tree, there is some helper function (el_print or so).
As I said earlier, when you're relying on a specific sequence of instructions, you have to implement it in the codegen, not the IR construction.

_______________________________________________
dmd-internals mailing list
dmd-internals@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-internals
December 29, 2015
> On 29 dec 2015, at 12:14, Martin Nowak via dmd-internals <dmd-internals@puremagic.com> wrote:
> 
> If you point us to some documentation of the native TLS, we might be able to help guide you a bit better.

As far as I know there is no documentation. But I have already figured it out.

> That's b/c our emulated TLS is simply a function call, no linker recognition and dedicated relocations are involved. Look at the native TLS implementation for linux, it works very differently, and I'd expect OSX' implementation to be somewhat similar.

It looks like it works very similar for Linux. At least it has the same kind of lowering.

> Well it is fairly easy, https://en.wikipedia.org/wiki/Binary_expression_tree, but it's still quite difficult to construct the correct IR tree. As Daniel said, try to print your tree, there is some helper function (el_print or so).
> As I said earlier, when you're relying on a specific sequence of instructions, you have to implement it in the codegen, not the IR construction.

Anyway, I have already figured it out. Thanks for the help.

-- 
/Jacob Carlborg


_______________________________________________
dmd-internals mailing list
dmd-internals@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-internals