CVS difference for ai12s/ai12-0321-1.txt

Differences between 1.4 and version 1.5
Log of other versions for file ai12s/ai12-0321-1.txt

--- ai12s/ai12-0321-1.txt	2019/03/12 04:55:54	1.4
+++ ai12s/ai12-0321-1.txt	2019/03/15 05:39:29	1.5
@@ -85,7 +85,7 @@
 An atomic flag object can either be considered to be set or cleared.
 
 Atomic_Test_And_Set performs an atomic test-and-set operation on Item.
-Item is set to some implementation defined nonzero value. The function returns 
+Item is set to some implementation-defined nonzero value. The function returns 
 True if the previous contents were nonzero, and otherwise returns False.
 
 Atomic_Clear performs an atomic clear operation on Item. After the
@@ -94,13 +94,13 @@
 
 C.6.4  The Package System.Atomic_Operations.Arithmetic
 
-The language-defined package System.Atomic_Operations.Arithmetic
+The language-defined generic package System.Atomic_Operations.Arithmetic
 provides operations to perform arithmetic atomically on objects of
-modular types.
+integer types.
 
 Static Semantics
 
-The library package System.Atomic_Operations.Arithmetic has the
+The generic library package System.Atomic_Operations.Arithmetic has the
 following declaration:
 
 generic
@@ -131,32 +131,33 @@
 
 end System.Atomic_Operations.Arithmetic;
 
+The operations of this package are defined as follows:
 
-   procedure Atomic_Add (Item  : aliased in out Atomic_Type;
-                         Value : Atomic_Type)
-      with Intrinsic;
+procedure Atomic_Add (Item  : aliased in out Atomic_Type;
+                      Value : Atomic_Type)
+   with Convention => Intrinsic;
 
-      Atomically performs: Item := Item + Value;
+   Atomically performs: Item := Item + Value;
 
-   procedure Atomic_Subtract (Item  : aliased in out Atomic_Type;
-                              Value : Atomic_Type)
-    with Intrinsic;
+procedure Atomic_Subtract (Item  : aliased in out Atomic_Type;
+                           Value : Atomic_Type)
+   with Convention => Intrinsic;
 
-      Atomically performs: Item := Item - Value;
+   Atomically performs: Item := Item - Value;
 
 
-   function Atomic_Fetch_And_Add (Item  : aliased in out Atomic_Type;
-                                  Value : Atomic_Type) return Atomic_Type
-    with Intrinsic;
+function Atomic_Fetch_And_Add (Item  : aliased in out Atomic_Type;
+                               Value : Atomic_Type) return Atomic_Type
+   with Convention => Intrinsic;
 
-     Atomically performs: Tmp := Item; Item := Item + Value; return Tmp;
+   Atomically performs: Tmp := Item; Item := Item + Value; return Tmp;
 
 
-   function Atomic_Fetch_And_Subtract (Item  : aliased in out Atomic_Type;
-                                       Value : Atomic_Type) return Atomic_Type
-    with Intrinsic;
+function Atomic_Fetch_And_Subtract (Item  : aliased in out Atomic_Type;
+                                    Value : Atomic_Type) return Atomic_Type
+   with Convention => Intrinsic;
 
-     Atomically performs: Tmp := Item; Item := Item - Value; return Tmp;
+   Atomically performs: Tmp := Item; Item := Item - Value; return Tmp;
 
 !discussion
 
@@ -177,6 +178,118 @@
 for overflow checks, so checking for overflow is needed. But if
 extra performance is needed, those checks can be suppressed.
 
