aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/libgnat/g-altive.ads
blob: 328fe698b55f9e6707c3730713c7cfca7171fa01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                         G N A T . A L T I V E C                          --
--                                                                          --
--                                 S p e c                                  --
--                                                                          --
--          Copyright (C) 2004-2023, 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.