DIP62: Volatile type qualifier for unoptimizable variables in embedded programming

Artur Skawina via Digitalmars-d digitalmars-d at puremagic.com
Wed Jul 16 12:59:57 PDT 2014


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


More information about the Digitalmars-d mailing list