DIP62: Volatile type qualifier for unoptimizable variables in embedded programming

Johannes Pfau via Digitalmars-d digitalmars-d at puremagic.com
Wed Jul 16 13:09:20 PDT 2014


Am Wed, 16 Jul 2014 21:59:57 +0200
schrieb Artur Skawina via Digitalmars-d <digitalmars-d at puremagic.com>:

> On 07/16/14 15:02, Johannes Pfau via Digitalmars-d wrote:
> > Am Tue, 15 Jul 2014 19:44:51 +0200
> > schrieb Artur Skawina via Digitalmars-d
> > <digitalmars-d at puremagic.com>:
> > 
> >> Could you show one (concrete) example where using 'volatile' is
> >> better than my approach?
> > 
> > I experimented a little more with Volatile!T and I don't think you
> > can make this example work:
> > 
> > struct Timer
> > {
> >     uint control;
> >     uint data;
> > }
> > 
> > enum timerA = (Volatile!Timer)* = cast()0xDEADBEAF;
> > 
> > timerA.control |= 0b1;
> 
> Thank you very much for showing actual code. There are many (wrong)
> assumptions being made in this thread (and the one on the gdc list).
> Claims like "A is required" or "B is impossible", where A and B are
> not actually defined and only vaguely described, do not usually lead
> to a productive dialogue. Concrete examples and code make it possible
> for the discussion to be about facts and not perceptions. 
> 
>    struct Timer
>    {
>        uint control;
>        uint data;
>    }
> 
>    enum timerA = cast(Volatile!(Timer)*)0xDEADBEAF;
>    //enum timerA = volatile_(cast(Timer*)0xDEADBEAF); // works too.
> 
>    void main() {
>       timerA.control |= 0b1;
>    }
> 
>    struct Volatile(PT) {
>       PT raw;
> 
>       auto opDispatch(string M)() @property { return
> volatile_(mixin(q{&raw.}~M)); }
> 
>       auto opOpAssign(string OP, B)(B b) {
>          auto a = load(*raw);
>          auto r = mixin("a "~OP~" b");
>          store(*raw, r);
>          return this;
>       }
> 
>    static:
>       T load(T)(ref T v) {
>          asm { "" : "+m" v; }
>          T res = v;
>          asm { "" : "+g" res; }
>          return res;
>       }
> 
>       T store(T)(ref T v, const T a) {
>          asm { "" : : "m" v; }
>          v = a;
>          asm { "" : "+m" v; }
>          return a;
>       }
>    }
>    auto volatile_(A)(A a) { return Volatile!A(a); } // Just for IFTI.
> 
> 
> when compiled w/ "gdc -O1" results in
> 
> 0000000000402949 <_Dmain>:
>   402949:       b8 af be ad de          mov    $0xdeadbeaf,%eax
>   40294e:       8b 10                   mov    (%rax),%edx
>   402950:       83 ca 01                or     $0x1,%edx
>   402953:       89 10                   mov    %edx,(%rax)
>   402955:       b8 00 00 00 00          mov    $0x0,%eax
>   40295a:       c3                      retq   
> 
> which is the exact op sequence you'd expect. Doing it as just one
> R-M-W op would be possible too, but that might not be supported by
> all HW/platforms.
> And, yes, gdc inlines it even at -O0, if @inline is used. But at -O0
> the generated code is /already/ huge and inefficient, hence not really
> usable in constrained mem environments.
> 
> Obviously, this is just a proof of concept and the minimal
> implementation that can only handle your example. But it's enough to
> disprove the it-cannot-be-made-to-work-without-c-volatile claim. Are
> there any other examples of things that cannot be efficiently handled
> w/o a built-in volatile type qualifier?
> 
> artur

Well I guess this is already decided anyway.

I think it's kinda ridiculous that D embedded code will only be usable
with strong optimization flags, but whatever. Maybe it works better
if the usage is restricted to basic types only.


More information about the Digitalmars-d mailing list