Slice expressions - exact evaluation order, dollar

Timon Gehr via Digitalmars-d digitalmars-d at puremagic.com
Sun Jun 26 19:38:22 PDT 2016


On 26.06.2016 20:08, Iain Buclaw via Digitalmars-d wrote:
> On 26 June 2016 at 14:33, Timon Gehr via Digitalmars-d
> <digitalmars-d at puremagic.com> wrote:
>> On 26.06.2016 10:08, Iain Buclaw via Digitalmars-d wrote:
>>>
>>> Old codegen:
>>>
>>> _base = *(getBase());
>>> _lwr = getLowerBound(_base.length);
>>> _upr = getUpperBound(_base.length);
>>> r = {.length=(_upr - _lwr), .ptr=_base.ptr + _lwr * 4};
>>>
>>> ---
>>
>>
>> This seems to be what I'd expect. It's also what CTFE does.
>> CTFE and run time behaviour should be identical. (So either one of them
>> needs to be fixed.)
>>
>>
>
> Very likely CTFE.  Anyway, this isn't the only thing where CTFE and
> Runtime do things differently.
> ...

All arbitrary differences should be eradicated.

>>> Now when creating temporaries of references, the reference is stabilized
>>> instead.
>>>
>>> New codegen:
>>>
>>> *(_ptr = getBase());
>>> _lwr = getLowerBound(_ptr.length);
>>> _upr = getUpperBound(_ptr.length);
>>> r = {.length=(_upr - _lwr), .ptr=_ptr.ptr + _lwr * 4};
>>> ---
>>>
>>> I suggest you fix LDC if it doesn't already do this. :-)
>>
>>
>>
>> I'm not convinced this is a good idea. It makes (()=>base)()[lwr()..upr()]
>> behave differently from base[lwr()..upr()].
>
> No, sorry, I'm afraid you are wrong there. They should both behave
> exactly the same.
> ...

I don't see how that is possible, unless I misunderstood your previous 
explanation. As far as I understand, for the first expression, code gen 
will generate a reference to a temporary copy of base, and for the 
second expression, it will generate a reference to base directly. If 
lwr() or upr() then update the ptr and/or the length of base, those 
changes will be seen for the second slice expression, but not for the first.


> I may need to step aside and explain what changed in GDC, as it had
> nothing to do with this LDC bug.
>
> ==> Step
>
> What made this subtle change was in relation to fixing bug 42 and 228
> in GDC, which involved turning on TREE_ADDRESSABLE(type) bit in our
> codegen trees, which in turn makes NRVO work consistently regardless
> of optimization flags used - no more optimizer being confused by us
> "faking it".
>
> How is the above jargon related? Well, one of the problems faced was
> that it must be ensured that lvalues continue being lvalues when
> considering creating a temporary in the codegen pass.  Lvalue
> references must have the reference stabilized, not the value that is
> being dereferenced.  This also came with an added assurance that GDC
> will now *never* create a temporary of a decl with a cpctor or dtor,
> else it'll die with an internal compiler error trying. :-)
> ...

What is the justification why the base should be evaluated as an lvalue?

> <== Step
>
> (() => base)[lwr()..up()] will make a temporary of (() => base), but
> guarantees that references are stabilized first.
>

(I assume you meant (() => base)()[lwr()..upr()].)

The lambda returns by value, so you will stabilize the reference to a 
temporary copy of base? (Unless I misunderstand your terminology.)

> base[lwr()..upr()] will create no temporary if base has no side
> effects.  And so if lwr() modifies base, then upr() will get the
> updated copy.
>

Yes, it is clear that upr() should see modifications to memory that 
lwr() makes. The point is that the slice expression itself does or does 
not see the updates based on whether I wrap base in a lambda or not.





More information about the Digitalmars-d mailing list