Am Mon, 20 Jun 2016 20:34:12 +0000
schrieb Basile B. <b2.t...@gmx.com>:

> On Monday, 20 June 2016 at 11:45:28 UTC, Johannes Pfau wrote:
> > Am Sun, 19 Jun 2016 20:52:52 +0000
> > schrieb deadalnix <deadal...@gmail.com>:
> >  
> >> On Sunday, 19 June 2016 at 11:11:18 UTC, Basile B. wrote:  
> >> > On Saturday, 23 April 2016 at 13:37:31 UTC, Andrei 
> >> > Alexandrescu wrote:  
> >> >> https://issues.dlang.org/show_bug.cgi?id=15951. I showed a 
> >> >> few obvious cases, but finding the best code in general is 
> >> >> tricky. Ideas? -- Andrei  
> >> >
> >> > A new "@noinit" attribute could solve this issue and other 
> >> > cases where the initializer is a handicap:
> >> >
> >> > The runtime would skip the copy of the initializer when
> >> > 1- @noinit is an attribute of an aggregate.
> >> > 2- a ctor that takes at least one parameter is present.
> >> > 3- the default ctor is disabled (only a condition for the
> >> > structs or the new free form unions)
> >> >
> >> > // OK
> >> > @noinit struct Foo
> >> > {
> >> >    uint a;
> >> >    @disable this();
> >> >    this(uint a){}
> >> > }
> >> >
> >> > // not accepted because a ctor with parameters misses
> >> > @noinit struct Foo
> >> > {
> >> >    @disable this();
> >> > }
> >> >
> >> > // Ok but a warning will be emitted...
> >> > @noinit struct Foo
> >> > {
> >> >    uint a = 1; // ...because this value is ignored
> >> >    @disable this();
> >> >    this(uint a){}
> >> > }
> >> >
> >> > // not accepted because there's a default ctor
> >> > @noinit struct Foo
> >> > {
> >> >    this(){}
> >> > }
> >> >
> >> > The rationale is that when there's a constructor that takes 
> >> > parameters it's really suposed to initialize the aggregate. 
> >> > At least that would be the contract, the "postulate', put by 
> >> > the usage of @noinit.  
> >> 
> >> No new attribute please. Just enable the damn thing where 
> >> there is an argumentless constructor and be done with it.  
> >
> > Can somebody explain how exactly are constructors related to 
> > the problem?  
> 
> The initializer is copied to the chunk that represents the new 
> aggregate instance. The idea here is to explicitly disable this 
> copy to get a faster instantiation, under certain conditions. For 
> example in allocator.make() this would mean "skip the call to 
> emplace() and call directly __ctor() on the new chunk".
> 
> > If I've got this:
> > struct Foo
> > {
> >     int a = 42;
> >     int b = void;
> >
> >     @disable this();
> >     this(int b)
> >     {this.b = b;}
> > }
> > auto foo = Foo(41);
> >
> > I'd still expect a to be initialized to 42.  
> 
> That's exactly why with @noinit you would get a warning
> 
> > Note that this does _not_ require a initializer symbol or 
> > memcpy.  
> 
> I'be verified again and the initializer is copied. For example 
> with a gap in the static initial values:

I meant this does not have to use a symbol. Right now it does, but
that's an implementation issue.

> 
> 
> struct Foo
> {
>       int a = 7;
>       int gap = void;
>       int c = 8;
>       @disable this();
>       this(int a)
>       {this.a = a;}
> }
> auto fun(){ auto foo = Foo(41); return foo.a;}
> 
> 
> I get (-O -release -inline) for fun():
> 
> 0000000000457D58h  sub rsp, 18h
> 0000000000457D5Ch  mov esi, 004C9390h // 
> typid(Foo).initializer.ptr
> 0000000000457D61h  lea rdi, qword ptr [rsp+08h]
> 0000000000457D66h  movsq //copy 8, note that the gap is not 
> handled at all
> 0000000000457D68h  movsb //copy 1
> 0000000000457D69h  movsb //copy 1
> 0000000000457D6Ah  movsb //copy 1
> 0000000000457D6Bh  movsb //copy 1
> 0000000000457D6Ch  mov eax, 00000029h //inlined __ctor
> 0000000000457D71h  mov dword ptr [rsp+08h], eax
> 0000000000457D75h  add rsp, 18h
> 0000000000457D79h  ret
> 
> But that was obvious. How would you expect a = 7 and c = 8 to be 
> generated otherwise ?

Instead of doing foo = Foo.init(symbol) you could do foo = {a:7,
c:8}(literal) (in the compiler). Then you don't need memory to memory
moves at all if your architecure allows hardcoding constants in
instructions. Additionally this allows the optimizer to see if you're
writing to a default initialized variable and remove the
useless initialization. If you don't have any default initializers / all
are =void, foo = {} is a no-op. With @noinit using default initializers
causes a warning, with my idea using default initializers works fine
and if you don't want any, just set all fields to =void. (This does not
produce optimal code right now, but considering the =void fields when
initializing is a simple change in GDC)

See https://issues.dlang.org/show_bug.cgi?id=15951#c4 for details.

> 
> with @noinit you would get
> 
> sub rsp, 18h
> mov eax, 00000029h //inlined __ctor
> mov dword ptr [rsp+08h], eax
> add rsp, 18h
> ret
> 
> That's a really simple and pragmatic idea. But I guess that if 
> you manage to get the compiler to generate a smarter initializer 
> copy then the problem is fixed. At least I'll experiment this 
> noinit stuff in my user library.


Reply via email to