The optimization of the expansion of protected procedure for the lock-free
implementation brings the following changes:
- Several renamings in order to match GCC built-in function wordings.
- Expected_Comp declaration moved to the the declarations list of the procedure
- GCC built-in operation__sync_bool_compare_and_swap replaced by
  __sync_val_compare_and_swap.
- Don't use an atomic compare and swap if Expected_Comp = Desired_Comp

Tested on x86_64-pc-linux-gnu, committed on trunk

2012-07-12  Vincent Pucci  <pu...@adacore.com>

        * exp_ch9.adb (Build_Lock_Free_Unprotected_Subprogram_Body):
        Atomic_Load_N replaced by Lock_Free_Read_N. Atomic_Compare_Exchange_N
        replaced by Lock_Free_Try_Write_N.
        Renaming of several local variables. For
        procedure, Expected_Comp declaration moved to the declaration
        list of the procedure.
        * rtsfind.ads: RE_Atomic_Compare_Exchange_8,
        RE_Atomic_Compare_Exchange_16, RE_Atomic_Compare_Exchange_32,
        RE_Atomic_Compare_Exchange_64, RE_Atomic_Load_8,
        RE_Atomic_Load_16, RE_Atomic_Load_32, RE_Atomic_Load_64,
        RE_Atomic_Synchronize, RE_Relaxed removed.  RE_Lock_Free_Read_8,
        RE_Lock_Free_Read_16, RE_Lock_Free_Read_32, RE_Lock_Free_Read_64,
        RE_Lock_Free_Try_Write_8, RE_Lock_Free_Try_Write_16,
        RE_Lock_Free_Try_Write_32, RE_Lock_Free_Try_Write_64 added.
        * s-atopri.adb: New file.
        * s-atopri.ads (Atomic_Compare_Exchange_8): Renaming of
        parameters.  Import primitive __sync_val_compare_and_swap_1.
        (Atomic_Compare_Exchange_16): Renaming of parameters.
        Import primitive __sync_val_compare_and_swap_2.
        (Atomic_Compare_Exchange_32): Renaming of parameters.
        Import primitive __sync_val_compare_and_swap_4.
        (Atomic_Compare_Exchange_64): Renaming of parameters.  Import
        primitive __sync_val_compare_and_swap_8.
        (Atomic_Load_8): Ptr renames parameter X.
        (Atomic_Load_16): Ptr renames parameter X.
        (Atomic_Load_32): Ptr renames parameter X.
        (Atomic_Load_64): Ptr renames parameter X.
        (Lock_Free_Read_8): New routine.
        (Lock_Free_Read_16): New routine.
        (Lock_Free_Read_32): New routine.
        (Lock_Free_Read_64): New routine.
        (Lock_Free_Try_Write_8): New routine.
        (Lock_Free_Try_Write_16): New routine.
        (Lock_Free_Try_Write_32): New routine.
        (Lock_Free_Try_Write_64): New routine.

Index: exp_ch9.adb
===================================================================
--- exp_ch9.adb (revision 189436)
+++ exp_ch9.adb (working copy)
@@ -2955,30 +2955,40 @@
    --  manner:
 
    --    procedure P (...) is
