Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
Atomic fetchadd now working with unittests. Should work for both x64 …
Browse files Browse the repository at this point in the history
…and x86
  • Loading branch information
jadbox committed Apr 7, 2015
1 parent 169681e commit 182c63e
Showing 1 changed file with 118 additions and 68 deletions.
186 changes: 118 additions & 68 deletions src/core/atomic.d
Expand Up @@ -56,6 +56,70 @@ version( AsmX86 )
{
return addr % T.sizeof == 0;
}

// Uses specialized asm for fast fetch and add operations
HeadUnshared!(T) atomicFetchAdd(T)( ref shared T val, T mod ) pure nothrow @nogc
if( __traits(isIntegral, T) )
in
{
// NOTE: 32 bit x86 systems support 8 byte CAS, which only requires
// 4 byte alignment, so use size_t as the align type here.
static if( T.sizeof > size_t.sizeof )
assert( atomicValueIsProperlyAligned!(size_t)( cast(size_t) &val ) );
else
assert( atomicValueIsProperlyAligned!(T)( cast(size_t) &val ) );
}
body
{
HeadUnshared!(T) oval = void;
static if (T.sizeof == 1)
{
asm pure nothrow @nogc
{
mov AL, mod;
mov RDX, val;
lock;
xadd[RDX], AL;
mov oval, AL;
}
}
else static if (T.sizeof == 2)
{
asm pure nothrow @nogc
{
mov AX, mod;
mov RDX, val;
lock;
xadd[RDX], AX;
mov oval, AX;
}
}
else static if (T.sizeof == 4)
{
asm pure nothrow @nogc
{
mov EAX, mod;
mov RDX, val;
lock;
xadd[RDX], EAX;
mov oval, EAX;
}
}
else static if (T.sizeof == 8)
{
asm pure nothrow @nogc
{
mov RAX, mod;
mov RDX, val;
lock;
xadd[RDX], RAX;
mov oval, RAX;
}
}

oval += mod;
return oval;
}
}


Expand Down Expand Up @@ -628,72 +692,6 @@ else version( AsmX86_32 )
}
else version( AsmX86_64 )
{
HeadUnshared!(T) atomicFetchAdd(T)( ref shared T val, T mod ) pure nothrow @nogc
if( __traits(isIntegral, T) )
in
{
// NOTE: 32 bit x86 systems support 8 byte CAS, which only requires
// 4 byte alignment, so use size_t as the align type here.
static if( T.sizeof > size_t.sizeof )
assert( atomicValueIsProperlyAligned!(size_t)( cast(size_t) &val ) );
else
assert( atomicValueIsProperlyAligned!(T)( cast(size_t) &val ) );
}
body
{
HeadUnshared!(T) oval = void;
static if (T.sizeof == 1)
{
asm pure nothrow @nogc
{
mov AL, mod;
mov RDX, val;
lock;
xadd[RDX], AL;
mov oval, AL;
}
}
else static if (T.sizeof == 2)
{
asm pure nothrow @nogc
{
mov AX, mod;
mov RDX, val;
lock;
xadd[RDX], AX;
mov oval, AX;
}
}
else static if (T.sizeof == 4)
{
asm pure nothrow @nogc
{
mov EAX, mod;
mov RDX, val;
lock;
xadd[RDX], EAX;
mov oval, EAX;
}
}
else static if (T.sizeof == 8)
{
asm pure nothrow @nogc
{
mov RAX, mod;
mov RDX, val;
lock;
xadd[RDX], RAX;
mov oval, RAX;
}
}

oval += mod;
return oval;
}




HeadUnshared!(T) atomicOp(string op, T, V1)( ref shared T val, V1 mod ) pure nothrow @nogc
if( __traits( compiles, mixin( "*cast(T*)&val" ~ op ~ "mod" ) ) )
in
Expand Down Expand Up @@ -727,10 +725,14 @@ else version( AsmX86_64 )
//
// += -= *= /= %= ^^= &=
// |= ^= <<= >>= >>>= ~=
static if( op == "+=" && __traits(isIntegral, T) && __traits(isSame,T,V1) ) {
static if( op == "+=" && __traits(isIntegral, T) && is(T==V1) ) {
return atomicFetchAdd!(T)(val, mod);
}
else
static if( op == "-=" && __traits(isIntegral, T) && is(T==V1) ) {
return atomicFetchAdd!(T)(val, -mod);
}
else
static if( op == "+=" || op == "-=" || op == "*=" || op == "/=" ||
op == "%=" || op == "^^=" || op == "&=" || op == "|=" ||
op == "^=" || op == "<<=" || op == ">>=" || op == ">>>=" ) // skip "~="
Expand Down Expand Up @@ -1519,6 +1521,54 @@ version( unittest )
assert(atomicOp!"+="(i8, 8) == 13);
assert(atomicOp!"+="(i16, 8) == 14);
assert(atomicOp!"+="(i32, 8) == 15);
assert(atomicOp!"+="(i64, 8) == 16);
version( AsmX86_64 ) {
assert(atomicOp!"+="(i64, 8) == 16);
}
}

unittest
{
shared ubyte u8 = 1;
shared ushort u16 = 2;
shared uint u32 = 3;
shared ulong u64 = 4;
shared byte i8 = 5;
shared short i16 = 6;
shared int i32 = 7;
shared long i64 = 8;

assert(atomicOp!"-="(u8, 1) == 0);
assert(atomicOp!"-="(u16, 1) == 1);
assert(atomicOp!"-="(u32, 1) == 2);
assert(atomicOp!"-="(u64, 1) == 3);
assert(atomicOp!"-="(i8, 1) == 4);
assert(atomicOp!"-="(i16, 1) == 5);
assert(atomicOp!"-="(i32, 1) == 6);
version( AsmX86_64 ) {
assert(atomicOp!"-="(i64, 1) == 7);
}
}

unittest
{
shared ubyte u8 = 1;
shared ushort u16 = 2;
shared uint u32 = 3;
shared ulong u64 = 4;
shared byte i8 = 5;
shared short i16 = 6;
shared int i32 = 7;
shared long i64 = 8;

assert(atomicFetchAdd(u8, 8) == 9);
assert(atomicFetchAdd(u16, 8) == 10);
assert(atomicFetchAdd(u32, -1) == 2);
assert(atomicFetchAdd(u64, -1) == 3);
assert(atomicFetchAdd(i8, -1) == 4);
assert(atomicFetchAdd(i16, -1) == 5);
assert(atomicFetchAdd(i32, -1) == 6);
version( AsmX86_64 ) {
assert(atomicFetchAdd(i64, -1) == 7);
}
}
}

0 comments on commit 182c63e

Please sign in to comment.