+!corrigendum C.6.3
+
+@dinsc
+
+The language-defined package System.Atomic_Operations.Test_And_Set
+provides an operation to atomically set and clear an atomic flag object.
+
+@s8<@i<Static Semantics>>
+
+The library package System.Atomic_Operations.Test_And_Set has the
+following declaration:
+
+@xcode<@b<package> System.Atomic_Operations.Test_And_Set
+   @b<with> Pure, Nonblocking @b<is>>
+
+@xcode<   @b<type> Test_And_Set_Flag @b<is mod> @ft<@i<implementation-defined>>
+      @b<with> Atomic, Default_Value =@> 0, Size =@> @ft<@i<implementation-defined>>;>
+
+@xcode<   @b<function> Atomic_Test_And_Set
+     (Item : @b<aliased in out> Test_And_Set_Flag) @b<return> Boolean
+      @b<with> Convention =@> Intrinsic;>
+
+@xcode<   @b<procedure> Atomic_Clear
+     (Item : @b<aliased in out> Test_And_Set_Flag)
+      @b<with> Convention =@> Intrinsic;>
+
+@xcode<   @b<function> Is_Lock_Free
+     (Item : @b<aliased> Test_And_Set_Flag) @b<return> Boolean
+      @b<with> Convention =@> Intrinsic;>
+
+@xcode<@b<end> System.Atomic_Operations.Test_And_Set;>
+
+Test_And_Set_Flag represents the state of an atomic flag object.
+An atomic flag object can either be considered to be set or cleared.
+
+Atomic_Test_And_Set performs an atomic test-and-set operation on Item.
+Item is set to some implementation-defined nonzero value. The function returns 
+True if the previous contents were nonzero, and otherwise returns False.
+
+Atomic_Clear performs an atomic clear operation on Item. After the
+operation, Item contains 0. This call should be used in conjunction with
+Atomic_Test_And_Set.
+
+!corrigendum C.6.4
+
+@dinsc
+
+The language-defined generic package System.Atomic_Operations.Arithmetic
+provides operations to perform arithmetic atomically on objects of
+integer types.
+
+@s8<@i<Static Semantics>>
+
+The generic library package System.Atomic_Operations.Arithmetic has the
+following declaration:
+
+@xcode<@b<generic>
+   @b<type> Atomic_Type @b<is range> <@> @b<with> Atomic;
+@b<package> System.Atomic_Operations.Arithmetic
+   @b<with> Pure, Nonblocking @b<is>>
+
+@xcode<   @b<procedure> Atomic_Add (Item  : @b<aliased in out> Atomic_Type;
+                         Value : Atomic_Type)
+       @b<with> Convention =@> Intrinsic;>
+
+@xcode<   @b<procedure> Atomic_Subtract (Item  : @b<aliased in out> Atomic_Type;
+                              Value : Atomic_Type)
+       @b<with> Convention =@> Intrinsic;>
+
+@xcode<   @b<function> Atomic_Fetch_And_Add
+      (Item  : @b<aliased in out> Atomic_Type;
+       Value : Atomic_Type) @b<return> Atomic_Type
+       @b<with> Convention =@> Intrinsic;>
+
+@xcode<   @b<function> Atomic_Fetch_And_Subtract
+      (Item  : @b<aliased in out> Atomic_Type;
+       Value : Atomic_Type) @b<return> Atomic_Type
+       @b<with> Convention =@> Intrinsic;>
+
+@xcode<   @b<function> Is_Lock_Free (Item : @b<aliased> Atomic_Type) @b<return> Boolean
+       @b<with> Convention =@> Intrinsic;>
+
+@xcode<@b<end> System.Atomic_Operations.Arithmetic;>
+
+The operations of this package are defined as follows:
+
+@xcode<@b<procedure> Atomic_Add (Item  : @b<aliased in out> Atomic_Type;
+                     Value : Atomic_Type)
+   @b<with> Convention =@> Intrinsic;>
+
+@xindent<Atomically performs: @fc<Item := Item + Value;>>
+
+@xcode<@b<procedure> Atomic_Subtract (Item  : @b<aliased in out> Atomic_Type;
+                           Value : Atomic_Type)
+   @b<with> Convention =@> Intrinsic;>
+
+@xindent<Atomically performs: @fc<Item := Item - Value;>>
+
+@xcode<@b<function> Atomic_Fetch_And_Add
+   (Item  : @b<aliased in out> Atomic_Type;
+    Value : Atomic_Type) @b<return> Atomic_Type
+   @b<with> Convention =@> Intrinsic;>
+
+@xindent<Atomically performs: @fc<Tmp := Item; Item := Item + Value; @b<return> Tmp;>>
+
+@xcode<@b<function> Atomic_Fetch_And_Subtract
+   (Item  : @b<aliased in out> Atomic_Type;
+    Value : Atomic_Type) @b<return> Atomic_Type
+   @b<with> Convention =@> Intrinsic;>
+
+@xindent<Atomically performs: @fc<Tmp := Item; Item := Item - Value; @b<return> Tmp;>>
+
 !ASIS
 
 No ASIS effect.
