Object file questions

Artur Skawina via D.gnu d.gnu at puremagic.com
Sun Aug 17 06:15:12 PDT 2014


On 08/17/14 10:49, Johannes Pfau via D.gnu wrote:

> That's a good start. Can you also get unary operators working?
> e.g
> TimerB++;

Unary ops are easy. If you mean post-inc and post-dec -- that's a 
language problem. At least for volatile, they will cause a compile
error; for atomic ops the naive `post-op->tmp-load+op+tmp` rewrite
can introduce bugs... D would need to make the post-ops overloadable
to get rid of these issues.

> Do you think it's possible to combine this with the other solution you
> posted for struct fields? Or do we need separate Volatile!T and
> VolatileField!T types?

Right now, I'd prefer this approach:

--------------------------------------------------------------
   module volat;
   
   version (GNU) {
   static import gcc.attribute;
   enum inline = gcc.attribute.attribute("forceinline");
   }
   
   extern int volatile_dummy;
   
   @inline T volatile_load(T)(ref T v) nothrow {
      asm { "" : "+m" v, "+m" volatile_dummy; }
      T res = v;
      asm { "" : "+g" res, "+m" v, "+m" volatile_dummy; }
      return res;
   }

   @inline void volatile_store(T, A)(ref T v, A a) nothrow {
      asm { "" : "+m" volatile_dummy : "m" v; }
      v = a;
      asm { "" : "+m" v, "+m" volatile_dummy; }
   }
   
   @inline void volatile_barrier(T)(ref T v) nothrow {
      asm { "" : "+m" v, "+m" volatile_dummy; }
   }
   
   struct Volatile(T) {
      T raw;
      nothrow: @inline:
      @disable this(this);
      void opAssign(A)(A a) { volatile_store(raw, a); }
      T load() @property { return volatile_load(raw); }
      alias load this;
      void opOpAssign(string OP)(const T b) {
           volatile_barrier(raw);
           mixin("raw " ~ OP ~ "= b;");
           volatile_barrier(raw);
      }
      T opUnary(string OP)() {
           volatile_barrier(raw);
           auto result = mixin(OP ~ "raw");
           volatile_barrier(raw);
           return result;
      }
   }
--------------------------------------------------------------
   import volat;

   struct Timer
   {
       Volatile!uint control;
       Volatile!uint data;
   }

   enum timerA = cast(Timer*)0xDEADBEAF;

   int main() {
      timerA.control |= 0b1;
      timerA.control += 1;
      timerA.control = 42;
      int a = timerA.data - timerA.data;
      int b = ++timerA.control;
      --timerA.data;
      timerA.control /= 2;
      return b;
   }
--------------------------------------------------------------

compiles to:

--------------------------------------------------------------
0000000000403620 <_Dmain>:
  403620:       ba af be ad de          mov    $0xdeadbeaf,%edx
  403625:       b9 b3 be ad de          mov    $0xdeadbeb3,%ecx
  40362a:       83 0a 01                orl    $0x1,(%rdx)
  40362d:       83 02 01                addl   $0x1,(%rdx)
  403630:       c7 02 2a 00 00 00       movl   $0x2a,(%rdx)
  403636:       8b 42 04                mov    0x4(%rdx),%eax
  403639:       8b 72 04                mov    0x4(%rdx),%esi
  40363c:       8b 02                   mov    (%rdx),%eax
  40363e:       83 c0 01                add    $0x1,%eax
  403641:       89 02                   mov    %eax,(%rdx)
  403643:       83 6a 04 01             subl   $0x1,0x4(%rdx)
  403647:       d1 2a                   shrl   (%rdx)
  403649:       c3                      retq   
--------------------------------------------------------------

Do you see any problems with it? (Other than gcc not removing
that dead constant load)

[The struct-with-volatile-fields can be built from a "normal"
 struct at CT. But that's just syntax sugar.]

artur


More information about the D.gnu mailing list