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