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-2018, 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.
|