// D import file generated from '../../../../gcc-4.6.1/libphobos/core/atomic.d'
module core.atomic;
version (D_InlineAsm_X86)
{
    version = AsmX86;
    version = AsmX86_32;
    enum has64BitCAS = true;
}
else
{
    version (D_InlineAsm_X86_64)
{
    version = AsmX86;
    version = AsmX86_64;
    enum has64BitCAS = true;
}
else
{
    version (GNU)
{
    enum has64BitCAS = false;
}
}
}
private template HeadUnshared(T)
{
static if(is(T U : shared(U*)))
{
    alias shared(U)* HeadUnshared;
}
else
{
    alias T HeadUnshared;
}
}

version (D_Ddoc)
{
    template atomicOp(string op,T,V1) if (__traits(compiles,mixin("val" ~ op ~ "mod")))
{
HeadUnshared!(T) atomicOp(ref shared T val, V1 mod)
{
return HeadUnshared!(T).init;
}
}
    template cas(T,V1,V2) if (__traits(compiles,mixin("*here = writeThis")))
{
bool cas(shared(T)* here, const V1 ifThis, const V2 writeThis)
{
return false;
}
}
    template atomicLoad(msync ms = msync.seq,T)
{
HeadUnshared!(T) atomicLoad(ref const shared T val)
{
return HeadUnshared!(T).init;
}
}
    template atomicStore(msync ms = msync.seq,T,V1) if (__traits(compiles,mixin("val = newval")))
{
void atomicStore(ref shared T val, V1 newval)
{
}
}
    enum msync 
{
raw,
acq,
rel,
seq,
}
}
else
{
    version (AsmX86_32)
{
    template atomicOp(string op,T,V1) if (__traits(compiles,mixin("val" ~ op ~ "mod")))
{
HeadUnshared!(T) atomicOp(ref shared T val, V1 mod)
in
{
}
body
{
static if(op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op == "^^" || op == "&" || op == "|" || op == "^" || op == "<<" || op == ">>" || op == ">>>" || op == "~" || op == "==" || op == "!=" || op == "<" || op == "<=" || op == ">" || op == ">=")
{
HeadUnshared!(T) get = atomicLoad!(msync.raw)(val);
mixin("return get " ~ op ~ " mod;");
}
else
{
static if(op == "+=" || op == "-=" || op == "*=" || op == "/=" || op == "%=" || op == "^^=" || op == "&=" || op == "|=" || op == "^=" || op == "<<=" || op == ">>=" || op == ">>>=")
{
HeadUnshared!(T) get,set;
do
{
get = (set = atomicLoad!(msync.raw)(val));
mixin("set " ~ op ~ " mod;");
}
while (!cas(&val,get,set));
return set;
}
else
{
static assert(false,"Operation not supported.");
}

}

}
}
    template cas(T,V1,V2) if (__traits(compiles,mixin("*here = writeThis")))
{
bool cas(shared(T)* here, const V1 ifThis, const V2 writeThis)
in
{
}
body
{
static if(T.sizeof == (byte).sizeof)
{
asm { mov DL,writeThis; }
asm { mov AL,ifThis; }
asm { mov ECX,here; }
asm { lock; }
asm { cmpxchg[ECX],DL; }
asm { setz AL; }
}
else
{
static if(T.sizeof == (short).sizeof)
{
asm { mov DX,writeThis; }
asm { mov AX,ifThis; }
asm { mov ECX,here; }
asm { lock; }
asm { cmpxchg[ECX],DX; }
asm { setz AL; }
}
else
{
static if(T.sizeof == (int).sizeof)
{
asm { mov EDX,writeThis; }
asm { mov EAX,ifThis; }
asm { mov ECX,here; }
asm { lock; }
asm { cmpxchg[ECX],EDX; }
asm { setz AL; }
}
else
{
static if(T.sizeof == (long).sizeof && has64BitCAS)
{
asm { push EDI; }
asm { push EBX; }
asm { lea EDI,writeThis; }
asm { mov EBX,[EDI]; }
asm { mov ECX,4[EDI]; }
asm { lea EDI,ifThis; }
asm { mov EAX,[EDI]; }
asm { mov EDX,4[EDI]; }
asm { mov EDI,here; }
asm { lock; }
asm { cmpxchg8b[EDI]; }
asm { setz AL; }
asm { pop EBX; }
asm { pop EDI; }
}
else
{
static assert(false,"Invalid template type specified.");
}

}

}

}

}
}
    enum msync 
{
raw,
acq,
rel,
seq,
}
    private 
{
    template isHoistOp(msync ms)
{
enum bool isHoistOp = ms == msync.acq || ms == msync.seq;
}
    template isSinkOp(msync ms)
{
enum bool isSinkOp = ms == msync.rel || ms == msync.seq;
}
    template needsLoadBarrier(msync ms)
{
const bool needsLoadBarrier = ms != msync.raw;

}
    template needsStoreBarrier(msync ms)
{
const bool needsStoreBarrier = ms == msync.seq || isHoistOp!(ms);

}
}
    template atomicLoad(msync ms = msync.seq,T) if (!__traits(isFloating,T))
{
HeadUnshared!(T) atomicLoad(ref const shared T val)
{
static if(T.sizeof == (byte).sizeof)
{
static if(needsLoadBarrier!(ms))
{
asm { mov DL,0; }
asm { mov AL,0; }
asm { mov ECX,val; }
asm { lock; }
asm { cmpxchg[ECX],DL; }
}
else
{
asm { mov EAX,val; }
asm { mov AL,[EAX]; }
}

}
else
{
static if(T.sizeof == (short).sizeof)
{
static if(needsLoadBarrier!(ms))
{
asm { mov DX,0; }
asm { mov AX,0; }
asm { mov ECX,val; }
asm { lock; }
asm { cmpxchg[ECX],DX; }
}
else
{
asm { mov EAX,val; }
asm { mov AX,[EAX]; }
}

}
else
{
static if(T.sizeof == (int).sizeof)
{
static if(needsLoadBarrier!(ms))
{
asm { mov EDX,0; }
asm { mov EAX,0; }
asm { mov ECX,val; }
asm { lock; }
asm { cmpxchg[ECX],EDX; }
}
else
{
asm { mov EAX,val; }
asm { mov EAX,[EAX]; }
}

}
else
{
static if(T.sizeof == (long).sizeof && has64BitCAS)
{
asm { push EDI; }
asm { push EBX; }
asm { mov EBX,0; }
asm { mov ECX,0; }
asm { mov EAX,0; }
asm { mov EDX,0; }
asm { mov EDI,val; }
asm { lock; }
asm { cmpxchg8b[EDI]; }
asm { pop EBX; }
asm { pop EDI; }
}
else
{
static assert(false,"Invalid template type specified.");
}

}

}

}

}
}
    template atomicStore(msync ms = msync.seq,T,V1) if (__traits(compiles,mixin("val = newval")))
{
void atomicStore(ref shared T val, V1 newval)
{
static if(T.sizeof == (byte).sizeof)
{
static if(needsStoreBarrier!(ms))
{
asm { mov EAX,val; }
asm { mov DL,newval; }
asm { lock; }
asm { xchg[EAX],DL; }
}
else
{
asm { mov EAX,val; }
asm { mov DL,newval; }
asm { mov[EAX],DL; }
}

}
else
{
static if(T.sizeof == (short).sizeof)
{
static if(needsStoreBarrier!(ms))
{
asm { mov EAX,val; }
asm { mov DX,newval; }
asm { lock; }
asm { xchg[EAX],DX; }
}
else
{
asm { mov EAX,val; }
asm { mov DX,newval; }
asm { mov[EAX],DX; }
}

}
else
{
static if(T.sizeof == (int).sizeof)
{
static if(needsStoreBarrier!(ms))
{
asm { mov EAX,val; }
asm { mov EDX,newval; }
asm { lock; }
asm { xchg[EAX],EDX; }
}
else
{
asm { mov EAX,val; }
asm { mov EDX,newval; }
asm { mov[EAX],EDX; }
}

}
else
{
static if(T.sizeof == (long).sizeof && has64BitCAS)
{
asm { push EDI; }
asm { push EBX; }
asm { lea EDI,newval; }
asm { mov EBX,[EDI]; }
asm { mov ECX,4[EDI]; }
asm { mov EDI,val; }
asm { mov EAX,[EDI]; }
asm { mov EDX,4[EDI]; }
L1:
asm { lock; }
asm { cmpxchg8b[EDI]; }
asm { jne L1; }
asm { pop EBX; }
asm { pop EDI; }
}
else
{
static assert(false,"Invalid template type specified.");
}

}

}

}

}
}
}
else
{
    version (AsmX86_64)
{
    template atomicOp(string op,T,V1) if (__traits(compiles,mixin("val" ~ op ~ "mod")))
{
HeadUnshared!(T) atomicOp(ref shared T val, V1 mod)
in
{
}
body
{
static if(op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op == "^^" || op == "&" || op == "|" || op == "^" || op == "<<" || op == ">>" || op == ">>>" || op == "~" || op == "==" || op == "!=" || op == "<" || op == "<=" || op == ">" || op == ">=")
{
HeadUnshared!(T) get = atomicLoad!(msync.raw)(val);
mixin("return get " ~ op ~ " mod;");
}
else
{
static if(op == "+=" || op == "-=" || op == "*=" || op == "/=" || op == "%=" || op == "^^=" || op == "&=" || op == "|=" || op == "^=" || op == "<<=" || op == ">>=" || op == ">>>=")
{
HeadUnshared!(T) get,set;
do
{
get = (set = atomicLoad!(msync.raw)(val));
mixin("set " ~ op ~ " mod;");
}
while (!cas(&val,get,set));
return set;
}
else
{
static assert(false,"Operation not supported.");
}

}

}
}
    template cas(T,V1,V2) if (__traits(compiles,mixin("*here = writeThis")))
{
bool cas(shared(T)* here, const V1 ifThis, const V2 writeThis)
in
{
}
body
{
static if(T.sizeof == (byte).sizeof)
{
asm { mov DL,writeThis; }
asm { mov AL,ifThis; }
asm { mov RCX,here; }
asm { lock; }
asm { cmpxchg[RCX],DL; }
asm { setz AL; }
}
else
{
static if(T.sizeof == (short).sizeof)
{
asm { mov DX,writeThis; }
asm { mov AX,ifThis; }
asm { mov RCX,here; }
asm { lock; }
asm { cmpxchg[RCX],DX; }
asm { setz AL; }
}
else
{
static if(T.sizeof == (int).sizeof)
{
asm { mov EDX,writeThis; }
asm { mov EAX,ifThis; }
asm { mov RCX,here; }
asm { lock; }
asm { cmpxchg[RCX],EDX; }
asm { setz AL; }
}
else
{
static if(T.sizeof == (long).sizeof)
{
asm { mov RDX,writeThis; }
asm { mov RAX,ifThis; }
asm { mov RCX,here; }
asm { lock; }
asm { cmpxchg[RCX],RDX; }
asm { setz AL; }
}
else
{
static assert(false,"Invalid template type specified.");
}

}

}

}

}
}
    enum msync 
{
raw,
acq,
rel,
seq,
}
    private 
{
    template isHoistOp(msync ms)
{
enum bool isHoistOp = ms == msync.acq || ms == msync.seq;
}
    template isSinkOp(msync ms)
{
enum bool isSinkOp = ms == msync.rel || ms == msync.seq;
}
    template needsLoadBarrier(msync ms)
{
const bool needsLoadBarrier = ms != msync.raw;

}
    template needsStoreBarrier(msync ms)
{
const bool needsStoreBarrier = ms == msync.seq || isHoistOp!(ms);

}
}
    template atomicLoad(msync ms = msync.seq,T) if (!__traits(isFloating,T))
{
HeadUnshared!(T) atomicLoad(ref const shared T val)
{
static if(T.sizeof == (byte).sizeof)
{
static if(needsLoadBarrier!(ms))
{
asm { mov DL,0; }
asm { mov AL,0; }
asm { mov RCX,val; }
asm { lock; }
asm { cmpxchg[RCX],DL; }
}
else
{
asm { mov RAX,val; }
asm { mov AL,[RAX]; }
}

}
else
{
static if(T.sizeof == (short).sizeof)
{
static if(needsLoadBarrier!(ms))
{
asm { mov DX,0; }
asm { mov AX,0; }
asm { mov RCX,val; }
asm { lock; }
asm { cmpxchg[RCX],DX; }
}
else
{
asm { mov RAX,val; }
asm { mov AX,[RAX]; }
}

}
else
{
static if(T.sizeof == (int).sizeof)
{
static if(needsLoadBarrier!(ms))
{
asm { mov EDX,0; }
asm { mov EAX,0; }
asm { mov RCX,val; }
asm { lock; }
asm { cmpxchg[RCX],EDX; }
}
else
{
asm { mov RAX,val; }
asm { mov EAX,[RAX]; }
}

}
else
{
static if(T.sizeof == (long).sizeof)
{
static if(needsLoadBarrier!(ms))
{
asm { mov RDX,0; }
asm { mov RAX,0; }
asm { mov RCX,val; }
asm { lock; }
asm { cmpxchg[RCX],RDX; }
}
else
{
asm { mov RAX,val; }
asm { mov RAX,[RAX]; }
}

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

}

}

}

}
}
    template atomicStore(msync ms = msync.seq,T,V1) if (__traits(compiles,mixin("val = newval")))
{
void atomicStore(ref shared T val, V1 newval)
{
static if(T.sizeof == (byte).sizeof)
{
static if(needsStoreBarrier!(ms))
{
asm { mov RAX,val; }
asm { mov DL,newval; }
asm { lock; }
asm { xchg[RAX],DL; }
}
else
{
asm { mov RAX,val; }
asm { mov DL,newval; }
asm { mov[RAX],DL; }
}

}
else
{
static if(T.sizeof == (short).sizeof)
{
static if(needsStoreBarrier!(ms))
{
asm { mov RAX,val; }
asm { mov DX,newval; }
asm { lock; }
asm { xchg[RAX],DX; }
}
else
{
asm { mov RAX,val; }
asm { mov DX,newval; }
asm { mov[RAX],DX; }
}

}
else
{
static if(T.sizeof == (int).sizeof)
{
static if(needsStoreBarrier!(ms))
{
asm { mov RAX,val; }
asm { mov EDX,newval; }
asm { lock; }
asm { xchg[RAX],EDX; }
}
else
{
asm { mov RAX,val; }
asm { mov EDX,newval; }
asm { mov[RAX],EDX; }
}

}
else
{
static if(T.sizeof == (long).sizeof && has64BitCAS)
{
static if(needsStoreBarrier!(ms))
{
asm { mov RAX,val; }
asm { mov RDX,newval; }
asm { lock; }
asm { xchg[RAX],RDX; }
}
else
{
asm { mov RAX,val; }
asm { mov RDX,newval; }
asm { mov[RAX],RDX; }
}

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

}

}

}

}
}
}
else
{
    version (GNU)
{
    import gcc.atomics;
    import gcc.builtins;
    template atomicOp(string op,T,V1) if (__traits(compiles,mixin("val" ~ op ~ "mod")))
{
HeadUnshared!(T) atomicOp(ref shared T val, V1 mod)
{
static if(op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op == "^^" || op == "&" || op == "|" || op == "^" || op == "<<" || op == ">>" || op == ">>>" || op == "~" || op == "==" || op == "!=" || op == "<" || op == "<=" || op == ">" || op == ">=")
{
HeadUnshared!(T) get = atomicLoad!(msync.raw)(val);
mixin("return get " ~ op ~ " mod;");
}
else
{
static if(op == "+=" || op == "-=" || op == "*=" || op == "/=" || op == "%=" || op == "^^=" || op == "&=" || op == "|=" || op == "^=" || op == "<<=" || op == ">>=" || op == ">>>=")
{
HeadUnshared!(T) get,set;
do
{
get = (set = atomicLoad!(msync.raw)(val));
mixin("set " ~ op ~ " mod;");
}
while (!cas(&val,get,set));
return set;
}
else
{
static assert(false,"Operation not supported.");
}

}

}
}
    template cas(T,V1,V2) if (__traits(compiles,mixin("*here = writeThis")))
{
bool cas(shared(T)* here, const V1 ifThis, const V2 writeThis)
{
version (GNU_Need_Atomics)
{
synchronized {
if (*here == ifThis)
{
if ((*here = writeThis) == writeThis)
return true;
}
return false;
}
}
else
{
return __sync_bool_compare_and_swap!(T)(here,ifThis,writeThis);
}

}
}
    enum msync 
{
raw,
acq,
rel,
seq,
}
    private 
{
    template isHoistOp(msync ms)
{
enum bool isHoistOp = ms == msync.acq || ms == msync.seq;
}
    template isSinkOp(msync ms)
{
enum bool isSinkOp = ms == msync.rel || ms == msync.seq;
}
    template needsLoadBarrier(msync ms)
{
const bool needsLoadBarrier = ms != msync.raw;

}
    template needsStoreBarrier(msync ms)
{
const bool needsStoreBarrier = ms == msync.seq || isHoistOp!(ms);

}
}
    template atomicLoad(msync ms = msync.seq,T)
{
HeadUnshared!(T) atomicLoad(ref const shared T val)
{
alias HeadUnshared!(T) S;
version (GNU_Need_Atomics)
{
static if(needsLoadBarrier!(ms))
{
synchronized return cast(S)val;
}
else
{
return cast(S)val;
}

}
else
{
static if(needsLoadBarrier!(ms))
{
__sync_synchronize();
}

return cast(S)val;
}

}
}
    template atomicStore(msync ms = msync.seq,T,V1) if (__traits(compiles,mixin("val = newval")))
{
void atomicStore(ref shared T val, V1 newval)
{
version (GNU_Need_Atomics)
{
static if(needsStoreBarrier!(ms))
{
synchronized val = newval;
}
else
{
val = newval;
}

}
else
{
static if(needsLoadBarrier!(ms))
{
__sync_synchronize();
}

val = newval;
}

}
}
}
}
}
}
template atomicLoad(msync ms = msync.seq,T) if (__traits(isFloating,T))
{
HeadUnshared!(T) atomicLoad(ref const shared T val)
{
static if(T.sizeof == (int).sizeof)
{
static assert(is(T : float));
auto ptr = cast(int*)&val;
auto asInt = atomicLoad!(ms)(*ptr);
return *cast(typeof(return)*)&asInt;
}
else
{
static if(T.sizeof == (long).sizeof)
{
static assert(is(T : double));
auto ptr = cast(long*)&val;
auto asLong = atomicLoad!(ms)(*ptr);
return *cast(typeof(return)*)&asLong;
}
else
{
static assert(0,"Cannot atomically load 80-bit reals.");
}

}

}
}
version (unittest)
{
    template testCAS(T)
{
void testCAS(T val = T.init + 1)
{
T base = cast(T)0;
shared(T) atom = cast(T)0;
assert(base != val,T.stringof);
assert(atom == base,T.stringof);
assert(cas(&atom,base,val),T.stringof);
assert(atom == val,T.stringof);
assert(!cas(&atom,base,base),T.stringof);
assert(atom == val,T.stringof);
}
}
    template testLoadStore(msync ms = msync.seq,T)
{
void testLoadStore(T val = T.init + 1)
{
T base = cast(T)0;
shared(T) atom = cast(T)0;
assert(base != val);
assert(atom == base);
atomicStore!(ms)(atom,val);
base = atomicLoad!(ms)(atom);
assert(base == val,T.stringof);
assert(atom == val);
}
}
    template testType(T)
{
void testType(T val = T.init + 1)
{
static if(!is(T U : U*))
{
testCAS!(T)(val);
}

testLoadStore!(msync.seq,T)(val);
testLoadStore!(msync.raw,T)(val);
}
}
    }
