| ------------------------------------------------------------------------------ | 
 | --                                                                          -- | 
 | --                         GNAT COMPILER COMPONENTS                         -- | 
 | --                                                                          -- | 
 | --                         G N A T . A L T I V E C                          -- | 
 | --                                                                          -- | 
 | --                                 S p e c                                  -- | 
 | --                                                                          -- | 
 | --          Copyright (C) 2004-2025, 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.      -- | 
 | --                                                                          -- | 
 | ------------------------------------------------------------------------------ | 
 |  | 
 | ------------------------- | 
 | -- General description -- | 
 | ------------------------- | 
 |  | 
 | --  This is the root of a package hierarchy offering an Ada binding to the | 
 | --  PowerPC AltiVec extensions, a set of 128bit vector types together with a | 
 | --  set of subprograms operating on them. Relevant documents are: | 
 |  | 
 | --  o AltiVec Technology, Programming Interface Manual (1999-06) | 
 | --    to which we will refer as [PIM], describes the data types, the | 
 | --    functional interface and the ABI conventions. | 
 |  | 
 | --  o AltiVec Technology, Programming Environments Manual (2002-02) | 
 | --    to which we will refer as [PEM], describes the hardware architecture | 
 | --    and instruction set. | 
 |  | 
 | --  These documents, as well as a number of others of general interest on the | 
 | --  AltiVec technology, are available from the Motorola/AltiVec Web site at: | 
 |  | 
 | --  http://www.freescale.com/altivec | 
 |  | 
 | --  The binding interface is structured to allow alternate implementations: | 
 | --  for real AltiVec capable targets, and for other targets. In the latter | 
 | --  case, everything is emulated in software. The two versions are referred | 
 | --  to as: | 
 |  | 
 | --  o The Hard binding for AltiVec capable targets (with the appropriate | 
 | --    hardware support and corresponding instruction set) | 
 |  | 
 | --  o The Soft binding for other targets (with the low level primitives | 
 | --    emulated in software). | 
 |  | 
 | --  In addition, interfaces that are not strictly part of the base AltiVec API | 
 | --  are provided, such as vector conversions to and from array representations, | 
 | --  which are of interest for client applications (e.g. for vector | 
 | --  initialization purposes). | 
 |  | 
 | --  Only the soft binding is available today | 
 |  | 
 | ----------------------------------------- | 
 | -- General package architecture survey -- | 
 | ----------------------------------------- | 
 |  | 
 | --  The various vector representations are all "containers" of elementary | 
 | --  values, the possible types of which are declared in this root package to | 
 | --  be generally accessible. | 
 |  | 
 | --  From the user standpoint, the binding materializes as a consistent | 
 | --  hierarchy of units: | 
 |  | 
 | --                             GNAT.Altivec | 
 | --                           (component types) | 
 | --                                   | | 
 | --          o----------------o----------------o-------------o | 
 | --          |                |                |             | | 
 | --    Vector_Types   Vector_Operations   Vector_Views   Conversions | 
 |  | 
 | --  Users can manipulate vectors through two families of types: Vector | 
 | --  types and View types. | 
 |  | 
 | --  Vector types are available through the Vector_Types and Vector_Operations | 
 | --  packages, which implement the core binding to the AltiVec API, as | 
 | --  described in [PIM-2.1 data types] and [PIM-4 AltiVec operations and | 
 | --  predicates]. | 
 |  | 
 | --  The layout of Vector objects is dependant on the target machine | 
 | --  endianness, and View types were devised to offer a higher level user | 
 | --  interface. With Views, a vector of 4 uints (1, 2, 3, 4) is always declared | 
 | --  with a VUI_View := (Values => (1, 2, 3, 4)), element 1 first, natural | 
 | --  notation to denote the element values, and indexed notation is available | 
 | --  to access individual elements. | 
 |  | 
 | --  View types do not represent Altivec vectors per se, in the sense that the | 
 | --  Altivec_Operations are not available for them. They are intended to allow | 
 | --  Vector initializations as well as access to the Vector component values. | 
 |  | 
 | --  The GNAT.Altivec.Conversions package is provided to convert a View to the | 
 | --  corresponding Vector and vice-versa. | 
 |  | 
 | --------------------------- | 
 | -- Underlying principles -- | 
 | --------------------------- | 
 |  | 
 | --  Internally, the binding relies on an abstraction of the Altivec API, a | 
 | --  rich set of functions around a core of low level primitives mapping to | 
 | --  AltiVec instructions. See for instance "vec_add" in [PIM-4.4 Generic and | 
 | --  Specific AltiVec operations], with no less than six result/arguments | 
 | --  combinations of byte vector types that map to "vaddubm". | 
 |  | 
 | --  The "soft" version is a software emulation of the low level primitives. | 
 |  | 
 | --  The "hard" version would map to real AltiVec instructions via GCC builtins | 
 | --  and inlining. | 
 |  | 
 | --  See the "Design Notes" section below for additional details on the | 
 | --  internals. | 
 |  | 
 | ------------------- | 
 | -- Example usage -- | 
 | ------------------- | 
 |  | 
 | --  Here is a sample program declaring and initializing two vectors, 'add'ing | 
 | --  them and displaying the result components: | 
 |  | 
 | --  with GNAT.Altivec.Vector_Types;      use GNAT.Altivec.Vector_Types; | 
 | --  with GNAT.Altivec.Vector_Operations; use GNAT.Altivec.Vector_Operations; | 
 | --  with GNAT.Altivec.Vector_Views;      use GNAT.Altivec.Vector_Views; | 
 | --  with GNAT.Altivec.Conversions;       use GNAT.Altivec.Conversions; | 
 |  | 
 | --  use GNAT.Altivec; | 
 |  | 
 | --  with Ada.Text_IO; use Ada.Text_IO; | 
 |  | 
 | --  procedure Sample is | 
 | --     Va : Vector_Unsigned_Int := To_Vector ((Values => (1, 2, 3, 4))); | 
 | --     Vb : Vector_Unsigned_Int := To_Vector ((Values => (1, 2, 3, 4))); | 
 |  | 
 | --     Vs : Vector_Unsigned_Int; | 
 | --     Vs_View : VUI_View; | 
 | --  begin | 
 | --     Vs := Vec_Add (Va, Vb); | 
 | --     Vs_View := To_View (Vs); | 
 |  | 
 | --     for I in Vs_View.Values'Range loop | 
 | --        Put_Line (Unsigned_Int'Image (Vs_View.Values (I))); | 
 | --     end loop; | 
 | --  end; | 
 |  | 
 | --  $ gnatmake sample.adb | 
 | --  [...] | 
 | --  $ ./sample | 
 | --  2 | 
 | --  4 | 
 | --  6 | 
 | --  8 | 
 |  | 
 | ------------------------------------------------------------------------------ | 
 |  | 
 | with System; | 
 |  | 
 | package GNAT.Altivec is | 
 |  | 
 |    --  Definitions of constants and vector/array component types common to all | 
 |    --  the versions of the binding. | 
 |  | 
 |    --  All the vector types are 128bits | 
 |  | 
 |    VECTOR_BIT : constant := 128; | 
 |  | 
 |    ------------------------------------------- | 
 |    -- [PIM-2.3.1 Alignment of vector types] -- | 
 |    ------------------------------------------- | 
 |  | 
 |    --  "A defined data item of any vector data type in memory is always | 
 |    --  aligned on a 16-byte boundary. A pointer to any vector data type always | 
 |    --  points to a 16-byte boundary. The compiler is responsible for aligning | 
 |    --  vector data types on 16-byte boundaries." | 
 |  | 
 |    VECTOR_ALIGNMENT : constant := Natural'Min (16, Standard'Maximum_Alignment); | 
 |    --  This value is used to set the alignment of vector datatypes in both the | 
 |    --  hard and the soft binding implementations. | 
 |    -- | 
 |    --  We want this value to never be greater than 16, because none of the | 
 |    --  binding implementations requires larger alignments and such a value | 
 |    --  would cause useless space to be allocated/wasted for vector objects. | 
 |    --  Furthermore, the alignment of 16 matches the hard binding leading to | 
 |    --  a more faithful emulation. | 
 |    -- | 
 |    --  It needs to be exactly 16 for the hard binding, and the initializing | 
 |    --  expression is just right for this purpose since Maximum_Alignment is | 
 |    --  expected to be 16 for the real Altivec ABI. | 
 |    -- | 
 |    --  The soft binding doesn't rely on strict 16byte alignment, and we want | 
 |    --  the value to be no greater than Standard'Maximum_Alignment in this case | 
 |    --  to ensure it is supported on every possible target. | 
 |  | 
 |    ------------------------------------------------------- | 
 |    -- [PIM-2.1] Data Types - Interpretation of contents -- | 
 |    ------------------------------------------------------- | 
 |  | 
 |    --------------------- | 
 |    -- char components -- | 
 |    --------------------- | 
 |  | 
 |    CHAR_BIT    : constant := 8; | 
 |    SCHAR_MIN   : constant := -2 ** (CHAR_BIT - 1); | 
 |    SCHAR_MAX   : constant := 2 ** (CHAR_BIT - 1) - 1; | 
 |    UCHAR_MAX   : constant := 2 ** CHAR_BIT - 1; | 
 |  | 
 |    type unsigned_char is mod UCHAR_MAX + 1; | 
 |    for unsigned_char'Size use CHAR_BIT; | 
 |  | 
 |    type signed_char is range SCHAR_MIN .. SCHAR_MAX; | 
 |    for signed_char'Size use CHAR_BIT; | 
 |  | 
 |    subtype bool_char is unsigned_char; | 
 |    --  ??? There is a difference here between what the Altivec Technology | 
 |    --  Programming Interface Manual says and what GCC says. In the manual, | 
 |    --  vector_bool_char is a vector_unsigned_char, while in altivec.h it | 
 |    --  is a vector_signed_char. | 
 |  | 
 |    bool_char_True  : constant bool_char := bool_char'Last; | 
 |    bool_char_False : constant bool_char := 0; | 
 |  | 
 |    ---------------------- | 
 |    -- short components -- | 
 |    ---------------------- | 
 |  | 
 |    SHORT_BIT   : constant := 16; | 
 |    SSHORT_MIN  : constant := -2 ** (SHORT_BIT - 1); | 
 |    SSHORT_MAX  : constant := 2 ** (SHORT_BIT - 1) - 1; | 
 |    USHORT_MAX  : constant := 2 ** SHORT_BIT - 1; | 
 |  | 
 |    type unsigned_short is mod USHORT_MAX + 1; | 
 |    for unsigned_short'Size use SHORT_BIT; | 
 |  | 
 |    subtype unsigned_short_int is unsigned_short; | 
 |  | 
 |    type signed_short is range SSHORT_MIN .. SSHORT_MAX; | 
 |    for signed_short'Size use SHORT_BIT; | 
 |  | 
 |    subtype signed_short_int is signed_short; | 
 |  | 
 |    subtype bool_short is unsigned_short; | 
 |    --  ??? See bool_char | 
 |  | 
 |    bool_short_True  : constant bool_short := bool_short'Last; | 
 |    bool_short_False : constant bool_short := 0; | 
 |  | 
 |    subtype bool_short_int is bool_short; | 
 |  | 
 |    -------------------- | 
 |    -- int components -- | 
 |    -------------------- | 
 |  | 
 |    INT_BIT     : constant := 32; | 
 |    SINT_MIN    : constant := -2 ** (INT_BIT - 1); | 
 |    SINT_MAX    : constant := 2 ** (INT_BIT - 1) - 1; | 
 |    UINT_MAX    : constant := 2 ** INT_BIT - 1; | 
 |  | 
 |    type unsigned_int is mod UINT_MAX + 1; | 
 |    for unsigned_int'Size use INT_BIT; | 
 |  | 
 |    type signed_int is range SINT_MIN .. SINT_MAX; | 
 |    for signed_int'Size use INT_BIT; | 
 |  | 
 |    subtype bool_int is unsigned_int; | 
 |    --  ??? See bool_char | 
 |  | 
 |    bool_int_True  : constant bool_int := bool_int'Last; | 
 |    bool_int_False : constant bool_int := 0; | 
 |  | 
 |    ---------------------- | 
 |    -- float components -- | 
 |    ---------------------- | 
 |  | 
 |    FLOAT_BIT   : constant := 32; | 
 |    FLOAT_DIGIT : constant := 6; | 
 |    FLOAT_MIN   : constant := -16#0.FFFF_FF#E+32; | 
 |    FLOAT_MAX   : constant := 16#0.FFFF_FF#E+32; | 
 |  | 
 |    type C_float is digits FLOAT_DIGIT range FLOAT_MIN .. FLOAT_MAX; | 
 |    for C_float'Size use FLOAT_BIT; | 
 |    --  Altivec operations always use the standard native floating-point | 
 |    --  support of the target. Note that this means that there may be | 
 |    --  minor differences in results between targets when the floating- | 
 |    --  point implementations are slightly different, as would happen | 
 |    --  with normal non-Altivec floating-point operations. In particular | 
 |    --  the Altivec simulations may yield slightly different results | 
 |    --  from those obtained on a true hardware Altivec target if the | 
 |    --  floating-point implementation is not 100% compatible. | 
 |  | 
 |    ---------------------- | 
 |    -- pixel components -- | 
 |    ---------------------- | 
 |  | 
 |    subtype pixel is unsigned_short; | 
 |  | 
 |    ----------------------------------------------------------- | 
 |    -- Subtypes for variants found in the GCC implementation -- | 
 |    ----------------------------------------------------------- | 
 |  | 
 |    subtype c_int is signed_int; | 
 |    subtype c_short is c_int; | 
 |  | 
 |    LONG_BIT  : constant := 32; | 
 |    --  Some of the GCC builtins are built with "long" arguments and | 
 |    --  expect SImode to come in. | 
 |  | 
 |    SLONG_MIN : constant := -2 ** (LONG_BIT - 1); | 
 |    SLONG_MAX : constant :=  2 ** (LONG_BIT - 1) - 1; | 
 |    ULONG_MAX : constant :=  2 ** LONG_BIT - 1; | 
 |  | 
 |    type signed_long   is range SLONG_MIN .. SLONG_MAX; | 
 |    type unsigned_long is mod ULONG_MAX + 1; | 
 |  | 
 |    subtype c_long is signed_long; | 
 |  | 
 |    subtype c_ptr is System.Address; | 
 |  | 
 |    --------------------------------------------------------- | 
 |    -- Access types, for the sake of some argument passing -- | 
 |    --------------------------------------------------------- | 
 |  | 
 |    type signed_char_ptr    is access all signed_char; | 
 |    type unsigned_char_ptr  is access all unsigned_char; | 
 |  | 
 |    type short_ptr          is access all c_short; | 
 |    type signed_short_ptr   is access all signed_short; | 
 |    type unsigned_short_ptr is access all unsigned_short; | 
 |  | 
 |    type int_ptr            is access all c_int; | 
 |    type signed_int_ptr     is access all signed_int; | 
 |    type unsigned_int_ptr   is access all unsigned_int; | 
 |  | 
 |    type long_ptr           is access all c_long; | 
 |    type signed_long_ptr    is access all signed_long; | 
 |    type unsigned_long_ptr  is access all unsigned_long; | 
 |  | 
 |    type float_ptr          is access all Float; | 
 |  | 
 |    -- | 
 |  | 
 |    type const_signed_char_ptr    is access constant signed_char; | 
 |    type const_unsigned_char_ptr  is access constant unsigned_char; | 
 |  | 
 |    type const_short_ptr          is access constant c_short; | 
 |    type const_signed_short_ptr   is access constant signed_short; | 
 |    type const_unsigned_short_ptr is access constant unsigned_short; | 
 |  | 
 |    type const_int_ptr            is access constant c_int; | 
 |    type const_signed_int_ptr     is access constant signed_int; | 
 |    type const_unsigned_int_ptr   is access constant unsigned_int; | 
 |  | 
 |    type const_long_ptr           is access constant c_long; | 
 |    type const_signed_long_ptr    is access constant signed_long; | 
 |    type const_unsigned_long_ptr  is access constant unsigned_long; | 
 |  | 
 |    type const_float_ptr          is access constant Float; | 
 |  | 
 |    --  Access to const volatile arguments need specialized types | 
 |  | 
 |    type volatile_float is new Float; | 
 |    pragma Volatile (volatile_float); | 
 |  | 
 |    type volatile_signed_char is new signed_char; | 
 |    pragma Volatile (volatile_signed_char); | 
 |  | 
 |    type volatile_unsigned_char is new unsigned_char; | 
 |    pragma Volatile (volatile_unsigned_char); | 
 |  | 
 |    type volatile_signed_short is new signed_short; | 
 |    pragma Volatile (volatile_signed_short); | 
 |  | 
 |    type volatile_unsigned_short is new unsigned_short; | 
 |    pragma Volatile (volatile_unsigned_short); | 
 |  | 
 |    type volatile_signed_int is new signed_int; | 
 |    pragma Volatile (volatile_signed_int); | 
 |  | 
 |    type volatile_unsigned_int is new unsigned_int; | 
 |    pragma Volatile (volatile_unsigned_int); | 
 |  | 
 |    type volatile_signed_long is new signed_long; | 
 |    pragma Volatile (volatile_signed_long); | 
 |  | 
 |    type volatile_unsigned_long is new unsigned_long; | 
 |    pragma Volatile (volatile_unsigned_long); | 
 |  | 
 |    type constv_char_ptr           is access constant volatile_signed_char; | 
 |    type constv_signed_char_ptr    is access constant volatile_signed_char; | 
 |    type constv_unsigned_char_ptr  is access constant volatile_unsigned_char; | 
 |  | 
 |    type constv_short_ptr          is access constant volatile_signed_short; | 
 |    type constv_signed_short_ptr   is access constant volatile_signed_short; | 
 |    type constv_unsigned_short_ptr is access constant volatile_unsigned_short; | 
 |  | 
 |    type constv_int_ptr            is access constant volatile_signed_int; | 
 |    type constv_signed_int_ptr     is access constant volatile_signed_int; | 
 |    type constv_unsigned_int_ptr   is access constant volatile_unsigned_int; | 
 |  | 
 |    type constv_long_ptr           is access constant volatile_signed_long; | 
 |    type constv_signed_long_ptr    is access constant volatile_signed_long; | 
 |    type constv_unsigned_long_ptr  is access constant volatile_unsigned_long; | 
 |  | 
 |    type constv_float_ptr  is access constant volatile_float; | 
 |  | 
 | private | 
 |  | 
 |    ----------------------- | 
 |    -- Various constants -- | 
 |    ----------------------- | 
 |  | 
 |    CR6_EQ     : constant := 0; | 
 |    CR6_EQ_REV : constant := 1; | 
 |    CR6_LT     : constant := 2; | 
 |    CR6_LT_REV : constant := 3; | 
 |  | 
 | end GNAT.Altivec; | 
 |  | 
 | -------------------- | 
 | --  Design Notes  -- | 
 | -------------------- | 
 |  | 
 | ------------------------ | 
 | -- General principles -- | 
 | ------------------------ | 
 |  | 
 | --  The internal organization has been devised from a number of driving ideas: | 
 |  | 
 | --  o From the clients standpoint, the two versions of the binding should be | 
 | --    as easily exchangable as possible, | 
 |  | 
 | --  o From the maintenance standpoint, we want to avoid as much code | 
 | --    duplication as possible. | 
 |  | 
 | --  o From both standpoints above, we want to maintain a clear interface | 
 | --    separation between the base bindings to the Motorola API and the | 
 | --    additional facilities. | 
 |  | 
 | --  The identification of the low level interface is directly inspired by the | 
 | --  the base API organization, basically consisting of a rich set of functions | 
 | --  around a core of low level primitives mapping to AltiVec instructions. | 
 |  | 
 | --  See for instance "vec_add" in [PIM-4.4 Generic and Specific AltiVec | 
 | --  operations]: no less than six result/arguments combinations of byte vector | 
 | --  types map to "vaddubm". | 
 |  | 
 | --  The "hard" version of the low level primitives map to real AltiVec | 
 | --  instructions via the corresponding GCC builtins. The "soft" version is | 
 | --  a software emulation of those. | 
 |  | 
 | --------------------------------------- | 
 | -- The Low_Level_Vectors abstraction -- | 
 | --------------------------------------- | 
 |  | 
 | --  The AltiVec C interface spirit is to map a large set of C functions down | 
 | --  to a much smaller set of AltiVec instructions, most of them operating on a | 
 | --  set of vector data types in a transparent manner. See for instance the | 
 | --  case of vec_add, which maps six combinations of result/argument types to | 
 | --  vaddubm for signed/unsigned/bool variants of 'char' components. | 
 |  | 
 | --  The GCC implementation of this idiom for C/C++ is to setup builtins | 
 | --  corresponding to the instructions and to expose the C user function as | 
 | --  wrappers around those builtins with no-op type conversions as required. | 
 | --  Typically, for the vec_add case mentioned above, we have (altivec.h): | 
 | -- | 
 | --    inline __vector signed char | 
 | --    vec_add (__vector signed char a1, __vector signed char a2) | 
 | --    { | 
 | --      return (__vector signed char) | 
 | --        __builtin_altivec_vaddubm ((__vector signed char) a1, | 
 | --                                   (__vector signed char) a2); | 
 | --    } | 
 |  | 
 | --    inline __vector unsigned char | 
 | --    vec_add (__vector __bool char a1, __vector unsigned char a2) | 
 | --    { | 
 | --      return (__vector unsigned char) | 
 | --        __builtin_altivec_vaddubm ((__vector signed char) a1, | 
 | --                                   (__vector signed char) a2); | 
 | --    } | 
 |  | 
 | --  The central idea for the Ada bindings is to leverage on the existing GCC | 
 | --  architecture, with the introduction of a Low_Level_Vectors abstraction. | 
 | --  This abstraction acts as a representative of the vector-types and builtins | 
 | --  compiler interface for either the Hard or the Soft case. | 
 |  | 
 | --  For the Hard binding, Low_Level_Vectors exposes data types with a GCC | 
 | --  internal translation identical to the "vector ..." C types, and a set of | 
 | --  subprograms mapping straight to the internal GCC builtins. | 
 |  | 
 | --  For the Soft binding, Low_Level_Vectors exposes the same set of types | 
 | --  and subprograms, with bodies simulating the instructions behavior. | 
 |  | 
 | --  Vector_Types/Operations "simply" bind the user types and operations to | 
 | --  some Low_Level_Vectors implementation, selected in accordance with the | 
 | --  target | 
 |  | 
 | --  To achieve a complete Hard/Soft independence in the Vector_Types and | 
 | --  Vector_Operations implementations, both versions of the low level support | 
 | --  are expected to expose a number of facilities: | 
 |  | 
 | --  o Private data type declarations for base vector representations embedded | 
 | --    in the user visible vector types, that is: | 
 |  | 
 | --      LL_VBC, LL_VUC and LL_VSC | 
 | --        for vector_bool_char, vector_unsigned_char and vector_signed_char | 
 |  | 
 | --      LL_VBS, LL_VUS and LL_VSS | 
 | --        for vector_bool_short, vector_unsigned_short and vector_signed_short | 
 |  | 
 | --      LL_VBI, LL_VUI and LL_VSI | 
 | --        for vector_bool_int, vector_unsigned_int and vector_signed_int | 
 |  | 
 | --    as well as: | 
 |  | 
 | --      LL_VP for vector_pixel and LL_VF for vector_float | 
 |  | 
 | --  o Primitive operations corresponding to the AltiVec hardware instruction | 
 | --    names, like "vaddubm". The whole set is not described here. The actual | 
 | --    sets are inspired from the GCC builtins which are invoked from GCC's | 
 | --    "altivec.h". | 
 |  | 
 | --  o An LL_Altivec convention identifier, specifying the calling convention | 
 | --    to be used to access the aforementioned primitive operations. | 
 |  | 
 | --  Besides: | 
 |  | 
 | --  o Unchecked_Conversion are expected to be allowed between any pair of | 
 | --    exposed data types, and are expected to have no effect on the value | 
 | --    bit patterns. | 
 |  | 
 | ------------------------- | 
 | -- Vector views layout -- | 
 | ------------------------- | 
 |  | 
 | --  Vector Views combine intuitive user level ordering for both elements | 
 | --  within a vector and bytes within each element. They basically map to an | 
 | --  array representation where array(i) always represents element (i), in the | 
 | --  natural target representation. This way, a user vector (1, 2, 3, 4) is | 
 | --  represented as: | 
 |  | 
 | --                                                       Increasing Addresses | 
 | --  -------------------------------------------------------------------------> | 
 |  | 
 | --  | 0x0 0x0 0x0 0x1 | 0x0 0x0 0x0 0x2 | 0x0 0x0 0x0 0x3 | 0x0 0x0 0x0 0x4 | | 
 | --  | V (0), BE       | V (1), BE       | V (2), BE       | V (3), BE       | | 
 |  | 
 | --  on a big endian target, and as: | 
 |  | 
 | --  | 0x1 0x0 0x0 0x0 | 0x2 0x0 0x0 0x0 | 0x3 0x0 0x0 0x0 | 0x4 0x0 0x0 0x0 | | 
 | --  | V (0), LE       | V (1), LE       | V (2), LE       | V (3), LE       | | 
 |  | 
 | --  on a little-endian target | 
 |  | 
 | ------------------------- | 
 | -- Vector types layout -- | 
 | ------------------------- | 
 |  | 
 | --  In the case of the hard binding, the layout of the vector type in | 
 | --  memory is documented by the Altivec documentation. In the case of the | 
 | --  soft binding, the simplest solution is to represent a vector as an | 
 | --  array of components. This representation can depend on the endianness. | 
 | --  We can consider three possibilities: | 
 |  | 
 | --  * First component at the lowest address, components in big endian format. | 
 | --  It is the natural way to represent an array in big endian, and it would | 
 | --  also be the natural way to represent a quad-word integer in big endian. | 
 |  | 
 | --  Example: | 
 |  | 
 | --  Let V be a vector of unsigned int which value is (1, 2, 3, 4). It is | 
 | --  represented as: | 
 |  | 
 | --                                                           Addresses growing | 
 | --  -------------------------------------------------------------------------> | 
 | --  | 0x0 0x0 0x0 0x1 | 0x0 0x0 0x0 0x2 | 0x0 0x0 0x0 0x3 | 0x0 0x0 0x0 0x4 | | 
 | --  | V (0), BE       | V (1), BE       | V (2), BE       | V (3), BE       | | 
 |  | 
 | --  * First component at the lowest address, components in little endian | 
 | --  format. It is the natural way to represent an array in little endian. | 
 |  | 
 | --  Example: | 
 |  | 
 | --  Let V be a vector of unsigned int which value is (1, 2, 3, 4). It is | 
 | --  represented as: | 
 |  | 
 | --                                                           Addresses growing | 
 | --  -------------------------------------------------------------------------> | 
 | --  | 0x1 0x0 0x0 0x0 | 0x2 0x0 0x0 0x0 | 0x3 0x0 0x0 0x0 | 0x4 0x0 0x0 0x0 | | 
 | --  | V (0), LE       | V (1), LE       | V (2), LE       | V (3), LE       | | 
 |  | 
 | --  * Last component at the lowest address, components in little endian format. | 
 | --  It is the natural way to represent a quad-word integer in little endian. | 
 |  | 
 | --  Example: | 
 |  | 
 | --  Let V be a vector of unsigned int which value is (1, 2, 3, 4). It is | 
 | --  represented as: | 
 |  | 
 | --                                                           Addresses growing | 
 | --  -------------------------------------------------------------------------> | 
 | --  | 0x4 0x0 0x0 0x0 | 0x3 0x0 0x0 0x0 | 0x2 0x0 0x0 0x0 | 0x1 0x0 0x0 0x0 | | 
 | --  | V (3), LE       | V (2), LE       | V (1), LE       | V (0), LE       | | 
 |  | 
 | --  There is actually a fourth case (components in big endian, first | 
 | --  component at the lowest address), but it does not have any interesting | 
 | --  properties: it is neither the natural way to represent a quad-word on any | 
 | --  machine, nor the natural way to represent an array on any machine. | 
 |  | 
 | --  Example: | 
 |  | 
 | --  Let V be a vector of unsigned int which value is (1, 2, 3, 4). It is | 
 | --  represented as: | 
 |  | 
 | --                                                           Addresses growing | 
 | --  -------------------------------------------------------------------------> | 
 | --  | 0x0 0x0 0x0 0x4 | 0x0 0x0 0x0 0x3 | 0x0 0x0 0x0 0x2 | 0x0 0x0 0x0 0x1 | | 
 | --  | V (3), BE       | V (2), BE       | V (1), BE       | V (0), BE       | | 
 |  | 
 | --  Most of the Altivec operations are specific to a component size, and | 
 | --  can be implemented with any of these three formats. But some operations | 
 | --  are defined by the same Altivec primitive operation for different type | 
 | --  sizes: | 
 |  | 
 | --  * operations doing arithmetics on a complete vector, seen as a quad-word; | 
 | --  * operations dealing with memory. | 
 |  | 
 | --  Operations on a complete vector: | 
 | --  -------------------------------- | 
 |  | 
 | --  Examples: | 
 |  | 
 | --  vec_sll/vsl : shift left on the entire vector. | 
 | --  vec_slo/vslo: shift left on the entire vector, by octet. | 
 |  | 
 | --  Those operations works on vectors seens as a quad-word. | 
 | --  Let us suppose that we have a conversion operation named To_Quad_Word | 
 | --  for converting vector types to a quad-word. | 
 |  | 
 | --  Let A be a Altivec vector of 16 components: | 
 | --  A = (A(0), A(1), A(2), A(3), ... , A(14), A(15)) | 
 | --  Let B be a Altivec vector of 8 components verifying: | 
 | --  B = (A(0) |8| A(1), A(2) |8| A(3), ... , A(14) |8| A(15)) | 
 | --  Let C be a Altivec vector of 4 components verifying: | 
 | --  C = (A(0)  |8| A(1)  |8| A(2)  |8| A(3), ... , | 
 | --       A(12) |8| A(13) |8| A(14) |8| A(15)) | 
 |  | 
 | --  (definition: |8| is the concatenation operation between two bytes; | 
 | --  i.e. 0x1 |8| 0x2 = 0x0102) | 
 |  | 
 | --  According to [PIM - 4.2 byte ordering], we have the following property: | 
 | --  To_Quad_Word (A) = To_Quad_Word (B) = To_Quad_Word (C) | 
 |  | 
 | --  Let To_Type_Of_A be a conversion operation from the type of B to the | 
 | --  type of A.  The quad-word operations are only implemented by one | 
 | --  Altivec primitive operation.  That means that, if QW_Operation is a | 
 | --  quad-word operation, we should have: | 
 | --  QW_Operation (To_Type_Of_A (B)) = QW_Operation (A) | 
 |  | 
 | --  That is true iff: | 
 | --  To_Quad_Word (To_Type_Of_A (B)) = To_Quad_Word (A) | 
 |  | 
 | --  As To_Quad_Word is a bijection. we have: | 
 | --  To_Type_Of_A (B) = A | 
 |  | 
 | --  resp. any combination of A, B, C: | 
 | --  To_Type_Of_A (C) = A | 
 | --  To_Type_Of_B (A) = B | 
 | --  To_Type_Of_C (B) = C | 
 | --  ... | 
 |  | 
 | --  Making sure that the properties described above are verified by the | 
 | --  conversion operations between vector types has different implications | 
 | --  depending on the layout of the vector types: | 
 | --  * with format 1 and 3: only a unchecked conversion is needed; | 
 | --  * with format 2 and 4: some reorganisation is needed for conversions | 
 | --  between vector types with different component sizes; that has a cost on the | 
 | --  efficiency, plus the complexity of having different memory pattern for | 
 | --  the same quad-word value, depending on the type. | 
 |  | 
 | --  Operation dealing with memory: | 
 | --  ------------------------------ | 
 |  | 
 | --  These operations are either load operation (vec_ld and the | 
 | --  corresponding primitive operation: vlx) or store operation (vec_st | 
 | --  and the corresponding primitive operation: vstx). | 
 |  | 
 | --  According to [PIM 4.4 - vec_ld], those operations take in input | 
 | --  either an access to a vector (e.g. a const_vector_unsigned_int_ptr) | 
 | --  or an access to a flow of components (e.g. a const_unsigned_int_ptr), | 
 | --  relying on the same Altivec primitive operations. That means that both | 
 | --  should have the same representation in memory. | 
 |  | 
 | --  For the stream, it is easier to adopt the format of the target. That | 
 | --  means that, in memory, the components of the vector should also have the | 
 | --  format of the target. meaning that we will prefer: | 
 | --  * On a big endian target: format 1 or 4 | 
 | --  * On a little endian target: format 2 or 3 | 
 |  | 
 | --  Conclusion: | 
 | --  ----------- | 
 |  | 
 | --  To take into consideration the constraint brought about by the routines | 
 | --  operating on quad-words and the routines operating on memory, the best | 
 | --  choice seems to be: | 
 |  | 
 | --  * On a big endian target: format 1; | 
 | --  * On a little endian target: format 3. | 
 |  | 
 | --  Those layout choices are enforced by GNAT.Altivec.Low_Level_Conversions, | 
 | --  which is the endianness-dependant unit providing conversions between | 
 | --  vector views and vector types. | 
 |  | 
 | ---------------------- | 
 | --  Layouts summary -- | 
 | ---------------------- | 
 |  | 
 | --  For a user abstract vector of 4 uints (1, 2, 3, 4), increasing | 
 | --  addresses from left to right: | 
 |  | 
 | --  ========================================================================= | 
 | --                 BIG ENDIAN TARGET MEMORY LAYOUT for (1, 2, 3, 4) | 
 | --  ========================================================================= | 
 |  | 
 | --                                    View | 
 | --  ------------------------------------------------------------------------- | 
 | --  | 0x0 0x0 0x0 0x1 | 0x0 0x0 0x0 0x2 | 0x0 0x0 0x0 0x3 | 0x0 0x0 0x0 0x4 | | 
 | --  | V (0), BE       | V (1), BE       | V (2), BE       | V (3), BE       | | 
 | --  ------------------------------------------------------------------------- | 
 |  | 
 | --                                   Vector | 
 | --  ------------------------------------------------------------------------- | 
 | --  | 0x0 0x0 0x0 0x1 | 0x0 0x0 0x0 0x2 | 0x0 0x0 0x0 0x3 | 0x0 0x0 0x0 0x4 | | 
 | --  | V (0), BE       | V (1), BE       | V (2), BE       | V (3), BE       | | 
 | --  ------------------------------------------------------------------------- | 
 |  | 
 | --  ========================================================================= | 
 | --              LITTLE ENDIAN TARGET MEMORY LAYOUT for (1, 2, 3, 4) | 
 | --  ========================================================================= | 
 |  | 
 | --                                    View | 
 | --  ------------------------------------------------------------------------- | 
 | --  | 0x1 0x0 0x0 0x0 | 0x2 0x0 0x0 0x0 | 0x3 0x0 0x0 0x0 | 0x4 0x0 0x0 0x0 | | 
 | --  | V (0), LE       | V (1), LE       | V (2), LE       | V (3), LE       | | 
 |  | 
 | --                                    Vector | 
 | --  ------------------------------------------------------------------------- | 
 | --  | 0x4 0x0 0x0 0x0 | 0x3 0x0 0x0 0x0 | 0x2 0x0 0x0 0x0 | 0x1 0x0 0x0 0x0 | | 
 | --  | V (3), LE       | V (2), LE       | V (1), LE       | V (0), LE       | | 
 | --  ------------------------------------------------------------------------- | 
 |  | 
 | --  These layouts are common to both the soft and hard implementations on | 
 | --  Altivec capable targets. |