+   --       Expected_Comp : constant Comp_Type :=
+   --                         Comp_Type
+   --                           (System.Atomic_Primitives.Lock_Free_Read_N
+   --                              (_Object.Comp'Address));
    --    begin
    --       loop
    --          declare
    --             <original declarations before the object renaming declaration
    --              of Comp>
-   --             Saved_Comp   : constant ... :=
-   --                              Atomic_Load (_Object.Comp'Address, Relaxed);
-   --             Current_Comp : ... := Saved_Comp;
-   --             Comp         : Comp_Type renames Current_Comp;
+   --
+   --             Desired_Comp : Comp_Type := Expected_Comp;
+   --             Comp         : Comp_Type renames Desired_Comp;
+   --
    --             <original delarations after the object renaming declaration
    --              of Comp>
+   --
    --          begin
    --             <original statements>
-   --             exit when Atomic_Compare
-   --                         (_Object.Comp, Saved_Comp, Current_Comp);
+   --             exit when System.Atomic_Primitives.Lock_Free_Try_Write_N
+   --                         (_Object.Comp'Address,
+   --                          Interfaces.Unsigned_N (Expected_Comp),
+   --                          Interfaces.Unsigned_N (Desired_Comp));
    --          end;
-   --          <<L0>>
    --       end loop;
    --    end P;
 
    --  Each return and raise statement of P is transformed into an atomic
    --  status check:
 
-   --    if Atomic_Compare (_Object.Comp, Saved_Comp, Current_Comp) then
+   --    if System.Atomic_Primitives.Lock_Free_Try_Write_N
+   --         (_Object.Comp'Address,
+   --          Interfaces.Unsigned_N (Expected_Comp),
+   --          Interfaces.Unsigned_N (Desired_Comp));
+   --    then
    --       <original statement>
    --    else
    --       goto L0;
@@ -2991,10 +3001,16 @@
    --    function F (...) return ... is
    --       <original declarations before the object renaming declaration
    --        of Comp>
-   --       Saved_Comp : constant ... := Atomic_Load (_Object.Comp'Address);
-   --       Comp       : Comp_Type renames Saved_Comp;
+   --
+   --       Expected_Comp : constant Comp_Type :=
+   --                         Comp_Type
+   --                           (System.Atomic_Primitives.Lock_Free_Read_N
+   --                              (_Object.Comp'Address));
+   --       Comp          : Comp_Type renames Expected_Comp;
+   --
    --       <original delarations after the object renaming declaration of
    --        Comp>
+   --
    --    begin
    --       <original statements>
    --    end F;
@@ -3003,11 +3019,6 @@
      (N        : Node_Id;
       Prot_Typ : Node_Id) return Node_Id
    is
-      Is_Procedure : constant Boolean    :=
-                       Ekind (Corresponding_Spec (N)) = E_Procedure;
-      Loc          : constant Source_Ptr := Sloc (N);
-      Label_Id     : Entity_Id := Empty;
-
       function Referenced_Component (N : Node_Id) return Entity_Id;
       --  Subprograms which meet the lock-free implementation criteria are
       --  allowed to reference only one unique component. Return the prival
@@ -3068,9 +3079,10 @@
 
       --  Local variables
 
-      Comp          : constant Entity_Id := Referenced_Component (N);
-      Hand_Stmt_Seq : Node_Id            := Handled_Statement_Sequence (N);
-      Decls         : List_Id            := Declarations (N);
+      Comp          : constant Entity_Id  := Referenced_Component (N);
+      Loc           : constant Source_Ptr := Sloc (N);
+      Hand_Stmt_Seq : Node_Id             := Handled_Statement_Sequence (N);
+      Decls         : List_Id             := Declarations (N);
 
    --  Start of processing for Build_Lock_Free_Unprotected_Subprogram_Body
 
@@ -3088,20 +3100,25 @@
             Comp_Decl    : constant Node_Id   := Parent (Comp);
             Comp_Sel_Nam : constant Node_Id   := Name (Comp_Decl);
             Comp_Type    : constant Entity_Id := Etype (Comp);
-            Block_Decls  : List_Id;
-            Compare      : Entity_Id;
-            Current_Comp : Entity_Id;
-            Decl         : Node_Id;
-            Label        : Node_Id;
-            Load         : Entity_Id;
-            Load_Params  : List_Id;
-            Saved_Comp   : Entity_Id;
-            Stmt         : Node_Id;
-            Stmts        : List_Id :=
-                             New_Copy_List (Statements (Hand_Stmt_Seq));
-            Typ_Size     : Int;
-            Unsigned     : Entity_Id;
 
+            Is_Procedure : constant Boolean :=
+                             Ekind (Corresponding_Spec (N)) = E_Procedure;
+            --  Indicates if N is a protected procedure body
+
+            Block_Decls   : List_Id;
+            Try_Write     : Entity_Id;
+            Desired_Comp  : Entity_Id;
+            Decl          : Node_Id;
+            Label         : Node_Id;
+            Label_Id      : Entity_Id := Empty;
+            Read          : Entity_Id;
+            Expected_Comp : Entity_Id;
+            Stmt          : Node_Id;
+            Stmts         : List_Id :=
+                              New_Copy_List (Statements (Hand_Stmt_Seq));
+            Typ_Size      : Int;
+            Unsigned      : Entity_Id;
+
             function Process_Node (N : Node_Id) return Traverse_Result;
             --  Transform a single node if it is a return statement, a raise
             --  statement or a reference to Comp.
@@ -3110,10 +3127,10 @@
             --  Given a statement sequence Stmts, wrap any return or raise
             --  statements in the following manner:
             --
-            --    if System.Atomic_Primitives.Atomic_Compare_Exchange
-            --         (Comp'Address,
-            --          Interfaces.Unsigned (Saved_Comp),
-            --          Interfaces.Unsigned (Current_Comp))
+            --    if System.Atomic_Primitives.Lock_Free_Try_Write_N
+            --         (_Object.Comp'Address,
+            --          Interfaces.Unsigned_N (Expected_Comp),
+            --          Interfaces.Unsigned_N (Desired_Comp))
             --    then
             --       <Stmt>;
             --    else
@@ -3149,10 +3166,10 @@
 
                   --  Generate:
 
-                  --    if System.Atomic_Primitives.Atomic_Compare_Exchange
-                  --         (Comp'Address,
-                  --          Interfaces.Unsigned (Saved_Comp),
-                  --          Interfaces.Unsigned (Current_Comp))
+                  --    if System.Atomic_Primitives.Lock_Free_Try_Write_N
+                  --         (_Object.Comp'Address,
+                  --          Interfaces.Unsigned_N (Expected_Comp),
+                  --          Interfaces.Unsigned_N (Desired_Comp))
                   --    then
                   --       <Stmt>;
                   --    else
@@ -3164,17 +3181,17 @@
                       Condition =>
                         Make_Function_Call (Loc,
                           Name                   =>
-                            New_Reference_To (Compare, Loc),
+                            New_Reference_To (Try_Write, Loc),
                           Parameter_Associations => New_List (
                             Make_Attribute_Reference (Loc,
                               Prefix         => Relocate_Node (Comp_Sel_Nam),
                               Attribute_Name => Name_Address),
 
                             Unchecked_Convert_To (Unsigned,
-                              New_Reference_To (Saved_Comp, Loc)),
+                              New_Reference_To (Expected_Comp, Loc)),
 
                             Unchecked_Convert_To (Unsigned,
-                              New_Reference_To (Current_Comp, Loc)))),
+                              New_Reference_To (Desired_Comp, Loc)))),
 
                       Then_Statements => New_List (Relocate_Node (Stmt)),
 
@@ -3253,67 +3270,53 @@
 
             case Typ_Size is
                when 8 =>
-                  Compare  := RTE (RE_Atomic_Compare_Exchange_8);
-                  Load     := RTE (RE_Atomic_Load_8);
-                  Unsigned := RTE (RE_Uint8);
+                  Try_Write := RTE (RE_Lock_Free_Try_Write_8);
+                  Read      := RTE (RE_Lock_Free_Read_8);
+                  Unsigned  := RTE (RE_Uint8);
 
                when 16 =>
-                  Compare  := RTE (RE_Atomic_Compare_Exchange_16);
-                  Load     := RTE (RE_Atomic_Load_16);
-                  Unsigned := RTE (RE_Uint16);
+                  Try_Write := RTE (RE_Lock_Free_Try_Write_16);
+                  Read      := RTE (RE_Lock_Free_Read_16);
+                  Unsigned  := RTE (RE_Uint16);
 
                when 32 =>
-                  Compare  := RTE (RE_Atomic_Compare_Exchange_32);
-                  Load     := RTE (RE_Atomic_Load_32);
-                  Unsigned := RTE (RE_Uint32);
+                  Try_Write := RTE (RE_Lock_Free_Try_Write_32);
+                  Read      := RTE (RE_Lock_Free_Read_32);
+                  Unsigned  := RTE (RE_Uint32);
 
                when 64 =>
-                  Compare  := RTE (RE_Atomic_Compare_Exchange_64);
-                  Load     := RTE (RE_Atomic_Load_64);
-                  Unsigned := RTE (RE_Uint64);
+                  Try_Write := RTE (RE_Lock_Free_Try_Write_64);
+                  Read      := RTE (RE_Lock_Free_Read_64);
+                  Unsigned  := RTE (RE_Uint64);
 
                when others =>
                   raise Program_Error;
             end case;
 
             --  Generate:
-            --    For functions:
 
-            --       Saved_Comp : constant Comp_Type :=
-            --                      Comp_Type (Atomic_Load (Comp'Address));
+            --  Expected_Comp : constant Comp_Type :=
+            --                    Comp_Type
+            --                      (System.Atomic_Primitives.Lock_Free_Read_N
+            --                         (_Object.Comp'Address));
 
-            --    For procedures:
-
-            --       Saved_Comp : constant Comp_Type :=
-            --                      Comp_Type (Atomic_Load (Comp'Address),
-            --                                             Relaxed);
-
-            Saved_Comp :=
+            Expected_Comp :=
               Make_Defining_Identifier (Loc,
                 New_External_Name (Chars (Comp), Suffix => "_saved"));
 
-            Load_Params := New_List (
-              Make_Attribute_Reference (Loc,
-                Prefix         => Relocate_Node (Comp_Sel_Nam),
-                Attribute_Name => Name_Address));
-
-            --  For protected procedures, set the memory model to be relaxed
-
-            if Is_Procedure then
-               Append_To (Load_Params,
-                 New_Reference_To (RTE (RE_Relaxed), Loc));
-            end if;
-
             Decl :=
               Make_Object_Declaration (Loc,
-                Defining_Identifier => Saved_Comp,
-                Constant_Present    => True,
+                Defining_Identifier => Expected_Comp,
                 Object_Definition   => New_Reference_To (Comp_Type, Loc),
+                Constant_Present    => True,
                 Expression          =>
                   Unchecked_Convert_To (Comp_Type,
                     Make_Function_Call (Loc,
-                      Name                   => New_Reference_To (Load, Loc),
-                      Parameter_Associations => Load_Params)));
+                      Name                   => New_Reference_To (Read, Loc),
+                      Parameter_Associations => New_List (
+                        Make_Attribute_Reference (Loc,
+                          Prefix         => Relocate_Node (Comp_Sel_Nam),
+                          Attribute_Name => Name_Address)))));
 
             --  Protected procedures
 
@@ -3322,37 +3325,35 @@
 
                Block_Decls := Decls;
 
-               --  Reset the declarations list of the protected procedure to be
-               --  an empty list.
+               --  Reset the declarations list of the protected procedure to
+               --  contain only Decl.
 
-               Decls := Empty_List;
+               Decls := New_List (Decl);
 
                --  Generate:
-               --    Current_Comp : Comp_Type := Saved_Comp;
+               --    Desired_Comp : Comp_Type := Expected_Comp;
 
-               Current_Comp :=
+               Desired_Comp :=
                  Make_Defining_Identifier (Loc,
                    New_External_Name (Chars (Comp), Suffix => "_current"));
 
-               --  Insert the declarations of Saved_Comp and Current_Comp in
+               --  Insert the declarations of Expected_Comp and Desired_Comp in
                --  the block declarations right before the renaming of the
                --  protected component.
 
-               Insert_Before (Comp_Decl, Decl);
-
                Insert_Before (Comp_Decl,
                  Make_Object_Declaration (Loc,
-                   Defining_Identifier => Current_Comp,
+                   Defining_Identifier => Desired_Comp,
                    Object_Definition   => New_Reference_To (Comp_Type, Loc),
                    Expression          =>
-                     New_Reference_To (Saved_Comp, Loc)));
+                     New_Reference_To (Expected_Comp, Loc)));
 
             --  Protected function
 
             else
-               Current_Comp := Saved_Comp;
+               Desired_Comp := Expected_Comp;
 
-               --  Insert the declaration of Saved_Comp in the function
+               --  Insert the declaration of Expected_Comp in the function
                --  declarations right before the renaming of the protected
                --  component.
 
@@ -3360,10 +3361,10 @@
             end if;
 
             --  Rewrite the protected component renaming declaration to be a
-            --  renaming of Current_Comp.
+            --  renaming of Desired_Comp.
 
             --  Generate:
-            --    Comp : Comp_Type renames Current_Comp;
+            --    Comp : Comp_Type renames Desired_Comp;
 
             Rewrite (Comp_Decl,
               Make_Object_Renaming_Declaration (Loc,
@@ -3372,7 +3373,7 @@
                 Subtype_Mark      =>
                   New_Occurrence_Of (Comp_Type, Loc),
                 Name              =>
-                  New_Reference_To (Current_Comp, Loc)));
+                  New_Reference_To (Desired_Comp, Loc)));
 
             --  Wrap any return or raise statements in Stmts in same the manner
             --  described in Process_Stmts.