@@ -276,6 +389,367 @@
 Using signed arithmetic means there is a need to check for arithmetic overflow,
 but that can be done without looping, and if performance is an issue, the
 overflow checks can be suppressed.
+
+****************************************************************
+
+From: Brad Moore
+Sent: Wednesday, March 13, 2019  12:22 AM
+
+In the recent electronic ARG meeting, we were discussing the 
+Atomic_Operations.Arithmetic package.
+
+It was mentioned that the Bitwise operations that were defined in AI12-0321-1 
+did not make sense if the generic formal type is a signed integer type, so we 
+decided to drop those subprograms from the AI. The thought was that Atomic 
+Addition and Subtraction is likely the most common need to support, 
+and that Bitwise operations seemed to be much less of a need.
+
+I mentioned that prior to Saturday, the generic formal of the Arithmetic 
+package was a modular type, but that I had changed it to signed integer, 
+due to perceived issues with dealing with addition and subtraction, when the 
+modulus of the generic formal type was not a multiple of the machines storage 
+element size.
+
+The decision to have the Arithmetic package only support the Add and Subtract, 
+still makes sense to me.
+
+But I am now thinking we were a bit too hasty in tossing out the bitwise 
+subprograms.
+
+After thinking about it, I think atomically modifying and testing bits 
+atomically is probably something that could be quite useful.
+
+Something I might have used for example, in my Paraffin libraries.
+
+If we wanted to support atomic bitwise operations, I think we'd want to limit 
+the support to modular types whose modulus is a power of two.
+
+That way, one cannot get into trouble setting or clearing bits of the generic
+formal modular type.
+All bit patterns (for values less than the 2**modulus) are valid bit patterns,
+so there would be no need to add additional checks on the results of these 
+operations. 
+
+Fortunately, that restriction could easily be enforced by placing the 
+following assert in the generic package.
+
+ --  Only Modular types whose modulus is a power of 2 are allowed
+   pragma Assert ((Atomic_Type'Base (Atomic_Type'Modulus) and
+                    Atomic_Type'Base (Atomic_Type'Modulus - 1)) = 0);
+
+Since adding these functions would be very similar to the wording for adding 
+the Atomic_Operations.Arithmetic package, I think we should consider adding 
+the following which supports three operations, "or", "and", and "xor";
+
+generic
+   type Atomic_Type is mod <>  with Atomic;
+package System.Atomic_Operations.Bitwise with Pure, Nonblocking
+is
+   
+   --  Only Modular types whose modulus is a power of 2 are allowed
+   pragma Assert ((Atomic_Type'Base (Atomic_Type'Modulus) and
+                    Atomic_Type'Base (Atomic_Type'Modulus - 1)) = 0);
+
+
+   procedure Atomic_Bitwise_And (Item  : aliased in out Atomic_Type;
+                                 Value : Atomic_Type)
+     with Convention => Intrinsic;
+
+   procedure Atomic_Bitwise_Or (Item  : aliased in out Atomic_Type;
+                                Value : Atomic_Type)
+     with Convention => Intrinsic;
+
+   procedure Atomic_Bitwise_Xor (Item  : aliased in out Atomic_Type;
+                                 Value : Atomic_Type)
+     with Convention => Intrinsic;
+
+
+   function Atomic_Fetch_And_Bitwise_And
+     (Item  : aliased in out Atomic_Type;
+      Value : Atomic_Type) return Atomic_Type
+     with Convention => Intrinsic;
+
+   function Atomic_Fetch_And_Bitwise_Or
+     (Item  : aliased in out Atomic_Type;
+      Value : Atomic_Type) return Atomic_Type
+     with Convention => Intrinsic;
+
+   function Atomic_Fetch_And_Bitwise_Xor
+     (Item  : aliased in out Atomic_Type;
+      Value : Atomic_Type) return Atomic_Type
+     with Convention => Intrinsic;
+
+   function Is_Lock_Free
+     (Item : aliased Atomic_Type) return Boolean
+     with Convention => Intrinsic, Nonblocking
+
+end System.Atomic_Operations.Bitwise;
+
+I'd be happy to write this up (likely as a new AI if it cant be added to 
+AI12-0321-1.
+
+Thoughts?
+
+***************************************************************
+
+From: Randy Brukardt
+Sent: Wednesday, March 13, 2019  12:49 AM
+
+...
+> Fortunately, that restriction could easily be enforced by placing the 
+> following assert in the generic package.
+> 
+>  --  Only Modular types whose modulus is a power of 2 are allowed
+>    pragma Assert ((Atomic_Type'Base (Atomic_Type'Modulus) and
+>                     Atomic_Type'Base (Atomic_Type'Modulus - 1)) = 0);
+
+I think this Assertion always raises Constraint_Error (or is illegal).
+Atomic_Type'Modulus is a universal_integer value, and those do not wrap. 
+For all T, T'Modulus > T'Last. Ergo, T'Modulus is out of range. If T'Modulus 
+was static (as it might be in an instance), then the type conversion is 
+illegal.
+
+You need to somehow use 'Mod. However, T'Mod(T'Modulus) is always 0.
+
+I've usually had to declare a Big_Mod type for this sort of thing:
+     type Big_Mod is mod System.Max_Binary_Modulus; 
+and then you can write your expression, so long as you pretest for modulii 
+that are too large. Which is a royal mess. :-)
+
+Anyway, you need to go back to the drawing board with this assertion. 
+
+****************************************************************
+
+From: Brad Moore
+Sent: Wednesday, March 13, 2019  1:32 AM
+
+> I think this Assertion always raises Constraint_Error (or is illegal).
+> Atomic_Type'Modulus is a universal_integer value, and those do not 
+> wrap. For all T, T'Modulus > T'Last. Ergo, T'Modulus is out of range. 
+> If T'Modulus was static (as it might be in an instance), then the type 
+> conversion is illegal.
+
+I knew that Atomic_Type'Modulus is a universal_integer value, which is why 
+I converted that result to the Atomic_Type'Base subtype, which allows me to 
+do the bitwise and operation.
+
+I tried this with GNAT, and it compiles, and works fine in my test program.
+
+When I try it with a type such as
+
+type Mod_5 is mod 5;
+
+It correctly tells me that an exception will be raised at runtime.
+(since the modulus of that subtype is not a power of 2)
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, March 13, 2019  8:40 AM
+
+In any case, I think we should leave these out for now, as they are less
+critical than add/subtract.
+
+It is easy enough to write such a package yourself if you know what you are 
+doing.  Here we are looking for widely useful capabilities that need 
+standardization.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Wednesday, March 13, 2019  3:41 PM
+
+> I knew that Atomic_Type'Modulus is a universal_integer value, which is 
+> why I converted that result to the Atomic_Type'Base subtype, which 
+> allows me to do the bitwise and operation.
+
+Yes, and that conversion always raises Constraint_Error (or is illegal if the 
+type is static).
+
+> I tried this with GNAT, and it compiles, and works fine in my test 
+> program.
+
+Either you didn't actually test what you think you did, or GNAT is wrong.
+4.6(28) clearly states that Constraint_Error is raised for a value outside of 
+the base range of a modular type. T'Modulus is by definition outside of the 
+base range of T. And 4.9 states that a static expression is illegal if it 
+raises any exception other than an overflow.
+
+Now, I know that if you compiled this with Janus/Ada, it would in fact work 
+with at least some types, but that would be because Janus/Ada doesn't 
+properly handle these conversions when found in a generic. In particular, 
+T'Modulus of mod 2**32 has the special value zero at runtime so we can handle 
+such types correctly, but that would of course cause oddities if actually used
+explicitly. But just because it would work doesn't make it right.
+
+So I wouldn't be surprised if it accidentally worked for Max_Binary_Modulus, 
+but I wouldn't take that as some sort of assumption that it should work. I'd 
+suggest trying it in a non-generic case to see.
+
+I'm pretty sure that there is an ACATS test that checks this rule, but perhaps
+it could use some beefing up.
+
+> When I try it with a type such as
+> 
+> type Mod_5 is mod 5;
+> 
+> It correctly tells me that an exception will be raised at runtime.
+> (since the modulus of that subtype is not a power of 2)
+
+Surely this is true, since it *always* raises Constraint_Error.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, March 13, 2019  4:30 PM
+
+Another test that should work, I believe, is:
+
+    pragma Assert (T'Modulus = 2 ** T'Size);
+
+unless the 'Size has been explicitly specified to be larger.
+
+Or if you want to go whole hog:
+
+   pragma Assert((for some I in 1..T'Size => T'Modulus = 2**I));
+
+though now you are getting into non-static expressions, so Constraint_Error
+becomes more likely if you bump up against the Max_Integer limits of run-time
+universal-int computations.
+
+;-)
+
+****************************************************************
+
+From: Bob Duff
+Sent: Wednesday, March 13, 2019  6:00 PM
+
+>    pragma Assert((for some I in 1..T'Size => T'Modulus = 2**I));
+
+For "type T is mod 1;", T'Size = 0, 2**T'Size = 1, and T'Modulus = 1.
+
+;-)
+
+Note to Brad:  Unlike signed integers, the base range of a modular type is
+widened beyond the first subtype.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, March 13, 2019  7:27 PM
+
+Yes, I realized that, but I was somehow unable to allow myself to include the 
+"mod 1" option. ;-)
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, March 13, 2019  7:33 PM
+
+> Note to Brad:  Unlike signed integers, the base range of a modular 
+> type is widened beyond the first subtype.
+
+What does this mean?  Did you mean the base range is *not* widened?
+
+****************************************************************
+
+From: Bob Duff
+Sent: Wednesday, March 13, 2019  8:12 PM
+
+Yes, thanks for the correction.
+
+****************************************************************
+
+From: Brad Moore
+Sent: Wednesday, March 13, 2019  11:30 PM
+
+Thanks for the explanations.
+
+By the way, the reason I thought the following example was OK, is because 
+I didn't have the "enable assertions" checkbox checked, for the project file.
+
+Oddly, I do get a warning if I uncomment the assert below, which says that 
+an assertion would fail at run time. But I don't get any warnings otherwise, 
+and the code runs successfully.
+
+If I enable assertions, then the code does not compile, as Randy said.
+
+
+with Ada.Text_IO;
+use Ada.Text_IO;
+
+procedure Main is
+   type Mod_8 is mod 2**3;
+   type Mod_5 is mod 5;
+
+   type Mod_16 is mod 2**4;
+   
+   type Mod_32 is mod 2**5;
+   
+   pragma Assert ((Mod_8'Base (Mod_8'Modulus) and
+                    Mod_8'Base (Mod_8'Modulus - 1)) = 0);
+   
+   pragma Assert ((Mod_16'Base (Mod_16'Modulus) and
+                    Mod_16'Base (Mod_16'Modulus - 1)) = 0);
+
+   pragma Assert ((Mod_32'Base (Mod_32'Modulus) and
+                    Mod_32'Base (Mod_32'Modulus - 1)) = 0);
+
+--   pragma Assert (((Mod_5'Base (Mod_5'Modulus) and
+--                      Mod_5'Base (Mod_5'Modulus - 1)) = 0));
+   
+   X : Mod_8;
+   X2 : Mod_16;
+   X3 : Mod_32;
+begin
+   
+   X := 4;
+   X := X + 7;
+   X2 := 4;
+   X2 := X2 + 14;
+   X3 := 5;
+   X3 := X3 + 30;
+
+   Put_Line ("Mod8:" & Mod_8'Image (X));
+   Put_Line ("Mod16:" & Mod_16'Image (X2));
+   Put_Line ("Mod32:" & Mod_32'Image (X3));
+   
+end Main;
+
+****************************************************************
+
+From: Brad Moore
+Sent: Wednesday, March 13, 2019  11:39 PM
+
+Thanks for the suggestion, that works (the first simpler version, at least) 
+for my example. A nice concise way to express this property. 
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Thursday, March 14, 2019  7:21 PM
+
+> >    pragma Assert((for some I in 1..T'Size => T'Modulus = 2**I));
+> 
+> For "type T is mod 1;", T'Size = 0, 2**T'Size = 1, and T'Modulus = 1.
+> 
+> ;-)
+
+Tucker noted that it isn't a very good assertion, since someone could
+declare:
+
+    type Biggie is mod 256 with Atomic, Size => 16;
+
+OTOH, we could decide to explicitly not care about such corner cases.
+ 
+> Note to Brad:  Unlike signed integers, the base range of a modular 
+> type is widened beyond the first subtype.
+
+Every time I read this, I'm confused. I even went and looked it up in the RM
+to be sure. I think there is a "not" missing somewhere. Perhaps you meant:
+
+   Note to Brad:  Unlike signed integers, the base range of a 
+   modular type is NOT widened beyond the first subtype.
 
 ****************************************************************
 

Questions? Ask the ACAA Technical Agent