; ; Implementation of atomic functions for 64 bit Visual C++. Visual C++ does not ; support inline assembler with this target and the compiler intrinsics are ; unfortunately insufficient. Thus, complete functions must be written in ; assembler. ; ; The calling convention on AMD64 simplifies things a lot. There is no need to ; perform complex stack setup for these functions. Registers may be used as ; follows (registers not listed must be preserved - see MSDN on details): ; ; RAX - scratch register, return value ; RBX - must be preserved ; RCX - first argument (if single value or pointer), scratch register ; RDX - second argument (same as RCX), scratch register ; R8 - third argument (same as RCX), scratch register ; R9 - fourth argument (same as RCX), scratch register ; R10 - scratch register (may be used in syscall) ; R11 - scratch register (may be used in syscall) ; XMM0 - first floating point argument, scratch register ; XMM1 - second floating point argument, scratch register ; XMM2 - third floating point argument, scratch register ; XMM3 - fourth floating point register, scratch register ; XMM4 - scratch regsiter ; XMM5 - scratch register ; ; Some of the functions here do not need to distinguish between signed ; and unsigned variables. But since C++ is picky about signed/unsigned ; conversions we cheat by giving the same function multiple names with ; multiple signatures. The syntax for this is quite awkward, however. .code ; char gltb_atomicIncByte(char *variable) gltb_atomicIncByte proc public gltb_atomicIncUByte gltb_atomicIncUByte:: mov al, 1 lock xadd [rcx], al ret gltb_atomicIncByte endp ; short gltb_atomicIncShort(short *variable) ; unsigned short gltb_atomicIncUShort(unsigned short *variable) gltb_atomicIncShort proc public gltb_atomicIncUShort gltb_atomicIncUShort:: mov ax, 1 lock xadd [rcx], ax ret gltb_atomicIncShort endp ; int gltb_atomicIncInt(int *variable) ; unsigned int gltb_atomicIncUInt(unsigned int *variable) gltb_atomicIncInt proc public gltb_atomicIncUInt gltb_atomicIncUInt:: mov eax, 1 lock xadd [rcx], eax ret gltb_atomicIncInt endp ; long long gltb_atomicIncLong(long long *variable) ; unsigned long long gltb_atomicIncULong(unsigned long long *variable) gltb_atomicIncLong proc public gltb_atomicIncULong gltb_atomicIncULong:: mov rax, 1 lock xadd [rcx], rax ret gltb_atomicIncLong endp ; char gltb_atomicAddByte(char *variable, char value) gltb_atomicAddByte proc public gltb_atomicAddUByte gltb_atomicAddUByte:: lock xadd [rcx], dl mov al, dl ret gltb_atomicAddByte endp ; short gltb_atomicAddShort(short *variable, short value) ; unsigned short gltb_atomicAddUShort(unsigned short *variable, unsigned short value) gltb_atomicAddShort proc public gltb_atomicAddUShort gltb_atomicAddUShort:: lock xadd [rcx], dx mov ax, dx ret gltb_atomicAddShort endp ; int gltb_atomicAddInt(int *variable, int value) ; unsigned int gltb_atomicAddUInt(unsigned int *variable, unsigned int value) gltb_atomicAddInt proc public gltb_atomicAddUInt gltb_atomicAddUInt:: lock xadd [rcx], edx mov eax, edx ret gltb_atomicAddInt endp ; long long gltb_atomicIncLong(long long *variable, long long value) ; unsigned long long gltb_atomicIncULong(unsigned long long *variable, unsigned long long value) gltb_atomicAddLong proc public gltb_atomicAddULong gltb_atomicAddULong:: lock xadd [rcx], rdx mov rax, rdx ret gltb_atomicAddLong endp ; char gltb_atomicCASByte(char *value, char newValue, char oldValue) ; NOTE order of arguments - saves a MOV instruction gltb_atomicCASByte proc public gltb_atomicCASUByte gltb_atomicCASUByte:: mov rax, r8 lock cmpxchg [rcx], dl ret gltb_atomicCASByte endp ; short gltb_atomicCASShort(short *value, short newValue, short oldValue) ; unsigned short gltb_atomicCASShort(unsigned short *value, unsigned short newValue, unsigned short oldValue) ; NOTE order of arguments - saves a MOV instruction gltb_atomicCASShort proc public gltb_atomicCASUShort gltb_atomicCASUShort:: mov rax, r8 lock cmpxchg [rcx], dx ret gltb_atomicCASShort endp ; int gltb_atomicCASInt(int *value, int newValue, int oldValue) ; unsigned int gltb_atomicCASUInt(unsigned int *value, unsigned int newValue, unsigned int oldValue) ; NOTE order of arguments - saves a MOV instruction gltb_atomicCASInt proc public gltb_atomicCASUInt gltb_atomicCASUInt:: mov rax, r8 lock cmpxchg [rcx], edx ret gltb_atomicCASInt endp ; long long gltb_atomicCASLong(long long *value, long long newValue, long long oldValue) ; unsigned long long gltb_atomicCASLong(unsigned long long *value, unsigned long long newValue, unsigned long long oldValue) ; NOTE order of arguments - saves a MOV instruction gltb_atomicCASLong proc public gltb_atomicCASULong gltb_atomicCASULong:: mov rax, r8 lock cmpxchg [rcx], rdx ret gltb_atomicCASLong endp ; char gltb_atomicDecByte(char *variable) gltb_atomicDecByte proc public gltb_atomicDecUByte gltb_atomicDecUByte:: mov al, 0FFh lock xadd [rcx], al ret gltb_atomicDecByte endp ; short gltb_atomicDecShort(short *variable) ; unsigned short gltb_atomicDecUShort(unsigned short *variable) gltb_atomicDecShort proc public gltb_atomicDecUShort gltb_atomicDecUShort:: mov ax, 0FFFFh lock xadd [rcx], ax ret gltb_atomicDecShort endp ; int gltb_atomicDecInt(int *variable) ; unsigned int gltb_atomicDecUInt(unsigned int *variable) gltb_atomicDecInt proc public gltb_atomicDecUInt gltb_AtomicDecUInt:: mov eax, 0FFFFFFFFh lock xadd [rcx], eax ret gltb_atomicDecInt endp ; long long gltb_atomicDecLong(long long *variable) ; unsigned long long gltb_atomicDecULong(unsigned long long *variable) gltb_atomicDecLong proc public gltb_atomicDecULong gltb_atomicDecULong:: mov rax, 0FFFFFFFFFFFFFFFFh lock xadd [rcx], rax ret gltb_atomicDecLong endp ; char gltb_atomicSubByte(char *variable, char value) gltb_atomicSubByte proc public gltb_atomicSubUByte gltb_atomicSubUByte:: neg dl lock xadd [rcx], dl mov al, dl ret gltb_atomicSubByte endp ; short gltb_atomicSubShort(short *variable, short value) ; unsigned short gltb_atomicSubUShort(unsigned short *variable, unsigned short value) gltb_atomicSubShort proc public gltb_atomicSubUShort gltb_atomicSubUShort:: neg dx lock xadd [rcx], dx mov ax, dx ret gltb_atomicSubShort endp ; int gltb_atomicSubInt(int *variable, int value) ; unsigned int gltb_atomicSubInt(unsigned int *variable, unsigned int value) gltb_atomicSubInt proc public gltb_atomicSubUInt gltb_atomicSubUInt:: neg edx lock xadd [rcx], edx mov eax, edx ret gltb_atomicSubInt endp ; long long gltb_atomicSubLong(long long *variable, long long value) ; unsigned long long gltb_atomicSubLong(unsigned long long *variable, unsigned long long value) gltb_atomicSubLong proc public gltb_atomicSubULong gltb_atomicSubULong:: neg rdx lock xadd [rcx], rdx mov rax, rdx ret gltb_atomicSubLong endp ; char gltb_atomicAndByte(char *variable, char value) gltb_atomicAndByte proc public gltb_atomicAndUByte gltb_atomicAndUByte:: mov al, [rcx] L1: mov r8b, dl and r8b, al lock cmpxchg [rcx], r8b jnz L1 ret gltb_atomicAndByte endp ; short gltb_atomicAndShort(short *variable, short value) ; unsigned short gltb_atomicAndUShort(unsigned short *variable, unsigned short value) gltb_atomicAndShort proc public gltb_atomicAndUShort gltb_atomicAndUShort:: mov ax, [rcx] L1: mov r8w, dx and r8w, ax lock cmpxchg [rcx], r8w jnz L1 ret gltb_atomicAndShort endp ; int gltb_atomicAndInt(int *variable, int value) ; unsigned int gltb_atomicAndUInt(unsigned int *variable, unsigned int value) gltb_atomicAndInt proc public gltb_atomicAndUInt gltb_atomicAndUInt:: mov eax, [rcx] L1: mov r8d, edx and r8d, eax lock cmpxchg [rcx], r8d jnz L1 ret gltb_atomicAndInt endp ; long long gltb_atomicAndLong(long long *variable, long long value) ; unsigned long long gltb_atomicAndULong(unsigned long long *variable, unsigned long long value) gltb_atomicAndLong proc public gltb_atomicAndULong gltb_atomicAndULong:: mov rax, [rcx] L1: mov r8, rdx and r8, rax lock cmpxchg [rcx], r8 jnz L1 ret gltb_atomicAndLong endp ; char gltb_atomicOrByte(char *variable, char value) gltb_atomicOrByte proc public gltb_atomicOrUByte gltb_atomicOrUByte:: mov al, [rcx] L1: mov r8b, dl or r8b, al lock cmpxchg [rcx], r8b jnz L1 ret gltb_atomicOrByte endp ; short gltb_atomicOrShort(short *variable, short value) ; unsigned short gltb_atomicOrUShort(unsigned short *variable, unsigned short value) gltb_atomicOrShort proc public gltb_atomicOrUShort gltb_atomicOrUShort:: mov ax, [rcx] L1: mov r8w, dx or r8w, ax lock cmpxchg [rcx], r8w jnz L1 ret gltb_atomicOrShort endp ; int gltb_atomicOrInt(int *variable, int value) ; unsigned int gltb_atomicOrUInt(unsigned int *variable, unsigned int value) gltb_atomicOrInt proc public gltb_atomicOrUInt gltb_atomicOrUInt:: mov eax, [rcx] L1: mov r8d, edx or r8d, eax lock cmpxchg [rcx], r8d jnz L1 ret gltb_atomicOrInt endp ; long long gltb_atomicOrLong(long long *variable, long long value) ; unsigned long long gltb_atomicOrULong(unsigned long long *variable, unsigned long long value) gltb_atomicOrLong proc public gltb_atomicOrULong gltb_atomicOrULong:: mov rax, [rcx] L1: mov r8, rdx or r8, rax lock cmpxchg [rcx], r8 jnz L1 ret gltb_atomicOrLong endp ; char gltb_atomicNAndByte(char *variable, char value) gltb_atomicNAndByte proc public gltb_atomicNAndUByte gltb_atomicNAndUByte:: mov al, [rcx] L1: mov r8b, dl and r8b, al not r8b lock cmpxchg [rcx], r8b jnz L1 ret gltb_atomicNAndByte endp ; short gltb_atomicNAndShort(short *variable, short value) ; unsigned short gltb_atomicNAndUShort(unsigned short *variable, unsigned short value) gltb_atomicNAndShort proc public gltb_atomicNAndUShort gltb_atomicNAndUShort:: mov ax, [rcx] L1: mov r8w, dx and r8w, ax not r8w lock cmpxchg [rcx], r8w jnz L1 ret gltb_atomicNAndShort endp ; int gltb_atomicNAndInt(int *variable, int value) ; unsigned int gltb_atomicNAndUInt(unsigned int *variable, unsigned int value) gltb_atomicNAndInt proc public gltb_atomicNAndUInt gltb_atomicNAndUInt:: mov eax, [rcx] L1: mov r8d, edx and r8d, eax not r8d lock cmpxchg [rcx], r8d jnz L1 ret gltb_atomicNAndInt endp ; long long gltb_atomicNAndLong(long long *variable, long long value) ; unsigned long long gltb_atomicNAndULong(unsigned long long *variable, unsigned long long value) gltb_atomicNAndLong proc public gltb_atomicNAndULong gltb_atomicNAndULong:: mov rax, [rcx] L1: mov r8, rdx and r8, rax not r8 lock cmpxchg [rcx], r8 jnz L1 ret gltb_atomicNAndLong endp ; char gltb_atomicXOrByte(char *variable, char value) gltb_atomicXOrByte proc public gltb_atomicXOrUByte gltb_atomicXOrUByte:: mov al, [rcx] L1: mov r8b, dl xor r8b, al lock cmpxchg [rcx], r8b jnz L1 ret gltb_atomicXOrByte endp ; short gltb_atomicXOrShort(short *variable, short value) ; unsigned short gltb_atomicXOrUShort(unsigned short *variable, unsigned short value) gltb_atomicXOrShort proc public gltb_atomicXOrUShort gltb_atomicXOrUShort:: mov ax, [rcx] L1: mov r8w, dx xor r8w, ax lock cmpxchg [rcx], r8w jnz L1 ret gltb_atomicXOrShort endp ; int gltb_atomicXOrInt(int *variable, int value) ; unsigned int gltb_atomicXOrUInt(unsigned int *variable, unsigned int value) gltb_atomicXOrInt proc public gltb_atomicXOrUInt gltb_atomicXOrUInt:: mov eax, [rcx] L1: mov r8d, edx xor r8d, eax lock cmpxchg [rcx], r8d jnz L1 ret gltb_atomicXOrInt endp ; long long gltb_atomicXOrLong(long long *variable, long long value) ; unsigned long long gltb_atomicXOrULong(unsigned long long *variable, unsigned long long value) gltb_atomicXOrLong proc public gltb_atomicXOrULong gltb_atomicXOrULong:: mov rax, [rcx] L1: mov r8, rdx xor r8, rax lock cmpxchg [rcx], r8 jnz L1 ret gltb_atomicXOrLong endp end