August 16, 2014
On 08/16/14 09:33, Johannes Pfau via D.gnu wrote:
> https://github.com/D-Programming-GDC/GDC/pull/82

[Only noticed this accidentally; using a mailing list instead of some web forum would increase visibility...]

>  enum var = Volatile!(T,addr)(): doesn't allow |= on enum literals, even if the type implements opAssign as there's no this pointer

   T volatile_load(T)(ref T v) nothrow {
      asm { "" : "+m" v; }
      T res = v;
      asm { "" : "+g" res; }
      return res;
   }

   void volatile_store(T)(ref T v, const T a) nothrow {
      asm { "" : : "m" v; }
      v = a;
      asm { "" : "+m" v; }
   }

   struct Volatile(T, alias /* T* */ A) {
       void opOpAssign(string OP)(const T rhs) nothrow {
           auto v = volatile_load(*A);
           mixin("v " ~ OP ~ "= rhs;");
           volatile_store(*A, v);
       }
   }

   enum TimerB = Volatile!(uint, cast(uint*)0xDEADBEEF)();

   void main() {
      TimerB |= 0b1;
      TimerB += 1;
   }

> not emitting force-inlined functions is a logical optimization for forceinline (if a function is always inlined, there's no way to call it, so there's no need to output it).

Taking the address of an always_inline function is allowed.

artur
August 16, 2014
On Saturday, 16 August 2014 at 09:29:14 UTC, Johannes Pfau wrote:

> I just had a look at this and ClassInfo has a mutable 'monitor' field,
> so it can't be placed into read-only data.

This was discussed at DConf 2014.  https://www.youtube.com/watch?v=TNvUIWFy02I#t=1008


There is currently a pull request to remove the monitor from object field from object and therefore all classes: https://github.com/D-Programming-Language/druntime/pull/789.

Mike
August 16, 2014
On Saturday, 16 August 2014 at 09:59:03 UTC, Artur Skawina via D.gnu wrote:
>
> Taking the address of an always_inline function is allowed.
>

It may be allowed, but it probably shouldn't be.  Always-inlining a function and taking the address of that function is contradictory.

But this situation demonstrates why having an intelligent linker is a better solution than decorating with attributes.  The linker should know if you took an address of an always-inlined function or not and decide whether or not to remove it from the binary.

Mike
August 16, 2014
On 08/16/14 12:41, Mike via D.gnu wrote:
> On Saturday, 16 August 2014 at 09:59:03 UTC, Artur Skawina via D.gnu wrote:
>>
>> Taking the address of an always_inline function is allowed.
>>
> 
> It may be allowed, but it probably shouldn't be.  Always-inlining a function and taking the address of that function is contradictory.

Address-of should work -- disallowing it wouldn't help much, but would create problems for code that needs to call the function both directly and indirectly. This is actually a larger problem for D than for C (where it's allowed) because of generic code, templates and delegates. The alternative would be requiring trivial not-@inline wrappers and compile failures if one is accidentally forgotten.

A `@nocode` attribute would be a good idea, yes, but there's no need to make it implicit for `@inline`.

> But this situation demonstrates why having an intelligent linker is a better solution than decorating with attributes.  The linker should know if you took an address of an always-inlined function or not and decide whether or not to remove it from the binary.

It already does. Apparently there are some kind of problems with certain setups, but, instead of addressing those problems, more and more /language/ hacks are proposed...

artur
August 16, 2014
On Saturday, 16 August 2014 at 09:59:03 UTC, Artur Skawina via D.gnu wrote:
> On 08/16/14 09:33, Johannes Pfau via D.gnu wrote:
>> https://github.com/D-Programming-GDC/GDC/pull/82
>
> [Only noticed this accidentally; using a mailing list
> instead of some web forum would increase visibility...]
>
>>  enum var = Volatile!(T,addr)(): doesn't allow |= on enum literals, even if the type implements opAssign as there's no this pointer
>
>    T volatile_load(T)(ref T v) nothrow {
>       asm { "" : "+m" v; }
>       T res = v;
>       asm { "" : "+g" res; }
>       return res;
>    }
>
>    void volatile_store(T)(ref T v, const T a) nothrow {
>       asm { "" : : "m" v; }
>       v = a;
>       asm { "" : "+m" v; }
>    }
> 
>    struct Volatile(T, alias /* T* */ A) {
>        void opOpAssign(string OP)(const T rhs) nothrow {
>            auto v = volatile_load(*A);
>            mixin("v " ~ OP ~ "= rhs;");
>            volatile_store(*A, v);
>        }
>    }
>
>    enum TimerB = Volatile!(uint, cast(uint*)0xDEADBEEF)();
>
>    void main() {
>       TimerB |= 0b1;
>       TimerB += 1;
>    }
>
>> not emitting force-inlined functions is a logical optimization for forceinline (if a function is always inlined, there's no way to call it, so there's no need to output it).
>
> Taking the address of an always_inline function is allowed.
>
> artur

This seems to work.

I am not so familiar with these opAssign things, so how I can do basic assignment: TimerB = 0x1234  ?

How can I use this with struct members ?

Is it possible to inline volatile_load and volatile_store ?
August 16, 2014
On 08/16/14 18:46, Timo Sintonen via D.gnu wrote:
> 
> I am not so familiar with these opAssign things, so how I can do basic assignment: TimerB = 0x1234  ?

