Accessing peripheral registers - the next version

Johannes Pfau via D.gnu d.gnu at puremagic.com
Sat Sep 24 01:40:12 PDT 2016


Am Wed, 31 Aug 2016 19:06:37 +0000
schrieb Timo Sintonen <t.sintonen at luukku.com>:

> On Wednesday, 31 August 2016 at 10:12:21 UTC, Johannes Pfau wrote:
> 
> >> There was @disable this(this)
> >> This prevents to use a location as argument to a function, 
> >> like:
> >> print(timer.count). Is there any reason to have this line or 
> >> not?  
> >
> > I guess timer is a (enum) pointer to a struct and count is a 
> > Volatile!T
> > field in that struct?  
> Yes
> 
> > But then timer.count does not return a address, it returns the 
> > value of
> > count? Unless of course print(X) takes its argument by ref or 
> > alias.  
> I want to use them just by value.
> 
> >
> > The reason for @disable this(this) is to disable copying of the 
> > struct.
> > The compiler otherwise accesses T raw in a 'non-volatile' way 
> > when
> > copying the value. In D we can only have a postblit function, 
> > but we
> > cannot reimplement the copying. opAssign can only be used in 
> > some cases:
> >     Foo f;
> >     auto f2 = Foo();
> >     auto f3 = f2;
> >     f = Foo();
> >     f = f2;
> >
> > Only the last two lines call opAssign. So "auto f3 = f2" could 
> > copy a Volatile!T in a non-volatile way. This is the reason for 
> > @disable this(this), AFAIK.
> >  
> I think I somehow get the point even if I do not fully understand 
> the explanation.

See https://dlang.org/spec/struct.html#struct-postblit :
"1. blitting the fields, i.e. copying the bits [...] The first part is
done automatically by the language,"

So assume we have a (Volatile!uint)* called 'value' pointing to 0x4.
Volatile!uint is a struct with a uint raw member. Now if we do
something like this:

Volatile!uint copy = *value;

This tells DMD that copy is a struct with one uint field on the stack.
Now to create this stack variable the compiler will copy the 4 bytes
from 0x4 for the field to the stack (The rule #1 quoted above). But
the compiler does not know that the data at 0x4 is 'volatile'. So it
would insert a normal / 'non-volatile' load. And this load is then
subject to the optimizations we want to avoid with Volatile!T.

So we somehow have to prevent the compiler from making such copies. The
only way to do this is @disable this(this).

> But it is too restrictive if I always need to have a getter 
> function or assign the value first to a temporary variable to use 
> the value in a function call.

I think there's a misunderstanding here:
The problem only occurs if you pass a _Volatile!T_ by value:

void foo(Volatile!uint value) {}
foo(timer.count);

But if you only need the payload data you can pass the _T_ type instead
and everything works fine, even with @disable this(this): The alias
this implements this implicit convertion. This means the compiler will
call load for you when preparing the function arguments (with the
standard D side effect rules, i.e. LTR evaluation)

void foo(uint value) {}
foo(timer.count); // <-- load is called here

If you really want to pass a Volatile!T type (or a struct containing
Volatile!T fields) the only safe way is pass by reference / pointer.
You have ta avoid copying / reading the data, but you can of course
refer to it's memory location / address:

void foo(ref Volatile!uint value) {}
foo(timer.count);

> 
> Anyway, I think it is a gdc bug that the error message comes from 
> the called function that has nothing to do with this. The error 
> should show the function call where the disabled copy operation 
> is.
> 

That's a valid point, but handling this is a DMD task. Please report
this at issues.dlang.org.


More information about the D.gnu mailing list