// D import file generated from 'core\sync\Atomic.d'
module tango.core.sync.Atomic;
version (LDC)
{
    import ldc.intrinsics;
}
private 
{
    template isIntegerType(T)
{
const 
{
    bool isIntegerType = isSignedIntegerType!(T) || isUnsignedIntegerType!(T);
}
}
    template isPointerType(T)
{
const isPointerType = false;
}
    template isPointerType(T : T*)
{
const isPointerType = true;
}
    template isSignedIntegerType(T)
{
const 
{
    bool isSignedIntegerType = is(T == byte) || is(T == short) || is(T == int) || is(T == long);
}
}
    template isUnsignedIntegerType(T)
{
const 
{
    bool isUnsignedIntegerType = is(T == ubyte) || is(T == ushort) || is(T == uint) || is(T == ulong);
}
}
}
extern (C) 
{
    void thread_yield();
}
template atomicValueIsProperlyAligned(T)
{
bool atomicValueIsProperlyAligned(size_t addr)
{
return addr % T.sizeof == 0;
}
}
version (LDC)
{
    template memoryBarrier(bool ll,bool ls,bool sl,bool ss,bool device = false)
{
void memoryBarrier()
{
llvm_memory_barrier(ll,ls,sl,ss,device);
}
}
}
else
{
    version (D_InlineAsm_X86)
{
    template memoryBarrier(bool ll,bool ls,bool sl,bool ss,bool device = false)
{
void memoryBarrier()
{
static if(device)
{
if (ls || sl || ll || ss)
{
volatile asm { push EBX; }
asm { mov EAX,0; }
asm { cpuid; }
asm { pop EBX; }
}
}
else
{
static if(ls || sl || ll && ss)
{
volatile asm { mfence; }
}
else
{
static if(ll)
{
volatile asm { lfence; }
}
else
{
static if(ss)
{
volatile asm { sfence; }
}

}

}

}

}
}
}
else
{
    version (D_InlineAsm_X86_64)
{
    template memoryBarrier(bool ll,bool ls,bool sl,bool ss,bool device = false)
{
void memoryBarrier()
{
static if(device)
{
if (ls || sl || ll || ss)
{
volatile asm { push RBX; }
asm { mov RAX,0; }
asm { cpuid; }
asm { pop RBX; }
}
}
else
{
static if(ls || sl || ll && ss)
{
volatile asm { mfence; }
}
else
{
static if(ll)
{
volatile asm { lfence; }
}
else
{
static if(ss)
{
volatile asm { sfence; }
}

}

}

}

}
}
}
else
{
    pragma(msg, "WARNING: no atomic operations on this architecture");
    pragma(msg, "WARNING: this is *slow* you probably want to change this!");
    int dummy;
    synchronized 
{
    template memoryBarrier(bool ll,bool ls,bool sl,bool ss,bool device = false)
{
void memoryBarrier()
{
dummy = 1;
}
}
}
    enum 
{
LockVersion = true,
}
}
}
}
static if(!is(typeof(LockVersion)))
{
    enum 
{
LockVersion = false,
}
}
version (LDC)
{
    template atomicSwap(T)
{
bool atomicSwap(ref T val, T newval)
{
T oldval = void;
static if(isPointerType!(T))
{
oldval = cast(T)llvm_atomic_swap!(size_t)(cast(size_t*)&val,cast(size_t)newval);
}
else
{
static if(is(T == bool))
{
oldval = llvm_atomic_swap!(ubyte)(cast(ubyte*)&val,newval ? 1 : 0) ? 0 : 1;
}
else
{
oldval = llvm_atomic_swap!(T)(&val,newval);
}

}

return oldval;
}
}
}
else
{
    version (D_InlineAsm_X86)
{
    template atomicSwap(T)
{
T atomicSwap(ref T val, T newval)
in
{
static if(T.sizeof > size_t.sizeof)
{
assert(atomicValueIsProperlyAligned!(size_t)(cast(size_t)&val));
}
else
{
assert(atomicValueIsProperlyAligned!(T)(cast(size_t)&val));
}

}
body
{
T* posVal = &val;
static if(T.sizeof == (byte).sizeof)
{
volatile asm { mov AL,newval; }
asm { mov ECX,posVal; }
asm { lock; }
asm { xchg[ECX],AL; }
}
else
{
static if(T.sizeof == (short).sizeof)
{
volatile asm { mov AX,newval; }
asm { mov ECX,posVal; }
asm { lock; }
asm { xchg[ECX],AX; }
}
else
{
static if(T.sizeof == (int).sizeof)
{
volatile asm { mov EAX,newval; }
asm { mov ECX,posVal; }
asm { lock; }
asm { xchg[ECX],EAX; }
}
else
{
static if(T.sizeof == (long).sizeof)
{
static assert(false,"Invalid template type specified, 8bytes in 32 bit mode: " ~ T.stringof);
}
else
{
static assert(false,"Invalid template type specified: " ~ T.stringof);
}

}

}

}

}
}
}
else
{
    version (D_InlineAsm_X86_64)
{
    template atomicSwap(T)
{
T atomicSwap(ref T val, T newval)
in
{
assert(atomicValueIsProperlyAligned!(T)(cast(size_t)&val));
}
body
{
T* posVal = &val;
static if(T.sizeof == (byte).sizeof)
{
volatile asm { mov AL,newval; }
asm { mov RCX,posVal; }
asm { lock; }
asm { xchg[RCX],AL; }
}
else
{
static if(T.sizeof == (short).sizeof)
{
volatile asm { mov AX,newval; }
asm { mov RCX,posVal; }
asm { lock; }
asm { xchg[RCX],AX; }
}
else
{
static if(T.sizeof == (int).sizeof)
{
volatile asm { mov EAX,newval; }
asm { mov RCX,posVal; }
asm { lock; }
asm { xchg[RCX],EAX; }
}
else
{
static if(T.sizeof == (long).sizeof)
{
volatile asm { mov RAX,newval; }
asm { mov RCX,posVal; }
asm { lock; }
asm { xchg[RCX],RAX; }
}
else
{
static assert(false,"Invalid template type specified: " ~ T.stringof);
}

}

}

}

}
}
}
else
{
    template atomicSwap(T)
{
T atomicSwap(ref T val, T newval)
in
{
assert(atomicValueIsProperlyAligned!(T)(cast(size_t)&val));
}
body
{
T oldVal;
synchronized(typeid(T)) {
oldVal = val;
val = newval;
}
return oldVal;
}
}
}
}
}
version (LDC)
{
    template atomicCAS(T)
{
bool atomicCAS(ref T val, T newval, T equalTo)
{
T oldval = void;
static if(isPointerType!(T))
{
oldval = cast(T)llvm_atomic_cmp_swap!(size_t)(cast(size_t*)&val,cast(size_t)equalTo,cast(size_t)newval);
}
else
{
static if(is(T == bool))
{
oldval = llvm_atomic_cmp_swap!(ubyte)(cast(ubyte*)&val,equalTo ? 1 : 0,newval ? 1 : 0) ? 0 : 1;
}
else
{
oldval = llvm_atomic_cmp_swap!(T)(&val,equalTo,newval);
}

}

return oldval == equalTo;
}
}
}
else
{
    version (D_InlineAsm_X86)
{
    template atomicCAS(T)
{
bool atomicCAS(ref T val, T newval, T equalTo)
in
{
static if(T.sizeof > size_t.sizeof)
{
assert(atomicValueIsProperlyAligned!(size_t)(cast(size_t)&val));
}
else
{
assert(atomicValueIsProperlyAligned!(T)(cast(size_t)&val));
}

}
body
{
T* posVal = &val;
static if(T.sizeof == (byte).sizeof)
{
volatile asm { mov DL,newval; }
asm { mov AL,equalTo; }
asm { mov ECX,posVal; }
asm { lock; }
asm { cmpxchg[ECX],DL; }
asm { setz AL; }
}
else
{
static if(T.sizeof == (short).sizeof)
{
volatile asm { mov DX,newval; }
asm { mov AX,equalTo; }
asm { mov ECX,posVal; }
asm { lock; }
asm { cmpxchg[ECX],DX; }
asm { setz AL; }
}
else
{
static if(T.sizeof == (int).sizeof)
{
volatile asm { mov EDX,newval; }
asm { mov EAX,equalTo; }
asm { mov ECX,posVal; }
asm { lock; }
asm { cmpxchg[ECX],EDX; }
asm { setz AL; }
}
else
{
static if(T.sizeof == (long).sizeof)
{
version (darwin)
{
return OSAtomicCompareAndSwap64(cast(long)equalTo,cast(long)newval,cast(long*)&val);
}
else
{
volatile asm { push EDI; }
asm { push EBX; }
asm { lea EDI,newval; }
asm { mov EBX,[EDI]; }
asm { mov ECX,4[EDI]; }
asm { lea EDI,equalTo; }
asm { mov EAX,[EDI]; }
asm { mov EDX,4[EDI]; }
asm { mov EDI,val; }
asm { lock; }
asm { cmpxch8b[EDI]; }
asm { setz AL; }
asm { pop EBX; }
asm { pop EDI; }
}

}
else
{
static assert(false,"Invalid template type specified: " ~ T.stringof);
}

}

}

}

}
}
}
else
{
    version (D_InlineAsm_X86_64)
{
    template atomicCAS(T)
{
bool atomicCAS(ref T val, T newval, T equalTo)
in
{
assert(atomicValueIsProperlyAligned!(T)(cast(size_t)&val));
}
body
{
T* posVal = &val;
static if(T.sizeof == (byte).sizeof)
{
volatile asm { mov DL,newval; }
asm { mov AL,equalTo; }
asm { mov RCX,posVal; }
asm { lock; }
asm { cmpxchg[RCX],DL; }
asm { setz AL; }
}
else
{
static if(T.sizeof == (short).sizeof)
{
volatile asm { mov DX,newval; }
asm { mov AX,equalTo; }
asm { mov RCX,posVal; }
asm { lock; }
asm { cmpxchg[RCX],DX; }
asm { setz AL; }
}
else
{
static if(T.sizeof == (int).sizeof)
{
volatile asm { mov EDX,newval; }
asm { mov EAX,equalTo; }
asm { mov RCX,posVal; }
asm { lock; }
asm { cmpxchg[RCX],EDX; }
asm { setz AL; }
}
else
{
static if(T.sizeof == (long).sizeof)
{
volatile asm { mov RDX,newval; }
asm { mov RAX,equalTo; }
asm { mov RCX,posVal; }
asm { lock; }
asm { cmpxchg[RCX],RDX; }
asm { setz AL; }
}
else
{
static assert(false,"Invalid template type specified: " ~ T.stringof);
}

}

}

}

}
}
}
else
{
    template atomicCAS(T)
{
bool atomicCAS(ref T val, T newval, T equalTo)
in
{
assert(atomicValueIsProperlyAligned!(T)(cast(size_t)&val));
}
body
{
synchronized(typeid(T)) {
if (val == equalTo)
{
val = newval;
return true;
}
}
return false;
}
}
}
}
}
template atomicLoad(T)
{
T atomicLoad(ref T val)
in
{
assert(atomicValueIsProperlyAligned!(T)(cast(size_t)&val));
static assert(T.sizeof <= size_t.sizeof,"invalid size for " ~ T.stringof);
}
body
{
volatile res = val;
return res;
}
}
template atomicStore(T)
{
T atomicStore(ref T val, T newVal)
in
{
assert(atomicValueIsProperlyAligned!(T)(cast(size_t)&val),"invalid alignment");
static assert(T.sizeof <= size_t.sizeof,"invalid size for " ~ T.stringof);
}
body
{
volatile newVal = val;
}
}
version (LDC)
{
    template atomicAdd(T)
{
T atomicAdd(ref T val, T inc)
{
static if(isPointerType!(T))
{
return cast(T)llvm_atomic_load_add!(size_t)(cast(size_t*)&val,inc);
}
else
{
static assert(isIntegerType!(T),"invalid type " ~ T.stringof);
return llvm_atomic_load_add!(T)(&val,cast(T)inc);
}

}
}
}
else
{
    version (D_InlineAsm_X86)
{
    template atomicAdd(T)
{
T atomicAdd(ref T val, T incV)
{
static assert(isIntegerType!(T) || isPointerType!(T),"invalid type: " ~ T.stringof);
T* posVal = &val;
T res;
static if(T.sizeof == 1)
{
volatile asm { mov DL,incV; }
asm { mov ECX,posVal; }
asm { lock; }
asm { xadd byte ptr[ECX],DL; }
asm { mov byte ptr res[EBP],DL; }
}
else
{
static if(T.sizeof == 2)
{
volatile asm { mov DX,incV; }
asm { mov ECX,posVal; }
asm { lock; }
asm { xadd short ptr[ECX],DX; }
asm { mov short ptr res[EBP],DX; }
}
else
{
static if(T.sizeof == 4)
{
volatile asm { mov EDX,incV; }
asm { mov ECX,posVal; }
asm { lock; }
asm { xadd int ptr[ECX],EDX; }
asm { mov int ptr res[EBP],EDX; }
}
else
{
static if(T.sizeof == 8)
{
return atomicOp(val, delegate(T x)
{
return x + inc;
}
);
}
else
{
static assert(0,"Unsupported type size");
}

}

}

}

return res;
}
}
}
else
{
    version (D_InlineAsm_X86_64)
{
    template atomicAdd(T)
{
T atomicAdd(ref T val, T incV)
{
static assert(isIntegerType!(T) || isPointerType!(T),"invalid type: " ~ T.stringof);
T* posVal = &val;
T res;
static if(T.sizeof == 1)
{
volatile asm { mov DL,incV; }
asm { mov RCX,posVal; }
asm { lock; }
asm { xadd byte ptr[RCX],DL; }
asm { mov byte ptr res[EBP],DL; }
}
else
{
static if(T.sizeof == 2)
{
volatile asm { mov DX,incV; }
asm { mov RCX,posVal; }
asm { lock; }
asm { xadd short ptr[RCX],DX; }
asm { mov short ptr res[EBP],DX; }
}
else
{
static if(T.sizeof == 4)
{
volatile asm { mov EDX,incV; }
asm { mov RCX,posVal; }
asm { lock; }
asm { xadd int ptr[RCX],EDX; }
asm { mov int ptr res[EBP],EDX; }
}
else
{
static if(T.sizeof == 8)
{
volatile asm { mov RAX,val; }
asm { mov RDX,incV; }
asm { lock; }
asm { xadd qword ptr[RAX],RDX; }
asm { mov res[EBP],RDX; }
}
else
{
static assert(0,"Unsupported type size for type:" ~ T.stringof);
}

}

}

}

return res;
}
}
}
else
{
    static if(LockVersion)
{
    template atomicAdd(T)
{
T atomicAdd(ref T val, T incV)
{
static assert(isIntegerType!(T) || isPointerType!(T),"invalid type: " ~ T.stringof);
synchronized(typeid(T)) {
T oldV = val;
val += incV;
return oldV;
}
}
}
}
else
{
    template atomicAdd(T)
{
T atomicAdd(ref T val, T incV)
{
static assert(isIntegerType!(T) || isPointerType!(T),"invalid type: " ~ T.stringof);
synchronized(typeid(T)) {
T oldV,newVal;
do
{
volatile oldV = val;
newV = oldV + incV;
}
while (!atomicCAS!(T)(val,newV,oldV))return oldV;
}
}
}
}
}
}
}
template atomicOp(T)
{
T atomicOp(ref T val, T delegate(T) f)
{
static assert(isIntegerType!(T) || isPointerType!(T));
T oldV,newV;
int i = 0;
bool success;
do
{
volatile oldV = val;
newV = f(oldV);
success = atomicCAS!(T)(val,newV,oldV);
}
while (!success && (i += 1) < 200)while (!success)
{
thread_yield();
volatile oldV = val;
newV = f(oldV);
success = atomicCAS!(T)(val,newV,oldV);
}
return oldV;
}
}
enum 
{
strictFences = false,
}
template flagGet(T)
{
T flagGet(ref T flag)
{
T res;
volatile res = flag;
memoryBarrier!(true,false,strictFences,false)();
return res;
}
}
template flagSet(T)
{
T flagSet(ref T flag, T newVal)
{
memoryBarrier!(false,strictFences,false,true)();
return atomicSwap(flag,newVal);
}
}
template flagOp(T)
{
T flagOp(ref T flag, T delegate(T) op)
{
memoryBarrier!(false,strictFences,false,true)();
return atomicOp(flag,op);
}
}
template flagAdd(T)
{
T flagAdd(ref T flag, T incV = cast(T)1)
{
static if(!LockVersion)
{
memoryBarrier!(false,strictFences,false,true)();
}

return atomicAdd(flag,incV);
}
}
template nextValue(T)
{
T nextValue(ref T val)
{
return atomicAdd(flag,cast(T)1);
}
}