> Is it possible to inline volatile_load and volatile_store ?

   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" 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; }
   }

   static struct Volatile(T, alias PTR) {
      static: nothrow: @inline:
      void opOpAssign(string OP)(const T rhs) {
           auto v = volatile_load(*PTR);
           mixin("v " ~ OP ~ "= rhs;");
           volatile_store(*PTR, v);
      }
      void opAssign()(const T rhs) { volatile_store(*PTR, rhs); }
      T opUnary(string OP:"*")() { return volatile_load(*PTR); }
   }

   enum TimerB = Volatile!(uint, cast(uint*)0xDEADBEEF)();

   int main() {
      TimerB |= 0b1;
      TimerB += 1;
      TimerB = 42;
      return *TimerB;
   }

> How can I use this with struct members ?

One possibility would be to declare all members as `Volatile!...`, or
even create such a struct at CT. Another solution would be something
like http://forum.dlang.org/post/mailman.4237.1405540813.2907.digitalmars-d@puremagic.com .

artur
August 16, 2014
On 08/16/14 20:40, Artur Skawina wrote:
>> How can I use this with struct members ?
> 
> One possibility would be to declare all members as `Volatile!...`, or

I did not like that required dereference in the previous version, and tried a different approach:

   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;
      return timerA.control;
   }

   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; }
   }

   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 rhs) {
           auto v = volatile_load(raw);
           mixin("v " ~ OP ~ "= rhs;");
           volatile_store(raw, v);
      }
   }


artur
August 17, 2014
On Saturday, 16 August 2014 at 20:01:06 UTC, Artur Skawina via
D.gnu wrote:
> On 08/16/14 20:40, Artur Skawina wrote:
>>> How can I use this with struct members ?
>> 
>> One possibility would be to declare all members as `Volatile!...`, or
>
> I did not like that required dereference in the previous version,
> and tried a different approach:
>
>    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;
>       return timerA.control;
>    }
>
>    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; }
>    }
> 
>    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 rhs) {
>            auto v = volatile_load(raw);
>            mixin("v " ~ OP ~ "= rhs;");
>            volatile_store(raw, v);
>       }
>    }
>
>
> artur

This seems to work. With inlining the code is quite compact.

Not tested yet but the code for these constructs looks correct:
for (f=0;f<50;f++) { regs.txreg = śomebuf[f] }
while (regs.status == 0) {}

What is the purpose of volatile_dummy? Even if it is not used,
the address for it is calculated in several places.

The struct members are defined saparately. This means the address
of every member is stored and fetched separately. The compiler
seems to remove some of these and use the pointer, but I am not
sure what happens when the structs are bigger.

It seems all loads and stores access the real memory, like
volatile should do. It is hard to follow the optimized code so I
am not yet sure that they have not been reordered in any way.

Anyway, this seems acceptable solution to me.

Johannes, is this good starting point to you or is your work with
compiler builtins giving us some more?
August 17, 2014
Am Sat, 16 Aug 2014 10:36:19 +0000
schrieb "Mike" <none@none.com>:

> On Saturday, 16 August 2014 at 09:29:14 UTC, Johannes Pfau wrote:
> 
> > I just had a look at this and ClassInfo has a mutable 'monitor'
> > field,
> > so it can't be placed into read-only data.
> 
> This was discussed at DConf 2014. https://www.youtube.com/watch?v=TNvUIWFy02I#t=1008
> 
> 
> There is currently a pull request to remove the monitor from object field from object and therefore all classes: https://github.com/D-Programming-Language/druntime/pull/789.
> 
> Mike

Great! But I think this pull request addresses a different monitor problem: There's an implicit __monitor field in every class right now, which makes every class _instance_ bigger.

But the monitor in TypeInfo/ClassInfo is different: ClassInfo exists only once per class, it doesn't matter how many class instances you've got. AFAIR this monitor is to support synchronize(ClassType) which synchronizes on the class type, not on an instance.
August 17, 2014
Am Sat, 16 Aug 2014 13:15:57 +0200
schrieb "Artur Skawina via D.gnu" <d.gnu@puremagic.com>:

> On 08/16/14 12:41, Mike via D.gnu wrote:
> > On Saturday, 16 August 2014 at 09:59:03 UTC, Artur Skawina via D.gnu wrote:
> >>
> >> Taking the address of an always_inline function is allowed.
> >>
> > 
> > It may be allowed, but it probably shouldn't be.  Always-inlining a function and taking the address of that function is contradictory.
> 
> Address-of should work -- disallowing it wouldn't help much, but would create problems for code that needs to call the function both directly and indirectly. This is actually a larger problem for D than for C (where it's allowed) because of generic code, templates and delegates. The alternative would be requiring trivial not-@inline wrappers and compile failures if one is accidentally forgotten.
> 
> A `@nocode` attribute would be a good idea, yes, but there's no need to make it implicit for `@inline`.

We can make this explicit. I don't care enough to argue about that.

> > But this situation demonstrates why having an intelligent linker is a better solution than decorating with attributes.  The linker should know if you took an address of an always-inlined function or not and decide whether or not to remove it from the binary.
> 
> It already does. Apparently there are some kind of problems with certain setups, but, instead of addressing those problems, more and more /language/ hacks are proposed...
> 
> artur

So as you know all these problems and you know exactly how to fix them, where's your contribution?