Browse Source

+ add platform independent helper routines for the atomic intrinsics; these only require the implementation of the size specific fpc_atomic_cmp_xhg_* helper, but if only the CPU size specific helper is implemented the others will at least be safe for multi threading inside the same process

Sven/Sarah Barth 2 years ago
parent
commit
9cbc802d0d
2 changed files with 625 additions and 2 deletions
  1. 31 1
      rtl/inc/compproc.inc
  2. 594 1
      rtl/inc/generic.inc

+ 31 - 1
rtl/inc/compproc.inc

@@ -646,12 +646,42 @@ procedure fpc_rol_assign_int64(var AValue : int64;const Dist : Byte);compilerpro
 procedure fpc_rol_assign_qword(var AValue : QWord;const Dist : Byte);compilerproc;
 {$endif FPC_HAS_INTERNAL_ROX_ASSIGN_QWORD}
 
-
 function fpc_popcnt_byte(AValue : Byte): Byte;compilerproc;
 function fpc_popcnt_word(AValue : Word): Word;compilerproc;
 function fpc_popcnt_dword(AValue : DWord): DWord;compilerproc;
 function fpc_popcnt_qword(AValue : QWord): QWord;compilerproc;
 
+{$if not defined(VER3_2) and not defined(CPUJVM)}
+function fpc_atomic_inc_8(var Target: shortint): shortint;compilerproc;
+function fpc_atomic_inc_16(var Target: smallint): smallint;compilerproc;
+function fpc_atomic_inc_32(var Target: longint): longint;compilerproc;
+function fpc_atomic_inc_64(var Target: int64): int64;compilerproc;
+
+function fpc_atomic_dec_8(var Target: shortint): shortint;compilerproc;
+function fpc_atomic_dec_16(var Target: smallint): smallint;compilerproc;
+function fpc_atomic_dec_32(var Target: longint): longint;compilerproc;
+function fpc_atomic_dec_64(var Target: int64): int64;compilerproc;
+
+function fpc_atomic_add_8(var Target: shortint; Value: shortint): shortint;compilerproc;
+function fpc_atomic_add_16(var Target: smallint; Value: smallint): smallint;compilerproc;
+function fpc_atomic_add_32(var Target: longint; Value: longint): longint;compilerproc;
+function fpc_atomic_add_64(var Target: int64; Value: int64): int64;compilerproc;
+
+function fpc_atomic_sub_8(var Target: shortint; Value: shortint): shortint;compilerproc;
+function fpc_atomic_sub_16(var Target: smallint; Value: smallint): smallint;compilerproc;
+function fpc_atomic_sub_32(var Target: longint; Value: longint): longint;compilerproc;
+function fpc_atomic_sub_64(var Target: int64; Value: int64): int64;compilerproc;
+
+function fpc_atomic_xchg_8(var Target: shortint; Source: shortint): shortint;compilerproc;
+function fpc_atomic_xchg_16(var Target: smallint; Source: smallint): smallint;compilerproc;
+function fpc_atomic_xchg_32(var Target: longint; Source: longint): longint;compilerproc;
+function fpc_atomic_xchg_64(var Target: int64; Source: int64): int64;compilerproc;
+
+function fpc_atomic_cmp_xchg_8(var Target: shortint; NewValue: shortint; Comparand: shortint): shortint;compilerproc;
+function fpc_atomic_cmp_xchg_16(var Target: smallint; NewValue: smallint; Comparand: smallint): smallint;compilerproc;
+function fpc_atomic_cmp_xchg_32(var Target: longint; NewValue: longint; Comparand: longint): longint;compilerproc;
+function fpc_atomic_cmp_xchg_64(var Target: int64; NewValue: int64; Comparand: int64): int64;compilerproc;
+{$endif VER3_2}
 
 {$ifndef FPUNONE}
 function fpc_abs_real(d : ValReal) : ValReal;compilerproc;

+ 594 - 1
rtl/inc/generic.inc

