--------------------------------
-- Ivan Levashew aka OCTAGRAM --
--              Barnaul, 2009 --
--------------------------------

-- TODO: Should Get use Read_Memory_Barrier?

-- rmb is "lock addl", "lock xaddl", "lock xchgl",
-- etc. on x86, so I decided to use lock xaddl 0 to
-- implement Get. I'm wondering if x86 CPUs are
-- clever enough to omit overwritting memory cell
-- with the same value as before.

-- TODO: Look on Java implementation
-- It's not obvious where to look for.
-- Created topic on programmersforum.ru
-- TODO: Look harder

with Interfaces, System, System.Machine_Code,
     Turbo_Private.Atomic_Integer_32_Package,
     Turbo_Private.Atomic_Unsigned_32_Package,
     Turbo_Private.Atomic_Integer_Addr_Package,
     Turbo_Private.Atomic_Unsigned_Addr_Package;

use  Interfaces, System, System.Machine_Code,
     Turbo_Private.Atomic_Integer_32_Package,
     Turbo_Private.Atomic_Unsigned_32_Package,
     Turbo_Private.Atomic_Integer_Addr_Package,
     Turbo_Private.Atomic_Unsigned_Addr_Package;

package body Turbo_Private.Atomic is

   LF : constant String := (1 => Character'Val (10));
   HT : constant String := (1 => Character'Val (9));

   NL : constant String := LF & HT;

   ------------
   -- Create --
   ------------

   function Create (Item : Integer_32) return Atomic_Integer_32 is
   begin
      return Result : Atomic_Integer_32 do
         Set (Result, Item);
      end return;
   end Create;

   -----------------
   -- Lazy_Create --
   -----------------

   function Lazy_Create (Item : Integer_32) return Atomic_Integer_32 is
   begin
      return (Item => Item);
   end Lazy_Create;

   -------------
   -- Inc_Get --
   -------------

   function Inc_Get (Addend : not null access Atomic_Integer_32)
      return Integer_32
   is
      -- Q: Why isn't Inc implemented with xaddl?
      -- A: This is due to potential overflow. Use
      -- Unsigned_* instead if you don't care about
      -- overflows.
      Old_Value, New_Value, Fetched : Integer_32;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value + 1;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return New_Value;
   end Inc_Get;

   -------------
   -- Get_Inc --
   -------------

   function Get_Inc (Addend : not null access Atomic_Integer_32)
      return Integer_32
   is
      Old_Value, New_Value, Fetched : Integer_32;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value + 1;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return Old_Value;
   end Get_Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : in out Atomic_Integer_32) is
      Value, Fetched : Integer_32;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend.Item'Access, Value, Value + 1);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : not null access Atomic_Integer_32) is
      Value, Fetched : Integer_32;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend, Value, Value + 1);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Inc;

   -------------
   -- Inc_Get --
   -------------

   function Inc_Get (Addend : not null access Atomic_Integer_32;
      Item : Integer_32) return Integer_32
   is
      Old_Value, New_Value, Fetched : Integer_32;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value + Item;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return New_Value;
   end Inc_Get;

   -------------
   -- Get_Inc --
   -------------

   function Get_Inc (Addend : not null access Atomic_Integer_32;
      Item : Integer_32) return Integer_32
   is
      Old_Value, New_Value, Fetched : Integer_32;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value + Item;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return Old_Value;
   end Get_Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : in out Atomic_Integer_32;
      Item : Integer_32)
   is
      Value, Fetched : Integer_32;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend.Item'Access, Value, Value + Item);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : not null access Atomic_Integer_32;
      Item : Integer_32)
   is
      Value, Fetched : Integer_32;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend, Value, Value + 1);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Inc;

   -------------
   -- Dec_Get --
   -------------

   function Dec_Get (Addend : not null access Atomic_Integer_32)
      return Integer_32
   is
      Old_Value, New_Value, Fetched : Integer_32;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value - 1;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return New_Value;
   end Dec_Get;

   -------------
   -- Get_Dec --
   -------------

   function Get_Dec (Addend : not null access Atomic_Integer_32)
      return Integer_32
   is
      Old_Value, New_Value, Fetched : Integer_32;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value - 1;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return Old_Value;
   end Get_Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : in out Atomic_Integer_32) is
      Value, Fetched : Integer_32;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend.Item'Access, Value, Value - 1);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : not null access Atomic_Integer_32) is
      Value, Fetched : Integer_32;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend.Item'Access, Value, Value - 1);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Dec;

   -------------
   -- Dec_Get --
   -------------

   function Dec_Get (Addend : not null access Atomic_Integer_32;
      Item : Integer_32) return Integer_32
   is
      Old_Value, New_Value, Fetched : Integer_32;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value - Item;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return New_Value;
   end Dec_Get;

   -------------
   -- Get_Dec --
   -------------

   function Get_Dec (Addend : not null access Atomic_Integer_32;
      Item : Integer_32) return Integer_32
   is
      Old_Value, New_Value, Fetched : Integer_32;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value - Item;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return Old_Value;
   end Get_Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : in out Atomic_Integer_32;
      Item : Integer_32)
   is
      Value, Fetched : Integer_32;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend.Item'Access, Value, Value - Item);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : not null access Atomic_Integer_32;
      Item : Integer_32)
   is
      Value, Fetched : Integer_32;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend, Value, Value - Item);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Dec;

   ------------
   -- Create --
   ------------

   function Create (Item : Unsigned_32) return Atomic_Unsigned_32 is
   begin
      return Result : Atomic_Unsigned_32 do
         Set (Result, Item);
      end return;
   end Create;

   -----------------
   -- Lazy_Create --
   -----------------

   function Lazy_Create (Item : Unsigned_32) return Atomic_Unsigned_32 is
   begin
      return (Item => Item);
   end Lazy_Create;

   -------------
   -- Inc_Get --
   -------------

   function Inc_Get (Addend : not null access Atomic_Unsigned_32)
      return Unsigned_32
   is
      Result : Unsigned_32;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_32'Asm_Output ("=m", Addend.Item),
                      Unsigned_32'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_32'Asm_Input ("1", 1),
         Volatile => True
      );
      return Result + 1;
   end Inc_Get;

   -------------
   -- Get_Inc --
   -------------

   function Get_Inc (Addend : not null access Atomic_Unsigned_32)
      return Unsigned_32
   is
      Result : Unsigned_32;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_32'Asm_Output ("=m", Addend.Item),
                      Unsigned_32'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_32'Asm_Input ("1", 1),
         Volatile => True
      );
      return Result;
   end Get_Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : in out Atomic_Unsigned_32) is
   begin
      Asm (
         "lock incl %0",
         Outputs  => Unsigned_32'Asm_Output ("=m", Addend.Item),
         Volatile => True
      );
   end Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : not null access Atomic_Unsigned_32) is
   begin
      Asm (
         "lock incl %0",
         Outputs  => Unsigned_32'Asm_Output ("=m", Addend.Item),
         Volatile => True
      );
   end Inc;

   -------------
   -- Inc_Get --
   -------------

   function Inc_Get (Addend : not null access Atomic_Unsigned_32;
      Item : Unsigned_32) return Unsigned_32
   is
      Result : Unsigned_32;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_32'Asm_Output ("=m", Addend.Item),
                      Unsigned_32'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_32'Asm_Input ("1", Item),
         Volatile => True
      );
      return Result + Item;
   end Inc_Get;

   -------------
   -- Get_Inc --
   -------------

   function Get_Inc (Addend : not null access Atomic_Unsigned_32;
      Item : Unsigned_32) return Unsigned_32
   is
      Result : Unsigned_32;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_32'Asm_Output ("=m", Addend.Item),
                      Unsigned_32'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_32'Asm_Input ("1", Item),
         Volatile => True
      );
      return Result;
   end Get_Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : in out Atomic_Unsigned_32;
      Item : Unsigned_32) is
   begin
      Asm (
         "lock addl %1, %0",
         Outputs  => Unsigned_32'Asm_Output ("=m", Addend.Item),
         Inputs   => Unsigned_32'Asm_Input ("ir", Item),
         Volatile => True
      );
   end Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : not null access Atomic_Unsigned_32;
      Item : Unsigned_32) is
   begin
      Asm (
         "lock addl %1, %0",
         Outputs  => Unsigned_32'Asm_Output ("=m", Addend.Item),
         Inputs   => Unsigned_32'Asm_Input ("ir", Item),
         Volatile => True
      );
   end Inc;

   -------------
   -- Dec_Get --
   -------------

   function Dec_Get (Addend : not null access Atomic_Unsigned_32)
      return Unsigned_32
   is
      Result : Unsigned_32;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_32'Asm_Output ("=m", Addend.Item),
                      Unsigned_32'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_32'Asm_Input ("1", -1),
         Volatile => True
      );
      return Result - 1;
   end Dec_Get;

   -------------
   -- Get_Dec --
   -------------

   function Get_Dec (Addend : not null access Atomic_Unsigned_32)
      return Unsigned_32
   is
      Result : Unsigned_32;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_32'Asm_Output ("=m", Addend.Item),
                      Unsigned_32'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_32'Asm_Input ("1", -1),
         Volatile => True
      );
      return Result;
   end Get_Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : in out Atomic_Unsigned_32) is
   begin
      Asm (
         "lock decl %0",
         Outputs  => Unsigned_32'Asm_Output ("=m", Addend.Item),
         Volatile => True
      );
   end Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : not null access Atomic_Unsigned_32) is
   begin
      Asm (
         "lock decl %0",
         Outputs  => Unsigned_32'Asm_Output ("=m", Addend.Item),
         Volatile => True
      );
   end Dec;

   -------------
   -- Dec_Get --
   -------------

   function Dec_Get (Addend : not null access Atomic_Unsigned_32;
      Item : Unsigned_32) return Unsigned_32
   is
      Result : Unsigned_32;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_32'Asm_Output ("=m", Addend.Item),
                      Unsigned_32'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_32'Asm_Input ("1", -Item),
         Volatile => True
      );
      return Result - Item;
   end Dec_Get;

   -------------
   -- Get_Dec --
   -------------

   function Get_Dec (Addend : not null access Atomic_Unsigned_32;
      Item : Unsigned_32) return Unsigned_32
   is
      Result : Unsigned_32;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_32'Asm_Output ("=m", Addend.Item),
                      Unsigned_32'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_32'Asm_Input ("1", -Item),
         Volatile => True
      );
      return Result;
   end Get_Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : in out Atomic_Unsigned_32;
      Item : Unsigned_32) is
   begin
      Asm (
         "lock subl %1, %0",
         Outputs  => Unsigned_32'Asm_Output ("=m", Addend.Item),
         Inputs   => Unsigned_32'Asm_Input ("ir", Item),
         Volatile => True
      );
   end Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : not null access Atomic_Unsigned_32;
      Item : Unsigned_32) is
   begin
      Asm (
         "lock subl %1, %0",
         Outputs  => Unsigned_32'Asm_Output ("=m", Addend.Item),
         Inputs   => Unsigned_32'Asm_Input ("ir", Item),
         Volatile => True
      );
   end Dec;

   ------------
   -- Create --
   ------------

   function Create (Item : Integer_Addr) return Atomic_Integer_Addr is
   begin
      return Result : Atomic_Integer_Addr do
         Set (Result, Item);
      end return;
   end Create;

   -----------------
   -- Lazy_Create --
   -----------------

   function Lazy_Create (Item : Integer_Addr) return Atomic_Integer_Addr is
   begin
      return (Item => Item);
   end Lazy_Create;

   -------------
   -- Inc_Get --
   -------------

   function Inc_Get (Addend : not null access Atomic_Integer_Addr)
      return Integer_Addr
   is
      -- Q: Why isn't Inc implemented with xaddl?
      -- A: This is due to potential overflow. Use
      -- Unsigned_* instead if you don't care about
      -- overflows.
      Old_Value, New_Value, Fetched : Integer_Addr;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value + 1;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return New_Value;
   end Inc_Get;

   -------------
   -- Get_Inc --
   -------------

   function Get_Inc (Addend : not null access Atomic_Integer_Addr)
      return Integer_Addr
   is
      Old_Value, New_Value, Fetched : Integer_Addr;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value + 1;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return Old_Value;
   end Get_Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : in out Atomic_Integer_Addr) is
      Value, Fetched : Integer_Addr;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend.Item'Access, Value, Value + 1);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : not null access Atomic_Integer_Addr) is
      Value, Fetched : Integer_Addr;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend, Value, Value + 1);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Inc;

   -------------
   -- Inc_Get --
   -------------

   function Inc_Get (Addend : not null access Atomic_Integer_Addr;
      Item : Integer_Addr) return Integer_Addr
   is
      Old_Value, New_Value, Fetched : Integer_Addr;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value + Item;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return New_Value;
   end Inc_Get;

   -------------
   -- Get_Inc --
   -------------

   function Get_Inc (Addend : not null access Atomic_Integer_Addr;
      Item : Integer_Addr) return Integer_Addr
   is
      Old_Value, New_Value, Fetched : Integer_Addr;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value + Item;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return Old_Value;
   end Get_Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : in out Atomic_Integer_Addr;
      Item : Integer_Addr)
   is
      Value, Fetched : Integer_Addr;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend.Item'Access, Value, Value + Item);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : not null access Atomic_Integer_Addr;
      Item : Integer_Addr)
   is
      Value, Fetched : Integer_Addr;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend, Value, Value + 1);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Inc;

   -------------
   -- Dec_Get --
   -------------

   function Dec_Get (Addend : not null access Atomic_Integer_Addr)
      return Integer_Addr
   is
      Old_Value, New_Value, Fetched : Integer_Addr;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value - 1;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return New_Value;
   end Dec_Get;

   -------------
   -- Get_Dec --
   -------------

   function Get_Dec (Addend : not null access Atomic_Integer_Addr)
      return Integer_Addr
   is
      Old_Value, New_Value, Fetched : Integer_Addr;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value - 1;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return Old_Value;
   end Get_Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : in out Atomic_Integer_Addr) is
      Value, Fetched : Integer_Addr;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend.Item'Access, Value, Value - 1);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : not null access Atomic_Integer_Addr) is
      Value, Fetched : Integer_Addr;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend.Item'Access, Value, Value - 1);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Dec;

   -------------
   -- Dec_Get --
   -------------

   function Dec_Get (Addend : not null access Atomic_Integer_Addr;
      Item : Integer_Addr) return Integer_Addr
   is
      Old_Value, New_Value, Fetched : Integer_Addr;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value - Item;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return New_Value;
   end Dec_Get;

   -------------
   -- Get_Dec --
   -------------

   function Get_Dec (Addend : not null access Atomic_Integer_Addr;
      Item : Integer_Addr) return Integer_Addr
   is
      Old_Value, New_Value, Fetched : Integer_Addr;
   begin
      Old_Value := Addend.Item;
      loop
         New_Value := Old_Value - Item;
         Fetched := Compare_Swap (Addend, Old_Value, New_Value);
      exit when Fetched = Old_Value;
         Old_Value := Fetched;
      end loop;
      return Old_Value;
   end Get_Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : in out Atomic_Integer_Addr;
      Item : Integer_Addr)
   is
      Value, Fetched : Integer_Addr;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend.Item'Access, Value, Value - Item);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : not null access Atomic_Integer_Addr;
      Item : Integer_Addr)
   is
      Value, Fetched : Integer_Addr;
   begin
      Value := Addend.Item;
      loop
         Fetched := Compare_Swap (Addend, Value, Value - Item);
      exit when Fetched = Value;
         Value := Fetched;
      end loop;      
   end Dec;

   ------------
   -- Create --
   ------------

   function Create (Item : Unsigned_Addr) return Atomic_Unsigned_Addr is
   begin
      return Result : Atomic_Unsigned_Addr do
         Set (Result, Item);
      end return;
   end Create;

   -----------------
   -- Lazy_Create --
   -----------------

   function Lazy_Create (Item : Unsigned_Addr) return Atomic_Unsigned_Addr is
   begin
      return (Item => Item);
   end Lazy_Create;

   -------------
   -- Inc_Get --
   -------------

   function Inc_Get (Addend : not null access Atomic_Unsigned_Addr)
      return Unsigned_Addr
   is
      Result : Unsigned_Addr;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_Addr'Asm_Output ("=m", Addend.Item),
                      Unsigned_Addr'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_Addr'Asm_Input ("1", 1),
         Volatile => True
      );
      return Result + 1;
   end Inc_Get;

   -------------
   -- Get_Inc --
   -------------

   function Get_Inc (Addend : not null access Atomic_Unsigned_Addr)
      return Unsigned_Addr
   is
      Result : Unsigned_Addr;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_Addr'Asm_Output ("=m", Addend.Item),
                      Unsigned_Addr'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_Addr'Asm_Input ("1", 1),
         Volatile => True
      );
      return Result;
   end Get_Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : in out Atomic_Unsigned_Addr) is
   begin
      Asm (
         "lock incl %0",
         Outputs  => Unsigned_Addr'Asm_Output ("=m", Addend.Item),
         Volatile => True
      );
   end Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : not null access Atomic_Unsigned_Addr) is
   begin
      Asm (
         "lock incl %0",
         Outputs  => Unsigned_Addr'Asm_Output ("=m", Addend.Item),
         Volatile => True
      );
   end Inc;

   -------------
   -- Inc_Get --
   -------------

   function Inc_Get (Addend : not null access Atomic_Unsigned_Addr;
      Item : Unsigned_Addr) return Unsigned_Addr
   is
      Result : Unsigned_Addr;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_Addr'Asm_Output ("=m", Addend.Item),
                      Unsigned_Addr'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_Addr'Asm_Input ("1", Item),
         Volatile => True
      );
      return Result + Item;
   end Inc_Get;

   -------------
   -- Get_Inc --
   -------------

   function Get_Inc (Addend : not null access Atomic_Unsigned_Addr;
      Item : Unsigned_Addr) return Unsigned_Addr
   is
      Result : Unsigned_Addr;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_Addr'Asm_Output ("=m", Addend.Item),
                      Unsigned_Addr'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_Addr'Asm_Input ("1", Item),
         Volatile => True
      );
      return Result;
   end Get_Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : in out Atomic_Unsigned_Addr;
      Item : Unsigned_Addr) is
   begin
      Asm (
         "lock addl %1, %0",
         Outputs  => Unsigned_Addr'Asm_Output ("=m", Addend.Item),
         Inputs   => Unsigned_Addr'Asm_Input ("ir", Item),
         Volatile => True
      );
   end Inc;

   ---------
   -- Inc --
   ---------

   procedure Inc (Addend : not null access Atomic_Unsigned_Addr;
      Item : Unsigned_Addr) is
   begin
      Asm (
         "lock addl %1, %0",
         Outputs  => Unsigned_Addr'Asm_Output ("=m", Addend.Item),
         Inputs   => Unsigned_Addr'Asm_Input ("ir", Item),
         Volatile => True
      );
   end Inc;

   -------------
   -- Dec_Get --
   -------------

   function Dec_Get (Addend : not null access Atomic_Unsigned_Addr)
      return Unsigned_Addr
   is
      Result : Unsigned_Addr;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_Addr'Asm_Output ("=m", Addend.Item),
                      Unsigned_Addr'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_Addr'Asm_Input ("1", -1),
         Volatile => True
      );
      return Result - 1;
   end Dec_Get;

   -------------
   -- Get_Dec --
   -------------

   function Get_Dec (Addend : not null access Atomic_Unsigned_Addr)
      return Unsigned_Addr
   is
      Result : Unsigned_Addr;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_Addr'Asm_Output ("=m", Addend.Item),
                      Unsigned_Addr'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_Addr'Asm_Input ("1", -1),
         Volatile => True
      );
      return Result;
   end Get_Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : in out Atomic_Unsigned_Addr) is
   begin
      Asm (
         "lock decl %0",
         Outputs  => Unsigned_Addr'Asm_Output ("=m", Addend.Item),
         Volatile => True
      );
   end Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : not null access Atomic_Unsigned_Addr) is
   begin
      Asm (
         "lock decl %0",
         Outputs  => Unsigned_Addr'Asm_Output ("=m", Addend.Item),
         Volatile => True
      );
   end Dec;

   -------------
   -- Dec_Get --
   -------------

   function Dec_Get (Addend : not null access Atomic_Unsigned_Addr;
      Item : Unsigned_Addr) return Unsigned_Addr
   is
      Result : Unsigned_Addr;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_Addr'Asm_Output ("=m", Addend.Item),
                      Unsigned_Addr'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_Addr'Asm_Input ("1", -Item),
         Volatile => True
      );
      return Result - Item;
   end Dec_Get;

   -------------
   -- Get_Dec --
   -------------

   function Get_Dec (Addend : not null access Atomic_Unsigned_Addr;
      Item : Unsigned_Addr) return Unsigned_Addr
   is
      Result : Unsigned_Addr;
   begin
      Asm (
         "lock xaddl %2, %0",
         Outputs  => (Unsigned_Addr'Asm_Output ("=m", Addend.Item),
                      Unsigned_Addr'Asm_Output ("=r", Result)),
         Inputs   => Unsigned_Addr'Asm_Input ("1", -Item),
         Volatile => True
      );
      return Result;
   end Get_Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : in out Atomic_Unsigned_Addr;
      Item : Unsigned_Addr) is
   begin
      Asm (
         "lock subl %1, %0",
         Outputs  => Unsigned_Addr'Asm_Output ("=m", Addend.Item),
         Inputs   => Unsigned_Addr'Asm_Input ("ir", Item),
         Volatile => True
      );
   end Dec;

   ---------
   -- Dec --
   ---------

   procedure Dec (Addend : not null access Atomic_Unsigned_Addr;
      Item : Unsigned_Addr) is
   begin
      Asm (
         "lock subl %1, %0",
         Outputs  => Unsigned_Addr'Asm_Output ("=m", Addend.Item),
         Inputs   => Unsigned_Addr'Asm_Input ("ir", Item),
         Volatile => True
      );
   end Dec;

end Turbo_Private.Atomic;