@@ -3381,10 +3382,10 @@
 
             --  Generate:
 
-            --    exit when System.Atomic_Primitives.Atomic_Compare_Exchange
-            --                (Comp'Address,
-            --                 Interfaces.Unsigned (Saved_Comp),
-            --                 Interfaces.Unsigned (Current_Comp))
+            --    exit when System.Atomic_Primitives.Lock_Free_Try_Write_N
+            --                (_Object.Comp'Address,
+            --                 Interfaces.Unsigned_N (Expected_Comp),
+            --                 Interfaces.Unsigned_N (Desired_Comp))
 
             if Is_Procedure then
                Stmt :=
@@ -3392,17 +3393,17 @@
                    Condition =>
                      Make_Function_Call (Loc,
                        Name                   =>
-                         New_Reference_To (Compare, Loc),
+                         New_Reference_To (Try_Write, Loc),
                        Parameter_Associations => New_List (
                          Make_Attribute_Reference (Loc,
                            Prefix         => Relocate_Node (Comp_Sel_Nam),
                            Attribute_Name => Name_Address),
 
                          Unchecked_Convert_To (Unsigned,
-                           New_Reference_To (Saved_Comp, Loc)),
+                           New_Reference_To (Expected_Comp, Loc)),
 
                          Unchecked_Convert_To (Unsigned,
-                           New_Reference_To (Current_Comp, Loc)))));
+                           New_Reference_To (Desired_Comp, Loc)))));
 
                --  Small optimization: transform the default return statement
                --  of a procedure into the atomic exit statement.