@@ -3161,7 +3161,6 @@ function fpc_PopCnt_dword(AValue : DWord): DWord;[Public,Alias:'FPC_POPCNT_DWORD
       end;
   end;
 
-
 {$ifndef FPC_SYSTEM_HAS_POPCNT_QWORD}
 function fpc_PopCnt_qword(AValue : QWord): QWord;[Public,Alias:'FPC_POPCNT_QWORD'];compilerproc;
   begin
@@ -3169,3 +3168,597 @@ function fpc_PopCnt_qword(AValue : QWord): QWord;[Public,Alias:'FPC_POPCNT_QWORD
   end;
 {$endif}
 
+{$if not defined(VER3_2) and not defined(CPUJVM)}
+{$push}
+{$R-,Q-}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_INC_8}
+function fpc_atomic_inc_8(var Target: shortint): shortint;compilerproc;
+{$if defined(FPC_SYSTEM_HAS_ATOMIC_ADD_8)}
+begin
+  Result := AtomicIncrement(Target, 1);
+{$elseif defined(FPC_SYSTEM_HAS_ATOMIC_SUB_8)}
+begin
+  Result := AtomicDecrement(Target, -1);
+{$else}
+var
+  t1, t2: shortint;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, t1 + 1, t1);
+  until t2 = t1;
+  Result := t2 + 1;
+{$endif}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_INC_8}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_INC_16}
+function fpc_atomic_inc_16(var Target: smallint): smallint;compilerproc;
+{$if defined(FPC_SYSTEM_HAS_ATOMIC_ADD_16)}
+begin
+  Result := AtomicIncrement(Target, 1);
+{$elseif defined(FPC_SYSTEM_HAS_ATOMIC_SUB_16)}
+begin
+  Result := AtomicDecrement(Target, -1);
+{$else}
+var
+  t1, t2: smallint;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, t1 + 1, t1);
+  until t2 = t1;
+  Result := t2 + 1;
+{$endif}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_INC_16}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_INC_32}
+function fpc_atomic_inc_32(var Target: longint): longint;compilerproc;
+{$if defined(FPC_SYSTEM_HAS_ATOMIC_ADD_32)}
+begin
+  Result := AtomicIncrement(Target, 1);
+{$elseif defined(FPC_SYSTEM_HAS_ATOMIC_SUB_32)}
+begin
+  Result := AtomicDecrement(Target, -1);
+{$else}
+var
+  t1, t2: longint;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, t1 + 1, t1);
+  until t2 = t1;
+  Result := t2 + 1;
+{$endif}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_INC_32}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_INC_64}
+function fpc_atomic_inc_64(var Target: int64): int64;compilerproc;
+{$if defined(FPC_SYSTEM_HAS_ATOMIC_ADD_64)}
+begin
+  Result := AtomicIncrement(Target, 1);
+{$elseif defined(FPC_SYSTEM_HAS_ATOMIC_SUB_64)}
+begin
+  Result := AtomicDecrement(Target, -1);
+{$else}
+var
+  t1, t2: int64;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, t1 + 1, t1);
+  until t2 = t1;
+  Result := t2 + 1;
+{$endif}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_INC_64}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_DEC_8}
+function fpc_atomic_dec_8(var Target: shortint): shortint;compilerproc;
+{$if defined(FPC_SYSTEM_HAS_ATOMIC_SUB_8)}
+begin
+  Result := AtomicDecrement(Target, 1);
+{$elseif defined(FPC_SYSTEM_HAS_ATOMIC_ADD_8)}
+begin
+  Result := AtomicIncrement(Target, -1);
+{$else}
+var
+  t1, t2: shortint;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, t1 - 1, t1);
+  until t2 = t1;
+  Result := t2 - 1;
+{$endif}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_DEC_8}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_DEC_16}
+function fpc_atomic_dec_16(var Target: smallint): smallint;compilerproc;
+{$if defined(FPC_SYSTEM_HAS_ATOMIC_SUB_16)}
+begin
+  Result := AtomicDecrement(Target, 1);
+{$elseif defined(FPC_SYSTEM_HAS_ATOMIC_ADD_16)}
+begin
+  Result := AtomicIncrement(Target, -1);
+{$else}
+var
+  t1, t2: smallint;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, t1 - 1, t1);
+  until t2 = t1;
+  Result := t2 - 1;
+{$endif}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_DEC_16}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_DEC_32}
+function fpc_atomic_dec_32(var Target: longint): longint;compilerproc;
+{$if defined(FPC_SYSTEM_HAS_ATOMIC_SUB_32)}
+begin
+  Result := AtomicDecrement(Target, 1);
+{$elseif defined(FPC_SYSTEM_HAS_ATOMIC_ADD_32)}
+begin
+  Result := AtomicIncrement(Target, -1);
+{$else}
+var
+  t1, t2: longint;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, t1 - 1, t1);
+  until t2 = t1;
+  Result := t2 - 1;
+{$endif}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_DEC_32}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_DEC_64}
+function fpc_atomic_dec_64(var Target: int64): int64;compilerproc;
+{$if defined(FPC_SYSTEM_HAS_ATOMIC_SUB_64)}
+begin
+  Result := AtomicDecrement(Target, 1);
+{$elseif defined(FPC_SYSTEM_HAS_ATOMIC_ADD_64)}
+begin
+  Result := AtomicIncrement(Target, -1);
+{$else}
+var
+  t1, t2: int64;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, t1 - 1, t1);
+  until t2 = t1;
+  Result := t2 - 1;
+{$endif}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_DEC_64}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_ADD_8}
+function fpc_atomic_add_8(var Target: shortint; Value: shortint): shortint;compilerproc;
+{$ifdef FPC_SYSTEM_HAS_ATOMIC_SUB_8}
+begin
+  { the intrinsic returns the new value, but the helper needs to return the old }
+  Result := AtomicDecrement(Target, - Value) - Value;
+{$else FPC_SYSTEM_HAS_ATOMIC_SUB_8}
+var
+  t1, t2: shortint;
+begin
+  repeat
+    t1:=Target;
+    t2:=AtomicCmpExchange(Target, t1 + Value, t1);
+  until t2 = t1;
+  Result := t2;
+{$endif}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_ADD_8}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_ADD_16}
+function fpc_atomic_add_16(var Target: smallint; Value: smallint): smallint;compilerproc;
+{$ifdef FPC_SYSTEM_HAS_ATOMIC_SUB_16}
+begin
+  { the intrinsic returns the new value, but the helper needs to return the old }
+  Result := AtomicDecrement(Target, - Value) - Value;
+{$else FPC_SYSTEM_HAS_ATOMIC_SUB_16}
+var
+  t1, t2: smallint;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, t1 + Value, t1);
+  until t2 = t1;
+  Result := t2;
+{$endif FPC_SYSTEM_HAS_ATOMIC_SUB_16}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_ADD_16}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_ADD_32}
+function fpc_atomic_add_32(var Target: longint; Value: longint): longint;compilerproc;
+{$ifdef FPC_SYSTEM_HAS_ATOMIC_SUB_32}
+begin
+  { the intrinsic returns the new value, but the helper needs to return the old }
+  Result := AtomicDecrement(Target, - Value) - Value;
+{$else FPC_SYSTEM_HAS_ATOMIC_SUB_32}
+var
+  t1, t2: longint;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, t1 + Value, t1);
+  until t2 = t1;
+  Result := t2;
+{$endif FPC_SYSTEM_HAS_ATOMIC_SUB_32}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_ADD_32}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_ADD_64}
+function fpc_atomic_add_64(var Target: int64; Value: int64): int64;compilerproc;
+{$ifdef FPC_SYSTEM_HAS_ATOMIC_SUB_64}
+begin
+  { the intrinsic returns the new value, but the helper needs to return the old }
+  Result := AtomicDecrement(Target, - Value) - Value;
+{$else FPC_SYSTEM_HAS_ATOMIC_SUB_64}
+var
+  t1, t2: int64;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, t1 + Value, t1);
+  until t2 = t1;
+  Result := t2;
+{$endif FPC_SYSTEM_HAS_ATOMIC_SUB_64}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_ADD_64}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_SUB_8}
+function fpc_atomic_sub_8(var Target: shortint; Value: shortint): shortint;compilerproc;
+{$ifdef FPC_SYSTEM_HAS_ATOMIC_ADD_8}
+begin
+  { the intrinsic returns the new value, but the helper needs to return the old }
+  Result := AtomicIncrement(Target, - Value) + Value;
+{$else FPC_SYSTEM_HAS_ATOMIC_ADD_8}
+var
+  t1, t2: smallint;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, t1 - Value, t1);
+  until t2 = t1;
+  Result := t2;
+{$endif FPC_SYSTEM_HAS_ATOMIC_ADD_8}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_SUB_8}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_SUB_16}
+function fpc_atomic_sub_16(var Target: smallint; Value: smallint): smallint;compilerproc;
+{$ifdef FPC_SYSTEM_HAS_ATOMIC_ADD_16}
+begin
+  { the intrinsic returns the new value, but the helper needs to return the old }
+  Result := AtomicIncrement(Target, - Value) + Value;
+{$else FPC_SYSTEM_HAS_ATOMIC_ADD_16}
+var
+  t1, t2: shortint;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, t1 - Value, t1);
+  until t2 = t1;
+  Result := t2;
+{$endif FPC_SYSTEM_HAS_ATOMIC_ADD_16}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_SUB_16}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_SUB_32}
+function fpc_atomic_sub_32(var Target: longint; Value: longint): longint;compilerproc;
+{$ifdef FPC_SYSTEM_HAS_ATOMIC_ADD_32}
+begin
+  { the intrinsic returns the new value, but the helper needs to return the old }
+  Result := AtomicIncrement(Target, - Value) + Value;
+{$else FPC_SYSTEM_HAS_ATOMIC_ADD_32}
+var
+  t1, t2: longint;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, t1 - Value, t1);
+  until t2 = t1;
+  Result := t2;
+{$endif FPC_SYSTEM_HAS_ATOMIC_ADD_32}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_SUB_32}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_SUB_64}
+function fpc_atomic_sub_64(var Target: int64; Value: int64): int64;compilerproc;
+{$ifdef FPC_SYSTEM_HAS_ATOMIC_ADD_64}
+begin
+  { the intrinsic returns the new value, but the helper needs to return the old }
+  Result := AtomicIncrement(Target, - Value) + Value;
+{$else FPC_SYSTEM_HAS_ATOMIC_ADD_64}
+var
+  t1, t2: int64;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, t1 - Value, t1);
+  until t2 = t1;
+  Result := t2;
+{$endif FPC_SYSTEM_HAS_ATOMIC_ADD_8}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_SUB_64}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_XCHG_8}
+function fpc_atomic_xchg_8(var Target: shortint; Source: shortint): shortint;compilerproc;
+var
+  t1, t2: shortint;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, Source, t1);
+  until t2 = t1;
+  Result := t1;
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_XCHG_8}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_XCHG_16}
+function fpc_atomic_xchg_16(var Target: smallint; Source: smallint): smallint;compilerproc;
+var
+  t1, t2: smallint;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, Source, t1);
+  until t2 = t1;
+  Result := t1;
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_XCHG_16}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_XCHG_32}
+function fpc_atomic_xchg_32(var Target: longint; Source: longint): longint;compilerproc;
+var
+  t1, t2: longint;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, Source, t1);
+  until t2 = t1;
+  Result := t1;
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_XCHG_32}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_XCHG_64}
+function fpc_atomic_xchg_64(var Target: int64; Source: int64): int64;compilerproc;
+var
+  t1, t2: int64;
+begin
+  repeat
+    t1 := Target;
+    t2 := AtomicCmpExchange(Target, Source, t1);
+  until t2 = t1;
+  Result := t1;
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_XCHG_64}
+
+{ the variant of fpc_atomic_cmp_xchg_<alusize>() needs to be implemented by
+  the corresponding platforms include file, then the default functions can do
+  the job (poorly) until the other functions are implemented for the platform }
+
+procedure AtomicEnterLock; forward;
+procedure AtomicLeaveLock; forward;
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_CMP_XCHG_8}
+{$if SizeOf(ALUSInt) = SizeOf(ShortInt)}
+{$message warning 'At least fpc_atomic_cmp_xchg_8 must be implemented for the current platform'}
+{$define FPC_SYSTEM_ATOMIC_8_NO_LOCK}
+{$else}
+{$define FPC_SYSTEM_NEEDS_ATOMIC_FALLBACK}
+{$endif}
+function fpc_atomic_cmp_xchg_8(var Target: shortint; NewValue: shortint; Comparand: shortint): shortint;compilerproc;
+begin
+  {$ifdef FPC_SYSTEM_ATOMIC_8_NO_LOCK}
+  AtomicEnterLock;
+  {$endif FPC_SYSTEM_ATOMIC_8_NO_LOCK}
+  Result:=Target;
+  if Target=Comparand then
+    Target:=NewValue;
+  {$ifdef FPC_SYSTEM_ATOMIC_8_NO_LOCK}
+  AtomicLeaveLock;
+  {$endif FPC_SYSTEM_ATOMIC_8_NO_LOCK}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_CMP_XCHG_8}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_CMP_XCHG_16}
+{$if SizeOf(ALUSInt) = SizeOf(SmallInt)}
+{$message warning 'At least fpc_atomic_cmp_xchg_16 must be implemented for the current platform'}
+{$define FPC_SYSTEM_ATOMIC_16_NO_LOCK}
+{$else}
+{$define FPC_SYSTEM_NEEDS_ATOMIC_FALLBACK}
+{$endif}
+function fpc_atomic_cmp_xchg_16(var Target: smallint; NewValue: smallint; Comparand: smallint): smallint;compilerproc;
+begin
+  {$ifdef FPC_SYSTEM_ATOMIC_16_NO_LOCK}
+  AtomicEnterLock;
+  {$endif FPC_SYSTEM_ATOMIC_16_NO_LOCK}
+  Result:=Target;
+  if Target=Comparand then
+    Target:=NewValue;
+  {$ifdef FPC_SYSTEM_ATOMIC_16_NO_LOCK}
+  AtomicLeaveLock;
+  {$endif FPC_SYSTEM_ATOMIC_16_NO_LOCK}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_CMP_XCHG_16}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_CMP_XCHG_32}
+{$if SizeOf(ALUSInt) = SizeOf(LongInt)}
+{$message warning 'At least fpc_atomic_cmp_xchg_32 must be implemented for the current platform'}
+{$define FPC_SYSTEM_ATOMIC_32_NO_LOCK}
+{$else}
+{$define FPC_SYSTEM_NEEDS_ATOMIC_FALLBACK}
+{$endif}
+function fpc_atomic_cmp_xchg_32(var Target: longint; NewValue: longint; Comparand: longint): longint;compilerproc;
+begin
+  {$ifdef FPC_SYSTEM_ATOMIC_32_NO_LOCK}
+  AtomicEnterLock;
+  {$endif FPC_SYSTEM_ATOMIC_32_NO_LOCK}
+  Result:=Target;
+  if Target=Comparand then
+    Target:=NewValue;
+  {$ifdef FPC_SYSTEM_ATOMIC_32_NO_LOCK}
+  AtomicLeaveLock;
+  {$endif FPC_SYSTEM_ATOMIC_32_NO_LOCK}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_CMP_XCHG_32}
+
+{$ifndef FPC_SYSTEM_HAS_ATOMIC_CMP_XCHG_64}
+{$if SizeOf(ALUSInt) = SizeOf(Int64)}
+{$message warning 'At least fpc_atomic_cmp_xchg_64 must be implemented for the current platform'}
+{$define FPC_SYSTEM_ATOMIC_64_NO_LOCK}
+{$else}
+{$define FPC_SYSTEM_NEEDS_ATOMIC_FALLBACK}
+{$endif}
+function fpc_atomic_cmp_xchg_64(var Target: int64; NewValue: int64; Comparand: int64): int64;compilerproc;
+begin
+  {$ifdef FPC_SYSTEM_ATOMIC_64_NO_LOCK}
+  AtomicEnterLock;
+  {$endif FPC_SYSTEM_ATOMIC_64_NO_LOCK}
+  Result:=Target;
+  if Target=Comparand then
+    Target:=NewValue;
+  {$ifdef FPC_SYSTEM_ATOMIC_64_NO_LOCK}
+  AtomicLeaveLock;
+  {$endif FPC_SYSTEM_ATOMIC_64_NO_LOCK}
+end;
+{$endif FPC_SYSTEM_HAS_ATOMIC_CMP_XCHG_64}
+
+{$if defined(FPC_SYSTEM_NEEDS_ATOMIC_FALLBACK)}
+var
+  gAtomicLock: ALUSInt = 0;
+
+function fpc_atomic_cmp_xchg_alu(var Target: ALUSInt; NewValue: ALUSInt; Comparand: ALUSint): ALUSint; external name
+{$if defined(CPU8)}
+  'FPC_ATOMIC_CMP_XCHG_8'
+{$elseif defined(CPU16)}
+  'FPC_ATOMIC_CMP_XCHG_16'
+{$elseif defined(CPU32)}
+  'FPC_ATOMIC_CMP_XCHG_32'
+{$elseif defined(CPU64)}
+  'FPC_ATOMIC_CMP_XCHG_64'
+{$else}
+  'FPC_ATOMIC_CMP_XCHG_UNKNOWN'
+{$endif}
+  ;
+
+procedure AtomicEnterLock;
+var
+  r: ALUSint;
+begin
+  { spin until we get the lock }
+  repeat
+    r := fpc_atomic_cmp_xchg_alu(gAtomicLock, 1, 0);
+  until r = 0;
+end;
+
+procedure AtomicLeaveLock;
+begin
+  fpc_atomic_cmp_xchg_alu(gAtomicLock, 0, 1);
+end;
+{$else}
+procedure AtomicEnterLock;
+begin
+end;
+
+procedure AtomicLeaveLock;
+begin
+end;
+{$endif}
+
+{$if defined(FPC_SYSTEM_INTERLOCKED_USE_INTRIN)}
+
+{$ifdef cpu16}
+function InterlockedIncrement (var Target: smallint) : smallint;
+begin
+  Result := AtomicIncrement(Target);
+end;
+
+function InterlockedDecrement (var Target: smallint) : smallint;
+begin
+  Result := AtomicDecrement(Target);
+end;
+
+function InterlockedExchange (var Target: smallint;Source : smallint) : smallint;
+begin
+  Result := AtomicExchange(Target, Source);
+end;
+
+function InterlockedExchangeAdd (var Target: smallint;Source : smallint) : smallint;
+begin
+  Result := AtomicIncrement(Target, Source) - Source;
+end;
+
+function InterlockedCompareExchange(var Target: smallint; NewValue: smallint; Comperand: smallint): smallint;
+begin
+  Result := AtomicCmpExchange(Target, NewValue, Comperand);
+end;
+{$endif cpu16}
+
+function InterlockedIncrement (var Target: longint) : longint;
+begin
+  Result := AtomicIncrement(Target);
+end;
+
+function InterlockedDecrement (var Target: longint) : longint;
+begin
+  Result := AtomicDecrement(Target);
+end;
+
+function InterlockedExchange (var Target: longint;Source : longint) : longint;
+begin
+  Result := AtomicExchange(Target, Source);
+end;
+
+function InterlockedExchangeAdd (var Target: longint;Source : longint) : longint;
+begin
+  Result := AtomicIncrement(Target, Source) - Source;
+end;
+
+function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint;
+begin
+  Result := AtomicCmpExchange(Target, NewValue, Comperand);
+end;
+
+{$ifdef cpu64}
+function InterlockedIncrement64 (var Target: int64) : int64;
+begin
+  Result := AtomicIncrement(Target);
+end;
+
+function InterlockedDecrement64 (var Target: int64) : int64;
+begin
+  Result := AtomicDecrement(Target);
+end;
+
+function InterlockedExchange64 (var Target: int64;Source : int64) : int64;
+begin
+  Result := AtomicExchange(Target, Source);
+end;
+
+function InterlockedExchangeAdd64 (var Target: int64;Source : int64) : int64;
+begin
+  Result := AtomicIncrement(Target, Source) - Source;
+end;
+
+function InterlockedCompareExchange64(var Target: int64; NewValue: int64; Comperand: int64): int64;
+begin
+  Result := AtomicCmpExchange(Target, NewValue, Comperand);
+end;
+{$endif cpu64}
+
+{$endif FPC_SYSTEM_INTERLOCKED_USE_INTRIN}
+
+{$pop}
+{$endif VER3_2}