Mercurial > hg > CbC > CbC_gcc
diff gcc/ada/libgnat/g-altive.ads @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children | 84e7813d76e9 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gcc/ada/libgnat/g-altive.ads Fri Oct 27 22:46:09 2017 +0900 @@ -0,0 +1,766 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- G N A T . A L T I V E C -- +-- -- +-- S p e c -- +-- -- +-- Copyright (C) 2004-2017, 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 abstaction 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.