aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2024-03-13 17:05:12 +0100
committerMarc Poulhiès <poulhies@adacore.com>2024-05-20 09:47:02 +0200
commit5d6c099ffaa384425f33d4e3a52f55149b9bc99a (patch)
treed2b0aca9d34e22f7a17829cebebbe6217f631353
parentd3b4ba120ce3b743838c3545a24554989955722a (diff)
downloadgcc-5d6c099ffaa384425f33d4e3a52f55149b9bc99a.zip
gcc-5d6c099ffaa384425f33d4e3a52f55149b9bc99a.tar.gz
gcc-5d6c099ffaa384425f33d4e3a52f55149b9bc99a.tar.bz2
ada: Rework and augment documentation on strict aliasing
The documentation was originally centered around pragma No_Strict_Aliasing and pragma Universal_Aliasing was mentioned only as an afterthought. It also contained a warning about the usage of overlays implemented by means of address clauses that has been obsolete for long. gcc/ada/ * doc/gnat_rm/implementation_defined_pragmas.rst (Universal_Aliasing): Remove reference to No_Strict_Aliasing. * doc/gnat_ugn/gnat_and_program_execution.rst (Optimization and Strict Aliasinng): Simplify first example and make it more consistent with the second. Add description of the effects of pragma Universal_Aliasing and document new warning issued for unchecked conversions. Remove obsolete stuff. * gnat_rm.texi: Regenerate. * gnat_ugn.texi: Regenerate.
-rw-r--r--gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst7
-rw-r--r--gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst296
-rw-r--r--gcc/ada/gnat_rm.texi7
-rw-r--r--gcc/ada/gnat_ugn.texi306
4 files changed, 353 insertions, 263 deletions
diff --git a/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst b/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst
index 7f221e3..bcbd859 100644
--- a/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst
+++ b/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst
@@ -6949,10 +6949,9 @@ Syntax:
``type_LOCAL_NAME`` must refer to a type declaration in the current
declarative part. The effect is to inhibit strict type-based aliasing
-optimization for the given type. In other words, the effect is as though
-access types designating this type were subject to pragma No_Strict_Aliasing.
-For a detailed description of the strict aliasing optimization, and the
-situations in which it must be suppressed, see the section on
+optimizations for the given type. For a detailed description of the
+strict type-based aliasing optimizations and the situations in which
+they need to be suppressed, see the section on
``Optimization and Strict Aliasing`` in the :title:`GNAT User's Guide`.
.. _Pragma-Unmodified:
diff --git a/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst b/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst
index 35e3477..d502da8 100644
--- a/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst
+++ b/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst
@@ -2072,37 +2072,36 @@ the following example:
.. code-block:: ada
- procedure R is
+ procedure M is
type Int1 is new Integer;
+ I1 : Int1;
+
type Int2 is new Integer;
- type Int1A is access Int1;
- type Int2A is access Int2;
- Int1V : Int1A;
- Int2V : Int2A;
+ type A2 is access Int2;
+ V2 : A2;
...
begin
...
for J in Data'Range loop
- if Data (J) = Int1V.all then
- Int2V.all := Int2V.all + 1;
+ if Data (J) = I1 then
+ V2.all := V2.all + 1;
end if;
end loop;
...
- end R;
+ end;
-In this example, since the variable ``Int1V`` can only access objects
-of type ``Int1``, and ``Int2V`` can only access objects of type
-``Int2``, there is no possibility that the assignment to
-``Int2V.all`` affects the value of ``Int1V.all``. This means that
-the compiler optimizer can "know" that the value ``Int1V.all`` is constant
-for all iterations of the loop and avoid the extra memory reference
-required to dereference it each time through the loop.
+In this example, since ``V2`` can only access objects of type ``Int2``
+and ``I1`` is not one of them, there is no possibility that the assignment
+to ``V2.all`` affects the value of ``I1``. This means that the compiler
+optimizer can infer that the value ``I1`` is constant for all iterations
+of the loop and load it from memory only once, before entering the loop,
+instead of in every iteration (this is called load hoisting).
-This kind of optimization, called strict aliasing analysis, is
+This kind of optimizations, based on strict type-based aliasing, is
triggered by specifying an optimization level of :switch:`-O2` or
-higher or :switch:`-Os` and allows GNAT to generate more efficient code
-when access values are involved.
+higher (or :switch:`-Os`) and allows the compiler to generate more
+efficient code.
However, although this optimization is always correct in terms of
the formal semantics of the Ada Reference Manual, difficulties can
@@ -2111,173 +2110,214 @@ the typing system. Consider the following complete program example:
.. code-block:: ada
- package p1 is
- type int1 is new integer;
- type int2 is new integer;
- type a1 is access int1;
- type a2 is access int2;
- end p1;
+ package P1 is
+ type Int1 is new Integer;
+ type A1 is access Int1;
+
+ type Int2 is new Integer;
+ type A2 is access Int2;
+ end P1;
- with p1; use p1;
- package p2 is
- function to_a2 (Input : a1) return a2;
+ with P1; use P1;
+ package P2 is
+ function To_A2 (Input : A1) return A2;
end p2;
with Ada.Unchecked_Conversion;
- package body p2 is
- function to_a2 (Input : a1) return a2 is
- function to_a2u is
- new Ada.Unchecked_Conversion (a1, a2);
+ package body P2 is
+ function To_A2 (Input : A1) return A2 is
+ function Conv is
+ new Ada.Unchecked_Conversion (A1, A2);
begin
- return to_a2u (Input);
- end to_a2;
- end p2;
+ return Conv (Input);
+ end To_A2;
+ end P2;
- with p2; use p2;
- with p1; use p1;
+ with P1; use P1;
+ with P2; use P2;
with Text_IO; use Text_IO;
- procedure m is
- v1 : a1 := new int1;
- v2 : a2 := to_a2 (v1);
+ procedure M is
+ V1 : A1 := new Int1;
+ V2 : A2 := To_A2 (V1);
begin
- v1.all := 1;
- v2.all := 0;
- put_line (int1'image (v1.all));
+ V1.all := 1;
+ V2.all := 0;
+ Put_Line (Int1'Image (V1.all));
end;
-This program prints out 0 in :switch:`-O0` or :switch:`-O1`
-mode, but it prints out 1 in :switch:`-O2` mode. That's
-because in strict aliasing mode, the compiler can and
-does assume that the assignment to ``v2.all`` could not
-affect the value of ``v1.all``, since different types
-are involved.
+This program prints out ``0`` in :switch:`-O0` or :switch:`-O1` modes,
+but it prints out ``1`` in :switch:`-O2` mode. That's because in strict
+aliasing mode, the compiler may and does assume that the assignment to
+``V2.all`` could not affect the value of ``V1.all``, since different
+types are involved.
This behavior is not a case of non-conformance with the standard, since
the Ada RM specifies that an unchecked conversion where the resulting
bit pattern is not a correct value of the target type can result in an
abnormal value and attempting to reference an abnormal value makes the
execution of a program erroneous. That's the case here since the result
-does not point to an object of type ``int2``. This means that the
-effect is entirely unpredictable.
+does not point to an object of type ``Int2``. This means that the effect
+is entirely unpredictable.
-However, although that explanation may satisfy a language
-lawyer, in practice an applications programmer expects an
-unchecked conversion involving pointers to create true
-aliases and the behavior of printing 1 seems plain wrong.
-In this case, the strict aliasing optimization is unwelcome.
+However, although that explanation may satisfy a language lawyer, in
+practice an application programmer expects an unchecked conversion
+involving pointers to create true aliases and the behavior of printing
+``1`` is questionable. In this case, the strict type-based aliasing
+optimizations are clearly unwelcome.
-Indeed the compiler recognizes this possibility, and the
-unchecked conversion generates a warning:
+Indeed the compiler recognizes this possibility and the instantiation of
+Unchecked_Conversion generates a warning:
::
- p2.adb:5:07: warning: possible aliasing problem with type "a2"
+ p2.adb:5:07: warning: possible aliasing problem with type "A2"
p2.adb:5:07: warning: use -fno-strict-aliasing switch for references
- p2.adb:5:07: warning: or use "pragma No_Strict_Aliasing (a2);"
+ p2.adb:5:07: warning: or use "pragma No_Strict_Aliasing (A2);"
-Unfortunately the problem is recognized when compiling the body of
-package ``p2``, but the actual "bad" code is generated while
-compiling the body of ``m`` and this latter compilation does not see
-the suspicious ``Unchecked_Conversion``.
+Unfortunately the problem is only recognized when compiling the body of
+package ``P2``, but the actual problematic code is generated while
+compiling the body of ``M`` and this latter compilation does not see
+the suspicious instance of ``Unchecked_Conversion``.
As implied by the warning message, there are approaches you can use to
-avoid the unwanted strict aliasing optimization in a case like this.
+avoid the unwanted strict aliasing optimizations in a case like this.
One possibility is to simply avoid the use of :switch:`-O2`, but
-that is a bit drastic, since it throws away a number of useful
+that is quite drastic, since it throws away a number of useful
optimizations that do not involve strict aliasing assumptions.
A less drastic approach is to compile the program using the
option :switch:`-fno-strict-aliasing`. Actually it is only the
unit containing the dereferencing of the suspicious pointer
that needs to be compiled. So in this case, if we compile
-unit ``m`` with this switch, then we get the expected
+unit ``M`` with this switch, then we get the expected
value of zero printed. Analyzing which units might need
the switch can be painful, so a more reasonable approach
is to compile the entire program with options :switch:`-O2`
and :switch:`-fno-strict-aliasing`. If the performance is
satisfactory with this combination of options, then the
-advantage is that the entire issue of possible "wrong"
-optimization due to strict aliasing is avoided.
+advantage is that the entire issue of possible problematic
+optimizations due to strict aliasing is avoided.
To avoid the use of compiler switches, the configuration
pragma ``No_Strict_Aliasing`` with no parameters may be
used to specify that for all access types, the strict
-aliasing optimization should be suppressed.
+aliasing optimizations should be suppressed.
-However, these approaches are still overkill, in that they causes
+However, these approaches are still overkill, in that they cause
all manipulations of all access values to be deoptimized. A more
refined approach is to concentrate attention on the specific
access type identified as problematic.
-First, if a careful analysis of uses of the pointer shows
-that there are no possible problematic references, then
-the warning can be suppressed by bracketing the
-instantiation of ``Unchecked_Conversion`` to turn
-the warning off:
+The first possibility is to move the instantiation of unchecked
+conversion to the unit in which the type is declared. In this
+example, we would move the instantiation of ``Unchecked_Conversion``
+from the body of package ``P2`` to the spec of package ``P1``.
+Now the warning disappears because any use of the access type
+knows there is a suspicious unchecked conversion, and the strict
+aliasing optimizations are automatically suppressed for it.
+
+If it is not practical to move the unchecked conversion to the same unit
+in which the destination access type is declared (perhaps because the
+source type is not visible in that unit), the second possibiliy is to
+use pragma ``No_Strict_Aliasing`` for the type. This pragma must occur
+in the same declarative part as the declaration of the access type:
.. code-block:: ada
- pragma Warnings (Off);
- function to_a2u is
- new Ada.Unchecked_Conversion (a1, a2);
- pragma Warnings (On);
+ type A2 is access Int2;
+ pragma No_Strict_Aliasing (A2);
-Of course that approach is not appropriate for this particular
-example, since indeed there is a problematic reference. In this
-case we can take one of two other approaches.
+Here again, the compiler now knows that strict aliasing optimizations
+should be suppressed for any dereference made through type ``A2`` and
+the expected behavior is obtained.
-The first possibility is to move the instantiation of unchecked
-conversion to the unit in which the type is declared. In
-this example, we would move the instantiation of
-``Unchecked_Conversion`` from the body of package
-``p2`` to the spec of package ``p1``. Now the
-warning disappears. That's because any use of the
-access type knows there is a suspicious unchecked
-conversion, and the strict aliasing optimization
-is automatically suppressed for the type.
-
-If it is not practical to move the unchecked conversion to the same unit
-in which the destination access type is declared (perhaps because the
-source type is not visible in that unit), you may use pragma
-``No_Strict_Aliasing`` for the type. This pragma must occur in the
-same declarative sequence as the declaration of the access type:
+The third possibility is to declare that one of the designated types
+involved, namely ``Int1`` or ``Int2``, is allowed to alias any other
+type in the universe, by using pragma ``Universal_Aliasing``:
.. code-block:: ada
- type a2 is access int2;
- pragma No_Strict_Aliasing (a2);
-
-Here again, the compiler now knows that the strict aliasing optimization
-should be suppressed for any reference to type ``a2`` and the
-expected behavior is obtained.
-
-Finally, note that although the compiler can generate warnings for
-simple cases of unchecked conversions, there are tricker and more
-indirect ways of creating type incorrect aliases which the compiler
-cannot detect. Examples are the use of address overlays and unchecked
-conversions involving composite types containing access types as
-components. In such cases, no warnings are generated, but there can
-still be aliasing problems. One safe coding practice is to forbid the
-use of address clauses for type overlaying, and to allow unchecked
-conversion only for primitive types. This is not really a significant
-restriction since any possible desired effect can be achieved by
-unchecked conversion of access values.
-
-The aliasing analysis done in strict aliasing mode can certainly
-have significant benefits. We have seen cases of large scale
-application code where the time is increased by up to 5% by turning
-this optimization off. If you have code that includes significant
-usage of unchecked conversion, you might want to just stick with
-:switch:`-O1` and avoid the entire issue. If you get adequate
-performance at this level of optimization level, that's probably
-the safest approach. If tests show that you really need higher
-levels of optimization, then you can experiment with :switch:`-O2`
-and :switch:`-O2 -fno-strict-aliasing` to see how much effect this
+ type Int2 is new Integer;
+ pragma Universal_Aliasing (Int2);
+
+The effect is equivalent to applying pragma ``No_Strict_Aliasing`` to
+every access type designating ``Int2``, in particular ``A2``, and more
+generally to every reference made to an object of declared type ``Int2``,
+so it is very powerful and effectively takes ``Int2`` out of the alias
+analysis performed by the compiler in all circumstances.
+
+This pragma can also be used to deal with aliasing issues that arise
+again from the use of ``Unchecked_Conversion`` in the source code but
+without the presence of access types. The typical example is code
+that streams data by means of arrays of storage units (bytes):
+
+ .. code-block:: ada
+
+ type Byte is mod 2**System.Storage_Unit;
+ for Byte'Size use System.Storage_Unit;
+
+ type Chunk_Of_Bytes is array (1 .. 64) of Byte;
+
+ procedure Send (S : Chunk_Of_Bytes);
+
+ type Rec is record
+ ...
+ end record;
+
+ procedure Dump (R : Rec) is
+ function To_Stream is
+ new Ada.Unchecked_Conversion (Rec, Chunk_Of_Bytes);
+ begin
+ Send (To_Stream (R));
+ end;
+
+This generates the following warning for the call to ``Send``:
+
+ ::
+
+ dump.adb:8:25: warning: unchecked conversion implemented by copy
+ dump.adb:8:25: warning: use pragma Universal_Aliasing on either type
+ dump.adb:8:25: warning: to enable RM 13.9(12) implementation permission
+
+This occurs because the formal parameter ``S`` of ``Send`` is passed by
+reference by the compiler and it is not possible to pass a reference to
+``R`` directly in the call without violating strict type-based aliasing.
+That's why the compiler generates a temporary of type ``Chunk_Of_Bytes``
+just before the call and passes a reference to this temporary instead.
+
+As implied by the warning message, it is possible to avoid the temporary
+(and the warning) by means of pragma ``Universal_Aliasing``:
+
+ .. code-block:: ada
+
+ type Chunk_Of_Bytes is array (1 .. 64) of Byte;
+ pragma Universal_Aliasing (Chunk_Of_Bytes);
+
+The pragma can also be applied to the component type instead:
+
+ .. code-block:: ada
+
+ type Byte is mod 2**System.Storage_Unit;
+ for Byte'Size use System.Storage_Unit;
+ pragma Universal_Aliasing (Byte);
+
+and every array type whose component is ``Byte`` will inherit the pragma.
+
+To sum up, the alias analysis performed in strict aliasing mode by the
+compiler can have significant benefits. We have seen cases of large scale
+application code where the execution time is increased by up to 5% when
+these optimizations are turned off. However, if you have code that make
+significant use of unchecked conversion, you might want to just stick
+with :switch:`-O1` and avoid the entire issue. If you get adequate
+performance at this level of optimization, that's probably the safest
+approach. If tests show that you really need higher levels of
+optimization, then you can experiment with :switch:`-O2` and
+:switch:`-O2 -fno-strict-aliasing` to see how much effect this
has on size and speed of the code. If you really need to use
:switch:`-O2` with strict aliasing in effect, then you should
-review any uses of unchecked conversion of access types,
-particularly if you are getting the warnings described above.
+review any uses of unchecked conversion, particularly if you are
+getting the warnings described above.
.. _Aliased_Variables_and_Optimization:
diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi
index 8dcdd6c..4051612 100644
--- a/gcc/ada/gnat_rm.texi
+++ b/gcc/ada/gnat_rm.texi
@@ -8497,10 +8497,9 @@ pragma Universal_Aliasing [([Entity =>] type_LOCAL_NAME)];
@code{type_LOCAL_NAME} must refer to a type declaration in the current
declarative part. The effect is to inhibit strict type-based aliasing
-optimization for the given type. In other words, the effect is as though
-access types designating this type were subject to pragma No_Strict_Aliasing.
-For a detailed description of the strict aliasing optimization, and the
-situations in which it must be suppressed, see the section on
+optimizations for the given type. For a detailed description of the
+strict type-based aliasing optimizations and the situations in which
+they need to be suppressed, see the section on
@code{Optimization and Strict Aliasing} in the @cite{GNAT User’s Guide}.
@node Pragma Unmodified,Pragma Unreferenced,Pragma Universal_Aliasing,Implementation Defined Pragmas
diff --git a/gcc/ada/gnat_ugn.texi b/gcc/ada/gnat_ugn.texi
index 7bad8b4..ebc1028 100644
--- a/gcc/ada/gnat_ugn.texi
+++ b/gcc/ada/gnat_ugn.texi
@@ -20716,39 +20716,38 @@ the following example:
@quotation
@example
-procedure R is
+procedure M is
type Int1 is new Integer;
+ I1 : Int1;
+
type Int2 is new Integer;
- type Int1A is access Int1;
- type Int2A is access Int2;
- Int1V : Int1A;
- Int2V : Int2A;
+ type A2 is access Int2;
+ V2 : A2;
...
begin
...
for J in Data'Range loop
- if Data (J) = Int1V.all then
- Int2V.all := Int2V.all + 1;
+ if Data (J) = I1 then
+ V2.all := V2.all + 1;
end if;
end loop;
...
-end R;
+end;
@end example
@end quotation
-In this example, since the variable @code{Int1V} can only access objects
-of type @code{Int1}, and @code{Int2V} can only access objects of type
-@code{Int2}, there is no possibility that the assignment to
-@code{Int2V.all} affects the value of @code{Int1V.all}. This means that
-the compiler optimizer can “know” that the value @code{Int1V.all} is constant
-for all iterations of the loop and avoid the extra memory reference
-required to dereference it each time through the loop.
+In this example, since @code{V2} can only access objects of type @code{Int2}
+and @code{I1} is not one of them, there is no possibility that the assignment
+to @code{V2.all} affects the value of @code{I1}. This means that the compiler
+optimizer can infer that the value @code{I1} is constant for all iterations
+of the loop and load it from memory only once, before entering the loop,
+instead of in every iteration (this is called load hoisting).
-This kind of optimization, called strict aliasing analysis, is
+This kind of optimizations, based on strict type-based aliasing, is
triggered by specifying an optimization level of @code{-O2} or
-higher or @code{-Os} and allows GNAT to generate more efficient code
-when access values are involved.
+higher (or @code{-Os}) and allows the compiler to generate more
+efficient code.
However, although this optimization is always correct in terms of
the formal semantics of the Ada Reference Manual, difficulties can
@@ -20758,184 +20757,237 @@ the typing system. Consider the following complete program example:
@quotation
@example
-package p1 is
- type int1 is new integer;
- type int2 is new integer;
- type a1 is access int1;
- type a2 is access int2;
-end p1;
+package P1 is
+ type Int1 is new Integer;
+ type A1 is access Int1;
-with p1; use p1;
-package p2 is
- function to_a2 (Input : a1) return a2;
+ type Int2 is new Integer;
+ type A2 is access Int2;
+end P1;
+
+with P1; use P1;
+package P2 is
+ function To_A2 (Input : A1) return A2;
end p2;
with Ada.Unchecked_Conversion;
-package body p2 is
- function to_a2 (Input : a1) return a2 is
- function to_a2u is
- new Ada.Unchecked_Conversion (a1, a2);
+package body P2 is
+ function To_A2 (Input : A1) return A2 is
+ function Conv is
+ new Ada.Unchecked_Conversion (A1, A2);
begin
- return to_a2u (Input);
- end to_a2;
-end p2;
+ return Conv (Input);
+ end To_A2;
+end P2;
-with p2; use p2;
-with p1; use p1;
+with P1; use P1;
+with P2; use P2;
with Text_IO; use Text_IO;
-procedure m is
- v1 : a1 := new int1;
- v2 : a2 := to_a2 (v1);
+procedure M is
+ V1 : A1 := new Int1;
+ V2 : A2 := To_A2 (V1);
begin
- v1.all := 1;
- v2.all := 0;
- put_line (int1'image (v1.all));
+ V1.all := 1;
+ V2.all := 0;
+ Put_Line (Int1'Image (V1.all));
end;
@end example
@end quotation
-This program prints out 0 in @code{-O0} or @code{-O1}
-mode, but it prints out 1 in @code{-O2} mode. That’s
-because in strict aliasing mode, the compiler can and
-does assume that the assignment to @code{v2.all} could not
-affect the value of @code{v1.all}, since different types
-are involved.
+This program prints out @code{0} in @code{-O0} or @code{-O1} modes,
+but it prints out @code{1} in @code{-O2} mode. That’s because in strict
+aliasing mode, the compiler may and does assume that the assignment to
+@code{V2.all} could not affect the value of @code{V1.all}, since different
+types are involved.
This behavior is not a case of non-conformance with the standard, since
the Ada RM specifies that an unchecked conversion where the resulting
bit pattern is not a correct value of the target type can result in an
abnormal value and attempting to reference an abnormal value makes the
execution of a program erroneous. That’s the case here since the result
-does not point to an object of type @code{int2}. This means that the
-effect is entirely unpredictable.
+does not point to an object of type @code{Int2}. This means that the effect
+is entirely unpredictable.
-However, although that explanation may satisfy a language
-lawyer, in practice an applications programmer expects an
-unchecked conversion involving pointers to create true
-aliases and the behavior of printing 1 seems plain wrong.
-In this case, the strict aliasing optimization is unwelcome.
+However, although that explanation may satisfy a language lawyer, in
+practice an application programmer expects an unchecked conversion
+involving pointers to create true aliases and the behavior of printing
+@code{1} is questionable. In this case, the strict type-based aliasing
+optimizations are clearly unwelcome.
-Indeed the compiler recognizes this possibility, and the
-unchecked conversion generates a warning:
+Indeed the compiler recognizes this possibility and the instantiation of
+Unchecked_Conversion generates a warning:
@quotation
@example
-p2.adb:5:07: warning: possible aliasing problem with type "a2"
+p2.adb:5:07: warning: possible aliasing problem with type "A2"
p2.adb:5:07: warning: use -fno-strict-aliasing switch for references
-p2.adb:5:07: warning: or use "pragma No_Strict_Aliasing (a2);"
+p2.adb:5:07: warning: or use "pragma No_Strict_Aliasing (A2);"
@end example
@end quotation
-Unfortunately the problem is recognized when compiling the body of
-package @code{p2}, but the actual “bad” code is generated while
-compiling the body of @code{m} and this latter compilation does not see
-the suspicious @code{Unchecked_Conversion}.
+Unfortunately the problem is only recognized when compiling the body of
+package @code{P2}, but the actual problematic code is generated while
+compiling the body of @code{M} and this latter compilation does not see
+the suspicious instance of @code{Unchecked_Conversion}.
As implied by the warning message, there are approaches you can use to
-avoid the unwanted strict aliasing optimization in a case like this.
+avoid the unwanted strict aliasing optimizations in a case like this.
One possibility is to simply avoid the use of @code{-O2}, but
-that is a bit drastic, since it throws away a number of useful
+that is quite drastic, since it throws away a number of useful
optimizations that do not involve strict aliasing assumptions.
A less drastic approach is to compile the program using the
option @code{-fno-strict-aliasing}. Actually it is only the
unit containing the dereferencing of the suspicious pointer
that needs to be compiled. So in this case, if we compile
-unit @code{m} with this switch, then we get the expected
+unit @code{M} with this switch, then we get the expected
value of zero printed. Analyzing which units might need
the switch can be painful, so a more reasonable approach
is to compile the entire program with options @code{-O2}
and @code{-fno-strict-aliasing}. If the performance is
satisfactory with this combination of options, then the
-advantage is that the entire issue of possible “wrong”
-optimization due to strict aliasing is avoided.
+advantage is that the entire issue of possible problematic
+optimizations due to strict aliasing is avoided.
To avoid the use of compiler switches, the configuration
pragma @code{No_Strict_Aliasing} with no parameters may be
used to specify that for all access types, the strict
-aliasing optimization should be suppressed.
+aliasing optimizations should be suppressed.
-However, these approaches are still overkill, in that they causes
+However, these approaches are still overkill, in that they cause
all manipulations of all access values to be deoptimized. A more
refined approach is to concentrate attention on the specific
access type identified as problematic.
-First, if a careful analysis of uses of the pointer shows
-that there are no possible problematic references, then
-the warning can be suppressed by bracketing the
-instantiation of @code{Unchecked_Conversion} to turn
-the warning off:
+The first possibility is to move the instantiation of unchecked
+conversion to the unit in which the type is declared. In this
+example, we would move the instantiation of @code{Unchecked_Conversion}
+from the body of package @code{P2} to the spec of package @code{P1}.
+Now the warning disappears because any use of the access type
+knows there is a suspicious unchecked conversion, and the strict
+aliasing optimizations are automatically suppressed for it.
+
+If it is not practical to move the unchecked conversion to the same unit
+in which the destination access type is declared (perhaps because the
+source type is not visible in that unit), the second possibiliy is to
+use pragma @code{No_Strict_Aliasing} for the type. This pragma must occur
+in the same declarative part as the declaration of the access type:
@quotation
@example
-pragma Warnings (Off);
-function to_a2u is
- new Ada.Unchecked_Conversion (a1, a2);
-pragma Warnings (On);
+type A2 is access Int2;
+pragma No_Strict_Aliasing (A2);
@end example
@end quotation
-Of course that approach is not appropriate for this particular
-example, since indeed there is a problematic reference. In this
-case we can take one of two other approaches.
+Here again, the compiler now knows that strict aliasing optimizations
+should be suppressed for any dereference made through type @code{A2} and
+the expected behavior is obtained.
-The first possibility is to move the instantiation of unchecked
-conversion to the unit in which the type is declared. In
-this example, we would move the instantiation of
-@code{Unchecked_Conversion} from the body of package
-@code{p2} to the spec of package @code{p1}. Now the
-warning disappears. That’s because any use of the
-access type knows there is a suspicious unchecked
-conversion, and the strict aliasing optimization
-is automatically suppressed for the type.
+The third possibility is to declare that one of the designated types
+involved, namely @code{Int1} or @code{Int2}, is allowed to alias any other
+type in the universe, by using pragma @code{Universal_Aliasing}:
-If it is not practical to move the unchecked conversion to the same unit
-in which the destination access type is declared (perhaps because the
-source type is not visible in that unit), you may use pragma
-@code{No_Strict_Aliasing} for the type. This pragma must occur in the
-same declarative sequence as the declaration of the access type:
+@quotation
+
+@example
+type Int2 is new Integer;
+pragma Universal_Aliasing (Int2);
+@end example
+@end quotation
+
+The effect is equivalent to applying pragma @code{No_Strict_Aliasing} to
+every access type designating @code{Int2}, in particular @code{A2}, and more
+generally to every reference made to an object of declared type @code{Int2},
+so it is very powerful and effectively takes @code{Int2} out of the alias
+analysis performed by the compiler in all circumstances.
+
+This pragma can also be used to deal with aliasing issues that arise
+again from the use of @code{Unchecked_Conversion} in the source code but
+without the presence of access types. The typical example is code
+that streams data by means of arrays of storage units (bytes):
@quotation
@example
-type a2 is access int2;
-pragma No_Strict_Aliasing (a2);
+type Byte is mod 2**System.Storage_Unit;
+for Byte'Size use System.Storage_Unit;
+
+type Chunk_Of_Bytes is array (1 .. 64) of Byte;
+
+procedure Send (S : Chunk_Of_Bytes);
+
+type Rec is record
+ ...
+end record;
+
+procedure Dump (R : Rec) is
+ function To_Stream is
+ new Ada.Unchecked_Conversion (Rec, Chunk_Of_Bytes);
+begin
+ Send (To_Stream (R));
+end;
+@end example
+@end quotation
+
+This generates the following warning for the call to @code{Send}:
+
+@quotation
+
+@example
+dump.adb:8:25: warning: unchecked conversion implemented by copy
+dump.adb:8:25: warning: use pragma Universal_Aliasing on either type
+dump.adb:8:25: warning: to enable RM 13.9(12) implementation permission
+@end example
+@end quotation
+
+This occurs because the formal parameter @code{S} of @code{Send} is passed by
+reference by the compiler and it is not possible to pass a reference to
+@code{R} directly in the call without violating strict type-based aliasing.
+That’s why the compiler generates a temporary of type @code{Chunk_Of_Bytes}
+just before the call and passes a reference to this temporary instead.
+
+As implied by the warning message, it is possible to avoid the temporary
+(and the warning) by means of pragma @code{Universal_Aliasing}:
+
+@quotation
+
+@example
+type Chunk_Of_Bytes is array (1 .. 64) of Byte;
+pragma Universal_Aliasing (Chunk_Of_Bytes);
@end example
@end quotation
-Here again, the compiler now knows that the strict aliasing optimization
-should be suppressed for any reference to type @code{a2} and the
-expected behavior is obtained.
-
-Finally, note that although the compiler can generate warnings for
-simple cases of unchecked conversions, there are tricker and more
-indirect ways of creating type incorrect aliases which the compiler
-cannot detect. Examples are the use of address overlays and unchecked
-conversions involving composite types containing access types as
-components. In such cases, no warnings are generated, but there can
-still be aliasing problems. One safe coding practice is to forbid the
-use of address clauses for type overlaying, and to allow unchecked
-conversion only for primitive types. This is not really a significant
-restriction since any possible desired effect can be achieved by
-unchecked conversion of access values.
-
-The aliasing analysis done in strict aliasing mode can certainly
-have significant benefits. We have seen cases of large scale
-application code where the time is increased by up to 5% by turning
-this optimization off. If you have code that includes significant
-usage of unchecked conversion, you might want to just stick with
-@code{-O1} and avoid the entire issue. If you get adequate
-performance at this level of optimization level, that’s probably
-the safest approach. If tests show that you really need higher
-levels of optimization, then you can experiment with @code{-O2}
-and @code{-O2 -fno-strict-aliasing} to see how much effect this
+The pragma can also be applied to the component type instead:
+
+@quotation
+
+@example
+type Byte is mod 2**System.Storage_Unit;
+for Byte'Size use System.Storage_Unit;
+pragma Universal_Aliasing (Byte);
+@end example
+@end quotation
+
+and every array type whose component is @code{Byte} will inherit the pragma.
+
+To sum up, the alias analysis performed in strict aliasing mode by the
+compiler can have significant benefits. We have seen cases of large scale
+application code where the execution time is increased by up to 5% when
+these optimizations are turned off. However, if you have code that make
+significant use of unchecked conversion, you might want to just stick
+with @code{-O1} and avoid the entire issue. If you get adequate
+performance at this level of optimization, that’s probably the safest
+approach. If tests show that you really need higher levels of
+optimization, then you can experiment with @code{-O2} and
+@code{-O2 -fno-strict-aliasing} to see how much effect this
has on size and speed of the code. If you really need to use
@code{-O2} with strict aliasing in effect, then you should
-review any uses of unchecked conversion of access types,
-particularly if you are getting the warnings described above.
+review any uses of unchecked conversion, particularly if you are
+getting the warnings described above.
@node Aliased Variables and Optimization,Atomic Variables and Optimization,Optimization and Strict Aliasing,Performance Considerations
@anchor{gnat_ugn/gnat_and_program_execution aliased-variables-and-optimization}@anchor{18f}@anchor{gnat_ugn/gnat_and_program_execution id37}@anchor{190}
@@ -29580,8 +29632,8 @@ to permit their use in free software.
@printindex ge
-@anchor{d1}@w{ }
@anchor{gnat_ugn/gnat_utility_programs switches-related-to-project-files}@w{ }
+@anchor{d1}@w{ }
@c %**end of body
@bye