DIP62: Volatile type qualifier for unoptimizable variables in embedded programming

Johannes Pfau via Digitalmars-d digitalmars-d at puremagic.com
Wed Jul 16 05:59:50 PDT 2014


Am Tue, 15 Jul 2014 23:38:21 -0700
schrieb Walter Bright <newshound2 at digitalmars.com>:

> On 7/15/2014 10:15 PM, Johannes Pfau wrote:
> > Yes, I actually tried tested that simple implementation with gdc.
> > With aggressive optimizations the code inlines just fine and it'll
> > generate the same asm as an access to a volatile variable in C. But
> > it's not space-effecient: Even if it inlines, the function is still
> > in the object file as a distinct function. There's TypeInfo and
> > there's the assert(this), there's an initializer symbol and I guess
> > there could be copy constructors as well. I expect many bug
> > reports/fixes till we get a Volatile!T wrapper to be really
> > space-efficient.
> 
> D is intended to have a robust enough feature set in order to
> implement types as library types rather than builtin, and have them
> operate as good as a builtin type would. These are more general
> issues, and are not specific to volatile.
> 

And how do you implement this with a wrapper? This is common in C/C++:

struct Timer
{
    uint control;
    uint data;
}

enum timerA = (Volatile!Timer)* = cast()oxDEADBEAF;

timerA.control |= 0b1;

Your peek/poke intrinsics don't even consider this example. If you
extend peek/poke to T, then it'll always load the complete type,
whereas the C code loads only the field. And you can't even do anything
about it, cause peek!T explicitly tells the compiler to load the
complete type and prevent optimization of this load...

And it seems timerA.control |= 0b1; produces absolute nonsense. It
compiles, but
* The codegen is horrible. In C this compiles to 3 instructions, in D
  30-40 instructions
* This doesn't do what it's supposed to do at all. For example it calls
  the getter twice and never calls the setter.

The more I think about it the more corner cases appear. After all
implementing this in the library is much more complex than a type
qualifier. Some of the complexity is already implemented (alias
this, ...) so there's less changes in DMD. But any bug in alias this,
templates, etc will immediately leak into Volatile!T.

> 
> >>>> 3. if you really hate peek/poke calls appearing in the code, you
> >>>> can use UFCS to make them look like variables
> >>> But you cant do REGISTER.peek() |= 0b1;
> >> As you mentioned in the DIP, read-modify-write operations should be
> >> split up, as their semantics are murky.
> > But not necessarily in user code. REGISTER |= is quite common in C
> > and it's perfectly safe.
> 
> The point is it is not perfectly safe. There is no definition, and
> certainly no portable definition, as to how many read/write cycles
> such an operation entails. That's what I meant, and DIP62 says pretty
> much said the same thing. Please allow me to quote:

In cases where you use |= the exact number of accesses usually does not
matter. What matters is that there's at least one access and that it's
not reordered with other reads/writes to volatile.

For example |= is used on control registers. But I don't care if I
read/set the bit twice or once, I just doesn't matter.

> 
> "CISC machines may allow other operations to memory than simple
> load/store operations. The question is then if a read-modify-write
> operation like 'x++' should translate to 'r = load x; r++; x = store
> r' or to a single add instruction 'add x;'. This DIP does not dictate
> any specific behaviour, but this is recommended: If it is known that
> instructions operating on memory do not work for memory mapped IO as
> expected, compilers should default to generating a load/modify/store
> sequence. Otherwise compilers should generate the same code sequence
> as for regular variables. It is recommended to provide a compiler
> switch on CISC architectures to allow the user to choose between
> these two different behaviours."

And what does peek/poke guarantee in that case? Everything you could
specify for peek/poke can be specified for volatile variables as well.

> 
> > If people will have to split this up into peek |=
> > poke that's a step backwards from C.
> 
> Support for op= is fairly simple for VolatilePointerToUint to
> implement, and it can implement them in terms of peek/poke for
> precise and portable semantics.
See above

> I do believe that a wrapper type around peek/poke satisfies
> essentially all your necessary requirements, except for transitivity.

See above. One important point is that this must be as effective as
c+volatile (in terms of code size and execution cycles). This is an
important aspect for embedded programming and it'll take ages and many
language changes to make a type wrapper as efficient. If it's even
possible at all.

> > I think it's a correct argument to say that you think
> > embedded system programming is not important enough for the
> > additional complexity introduced by a new qualifier.
> 
> That is not what I'm saying at all. Please do not conflate
> disagreement about the best way to achieve a goal with disagreement
> about the goal.

So you do think peek/poke is a better solution than DIP62? Then you
have to explain this. All arguments so far have been it's too
complex in the compiler implementation, but never that peek/poke is a
better way to achieve that goal of accessing volatile memory.

In the end it's a judgement call between complexity and more
convenience for embedded programming and it's absolutely your decision.
But as long as I'm not convinced that peek/poke is a _better_ solution
I'll think that embedded programming is not important enough for you to
implement the _best_ solution, as it causes some implementation
complexity. And this in the end means it's of lower priority to you
than keeping some complexity out of the compiler.

> I understand that you and others put a lot of work into DIP62. As I
> said before, it's a very nice example of a well-done DIP.
> 

That's not the point. If I were convinced there's a better solution,
I'd be glad to accept it. But I'm not convinced at all, the only
argument against DIP62 so far was complexity.


More information about the Digitalmars-d mailing list