@@ -3439,9 +3440,6 @@
             if Is_Procedure then
                Stmts :=
                  New_List (
-                   Make_Procedure_Call_Statement (Loc,
-                      Name =>
-                        New_Reference_To (RTE (RE_Atomic_Synchronize), Loc)),
                    Make_Loop_Statement (Loc,
                      Statements => New_List (
                        Make_Block_Statement (Loc,
Index: rtsfind.ads
===================================================================
--- rtsfind.ads (revision 189431)
+++ rtsfind.ads (working copy)
@@ -731,16 +731,14 @@
      RE_Assert_Failure,                  -- System.Assertions
      RE_Raise_Assert_Failure,            -- System.Assertions
 
-     RE_Atomic_Compare_Exchange_8,       -- System.Atomic_Primitives
-     RE_Atomic_Compare_Exchange_16,      -- System.Atomic_Primitives
-     RE_Atomic_Compare_Exchange_32,      -- System.Atomic_Primitives
-     RE_Atomic_Compare_Exchange_64,      -- System.Atomic_Primitives
-     RE_Atomic_Load_8,                   -- System.Atomic_Primitives
-     RE_Atomic_Load_16,                  -- System.Atomic_Primitives
-     RE_Atomic_Load_32,                  -- System.Atomic_Primitives
-     RE_Atomic_Load_64,                  -- System.Atomic_Primitives
-     RE_Atomic_Synchronize,              -- System.Atomic_Primitives
-     RE_Relaxed,                         -- System.Atomic_Primitives
+     RE_Lock_Free_Read_8,                -- System.Atomic_Primitives
+     RE_Lock_Free_Read_16,               -- System.Atomic_Primitives
+     RE_Lock_Free_Read_32,               -- System.Atomic_Primitives
+     RE_Lock_Free_Read_64,               -- System.Atomic_Primitives
+     RE_Lock_Free_Try_Write_8,           -- System.Atomic_Primitives
+     RE_Lock_Free_Try_Write_16,          -- System.Atomic_Primitives
+     RE_Lock_Free_Try_Write_32,          -- System.Atomic_Primitives
+     RE_Lock_Free_Try_Write_64,          -- System.Atomic_Primitives
      RE_Uint8,                           -- System.Atomic_Primitives
      RE_Uint16,                          -- System.Atomic_Primitives
      RE_Uint32,                          -- System.Atomic_Primitives
@@ -1955,16 +1953,14 @@
      RE_Assert_Failure                   => System_Assertions,
      RE_Raise_Assert_Failure             => System_Assertions,
 
-     RE_Atomic_Compare_Exchange_8        => System_Atomic_Primitives,
-     RE_Atomic_Compare_Exchange_16       => System_Atomic_Primitives,
-     RE_Atomic_Compare_Exchange_32       => System_Atomic_Primitives,
-     RE_Atomic_Compare_Exchange_64       => System_Atomic_Primitives,
-     RE_Atomic_Load_8                    => System_Atomic_Primitives,
-     RE_Atomic_Load_16                   => System_Atomic_Primitives,
-     RE_Atomic_Load_32                   => System_Atomic_Primitives,
-     RE_Atomic_Load_64                   => System_Atomic_Primitives,
-     RE_Atomic_Synchronize               => System_Atomic_Primitives,
-     RE_Relaxed                          => System_Atomic_Primitives,
+     RE_Lock_Free_Read_8                 => System_Atomic_Primitives,
+     RE_Lock_Free_Read_16                => System_Atomic_Primitives,
+     RE_Lock_Free_Read_32                => System_Atomic_Primitives,
+     RE_Lock_Free_Read_64                => System_Atomic_Primitives,
+     RE_Lock_Free_Try_Write_8            => System_Atomic_Primitives,
+     RE_Lock_Free_Try_Write_16           => System_Atomic_Primitives,
+     RE_Lock_Free_Try_Write_32           => System_Atomic_Primitives,
+     RE_Lock_Free_Try_Write_64           => System_Atomic_Primitives,
      RE_Uint8                            => System_Atomic_Primitives,
      RE_Uint16                           => System_Atomic_Primitives,
      RE_Uint32                           => System_Atomic_Primitives,
Index: s-atopri.adb
===================================================================
--- s-atopri.adb        (revision 0)
+++ s-atopri.adb        (revision 0)
@@ -0,0 +1,128 @@
+------------------------------------------------------------------------------
+--                                                                          --
+--                         GNAT RUN-TIME COMPONENTS                         --
+--                                                                          --
+--               S Y S T E M . A T O M I C _ P R I M I T I V E S            --
+--                                                                          --
+--                                 B o d y                                  --
+--                                                                          --
+--              Copyright (C) 2012, Free Software Foundation, Inc.          --
+--                                                                          --
+-- GNAT is free software;  you can  redistribute it  and/or modify it under --
+-- terms of the  GNU General Public License as published  by the Free Soft- --
+-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
+-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
+-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
+-- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
+--                                                                          --
+-- As a special exception under Section 7 of GPL version 3, you are granted --
+-- additional permissions described in the GCC Runtime Library Exception,   --
+-- version 3.1, as published by the Free Software Foundation.               --
+--                                                                          --
+-- You should have received a copy of the GNU General Public License and    --
+-- a copy of the GCC Runtime Library Exception along with this program;     --
+-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
+-- <http://www.gnu.org/licenses/>.                                          --
+--                                                                          --
+-- GNAT was originally developed  by the GNAT team at  New York University. --
+-- Extensive contributions were provided by Ada Core Technologies Inc.      --
+--                                                                          --
+------------------------------------------------------------------------------
+
+package body System.Atomic_Primitives is
+   ---------------------------
+   -- Lock_Free_Try_Write_8 --
+   ---------------------------
+
+   function Lock_Free_Try_Write_8
+      (Ptr       : Address;
+       Expected  : in out uint8;
+       Desired   : uint8) return Boolean
+   is
+      Actual : uint8;
+
+   begin
+      if Expected /= Desired then
+         Actual := Atomic_Compare_Exchange_8 (Ptr, Expected, Desired);
+
+         if Actual /= Expected then
+            Expected := Actual;
+            return False;
+         end if;
+      end if;
+
+      return True;
+   end Lock_Free_Try_Write_8;
+
+   ----------------------------
+   -- Lock_Free_Try_Write_16 --
+   ----------------------------
+
+   function Lock_Free_Try_Write_16
+      (Ptr       : Address;
+       Expected  : in out uint16;
+       Desired   : uint16) return Boolean
+   is
+      Actual : uint16;
+
+   begin
+      if Expected /= Desired then
+         Actual := Atomic_Compare_Exchange_16 (Ptr, Expected, Desired);
+
+         if Actual /= Expected then
+            Expected := Actual;
+            return False;
+         end if;
+      end if;
+
+      return True;
+   end Lock_Free_Try_Write_16;
+
+   ----------------------------
+   -- Lock_Free_Try_Write_32 --
+   ----------------------------
+
+   function Lock_Free_Try_Write_32
+      (Ptr       : Address;
+       Expected  : in out uint32;
+       Desired   : uint32) return Boolean
+   is
+      Actual : uint32;
+
+   begin
+      if Expected /= Desired then
+         Actual := Atomic_Compare_Exchange_32 (Ptr, Expected, Desired);
+
+         if Actual /= Expected then
+            Expected := Actual;
+            return False;
+         end if;
+      end if;
+
+      return True;
+   end Lock_Free_Try_Write_32;
+
+   ----------------------------
+   -- Lock_Free_Try_Write_64 --
+   ----------------------------
+
+   function Lock_Free_Try_Write_64
+      (Ptr       : Address;
+       Expected  : in out uint64;
+       Desired   : uint64) return Boolean
+   is
+      Actual : uint64;
+
+   begin
+      if Expected /= Desired then
+         Actual := Atomic_Compare_Exchange_64 (Ptr, Expected, Desired);
+
+         if Actual /= Expected then
+            Expected := Actual;
+            return False;
+         end if;
+      end if;
+
+      return True;
+   end Lock_Free_Try_Write_64;
+end System.Atomic_Primitives;
Index: s-atopri.ads
===================================================================
--- s-atopri.ads        (revision 189431)
+++ s-atopri.ads        (working copy)
@@ -29,11 +29,10 @@
 --                                                                          --
 ------------------------------------------------------------------------------
 
---  This package contains atomic primitives defined from gcc built-in functions
+--  This package contains both atomic primitives defined from gcc built-in
+--  functions and operations used by the compiler to generate the lock-free
+--  implementation of protected objects.
 
---  For now, these operations are only used by the compiler to generate the
---  lock-free implementation of protected objects.
-
 package System.Atomic_Primitives is
    pragma Preelaborate;
 
@@ -59,19 +58,24 @@
 
    subtype Mem_Model is Integer range Relaxed .. Last;
 
+   ------------------------------------
+   -- GCC built-in atomic primitives --
+   ------------------------------------
+
    function Atomic_Compare_Exchange_8
-     (X             : Address;
-      X_Old         : uint8;
-      X_Copy        : uint8) return Boolean;
+     (Ptr      : Address;
+      Expected : uint8;
+      Desired  : uint8) return uint8;
    pragma Import (Intrinsic,
                   Atomic_Compare_Exchange_8,
-                  "__sync_bool_compare_and_swap_1");
+                  "__sync_val_compare_and_swap_1");
 
    --  ??? Should use __atomic_compare_exchange_1 (doesn't work yet):
    --  function Atomic_Compare_Exchange_8
-   --    (X             : Address;
-   --     X_Old         : Address;
-   --     X_Copy        : uint8;
+   --    (Ptr           : Address;
+   --     Expected      : Address;
+   --     Desired       : uint8;
+   --     Weak          : Boolean   := False;
    --     Success_Model : Mem_Model := Seq_Cst;
    --     Failure_Model : Mem_Model := Seq_Cst) return Boolean;
    --  pragma Import (Intrinsic,
@@ -79,49 +83,100 @@
    --                 "__atomic_compare_exchange_1");
 
    function Atomic_Compare_Exchange_16
-     (X             : Address;
-      X_Old         : uint16;
-      X_Copy        : uint16) return Boolean;
+     (Ptr      : Address;
+      Expected : uint16;
+      Desired  : uint16) return uint16;
    pragma Import (Intrinsic,
                   Atomic_Compare_Exchange_16,
-                  "__sync_bool_compare_and_swap_2");
+                  "__sync_val_compare_and_swap_2");
 
    function Atomic_Compare_Exchange_32
-     (X             : Address;
-      X_Old         : uint32;
-      X_Copy        : uint32) return Boolean;
+     (Ptr      : Address;
+      Expected : uint32;
+      Desired  : uint32) return uint32;
    pragma Import (Intrinsic,
                   Atomic_Compare_Exchange_32,
-                  "__sync_bool_compare_and_swap_4");
+                  "__sync_val_compare_and_swap_4");
 
    function Atomic_Compare_Exchange_64
-     (X             : Address;
-      X_Old         : uint64;
-      X_Copy        : uint64) return Boolean;
+     (Ptr      : Address;
+      Expected : uint64;
+      Desired  : uint64) return uint64;
    pragma Import (Intrinsic,
                   Atomic_Compare_Exchange_64,
-                  "__sync_bool_compare_and_swap_8");
+                  "__sync_val_compare_and_swap_8");
 
    function Atomic_Load_8
-     (X     : Address;
+     (Ptr   : Address;
       Model : Mem_Model := Seq_Cst) return uint8;
    pragma Import (Intrinsic, Atomic_Load_8, "__atomic_load_1");
 
    function Atomic_Load_16
-     (X     : Address;
+     (Ptr   : Address;
       Model : Mem_Model := Seq_Cst) return uint16;
    pragma Import (Intrinsic, Atomic_Load_16, "__atomic_load_2");
 
    function Atomic_Load_32
-     (X     : Address;
+     (Ptr   : Address;
       Model : Mem_Model := Seq_Cst) return uint32;
    pragma Import (Intrinsic, Atomic_Load_32, "__atomic_load_4");
 
    function Atomic_Load_64
-     (X     : Address;
+     (Ptr   : Address;
       Model : Mem_Model := Seq_Cst) return uint64;
    pragma Import (Intrinsic, Atomic_Load_64, "__atomic_load_8");
 
-   procedure Atomic_Synchronize;
-   pragma Import (Intrinsic, Atomic_Synchronize, "__sync_synchronize");
+   --------------------------
+   -- Lock-free operations --
+   --------------------------
+
+   --  The lock-free implementation uses two atomic instructions for the
+   --  expansion of protected operations:
+
+   --  * Lock_Free_Read_N atomically loads the value of the protected component
+   --    accessed by the current protected operation.
+
+   --  * Lock_Free_Try_Write_N tries to write the the Desired value into Ptr
+   --    only if Expected and Desired mismatch.
+
+   function Lock_Free_Read_8 (Ptr : Address) return uint8 is
+     (Atomic_Load_8 (Ptr, Acquire));
+
+   function Lock_Free_Read_16 (Ptr : Address) return uint16 is
+      (Atomic_Load_16 (Ptr, Acquire));
+
+   function Lock_Free_Read_32 (Ptr : Address) return uint32 is
+      (Atomic_Load_32 (Ptr, Acquire));
+
+   function Lock_Free_Read_64 (Ptr : Address) return uint64 is
+      (Atomic_Load_64 (Ptr, Acquire));
+
+   function Lock_Free_Try_Write_8
+      (Ptr       : Address;
+       Expected  : in out uint8;
+       Desired   : uint8) return Boolean;
+
+   function Lock_Free_Try_Write_16
+      (Ptr       : Address;
+       Expected  : in out uint16;
+       Desired   : uint16) return Boolean;
+
+   function Lock_Free_Try_Write_32
+      (Ptr       : Address;
+       Expected  : in out uint32;
+       Desired   : uint32) return Boolean;
+
+   function Lock_Free_Try_Write_64
+      (Ptr       : Address;
+       Expected  : in out uint64;
+       Desired   : uint64) return Boolean;
+
+   pragma Inline (Lock_Free_Read_8);
+   pragma Inline (Lock_Free_Read_16);
+   pragma Inline (Lock_Free_Read_32);
+   pragma Inline (Lock_Free_Read_64);
+   pragma Inline (Lock_Free_Try_Write_8);
+   pragma Inline (Lock_Free_Try_Write_16);
+   pragma Inline (Lock_Free_Try_Write_32);
+   pragma Inline (Lock_Free_Try_Write_64);
 end System.Atomic_Primitives;

Reply via email to