Technical: Hardware: G4
Advanced Search
Apple Developer Connection
Member Login Log In | Not a Member? Support

Using AltiVec

Getting Started in C

As presented in The C Programming Model, you may program AltiVec from the higher level languages C, C++ and Objective C using the AltiVec C Programming Interface. The collection of intrinsic data types and C-style functions that use them will be familiar to developers who already know how to program in C. There are, however, some subtle differences between ordinary C and the AltiVec extension to C:

Type Conversions

Typecasts are handled somewhat differently with vector types. Implied type conversions are not allowed. The compiler will reject the second line from the code sample below:

vector unsigned long one = (vector unsigned long) (1);
vector float floatOne = one;
//Error!

In this case, the implied type conversion between (vector unsigned long) and (vector float) in the assignment on the second line is not allowed. However, if you do an overt type coercion, then the code will compile:

vector unsigned long one = (vector unsigned long) (1);
vector float floatOne = (vector float) one;
// Compiles, but...

However, unlike scalar type coercions, vector type coercions do not change any bits in the vector. This means that you have to be a little bit more careful with them because such a type coercion may cause the vector to be reinterpreted to have a different value. In this example, the type coercion shown above causes floatOne to emerge from the assignment holding 0x00000001 in every element. When interpreted as a float, 0x00000001 is a very, very small number that is not the floating point value, 1.0! Similarly, if you convert that vector unsigned long to a vector unsigned short using an overt type coercion, the result vector will hold alternating zeros and ones: ( 0x0000, 0x0001, 0x0000, 0x0001, ...) If you do need to convert between types with retention of numerical value, there are a number of AltiVec instructions available for converting between vector types that conserve the value. For example, the function vec_ctf() will convert a vector (un)signed int into a vector float. If you really wanted a vector float full of 1.0, then this would be a way to do it:

vector unsigned long one = (vector unsigned long) (1);
vector float floatOne = vec_ctf( one, 0 );
// Correct!

Why is type casting done this way? Overt type coercions between vector types always have zero cost. Since they never cause any bits to change, they never compile into an AltiVec instruction. This is different from similar appearing type coercions applied to standard scalar C types. For example, for a scalar int->float conversion, the compiler will generate code to make sure that the value does not change as the data is moved from the integer unit to the floating point unit. AltiVec's bit-wise identical type coercion feature allows you to proceed with confidence that the compiler is not silently inserting excess code into your optimized routine. You have no such guarantees with classical scalar types. This is important because the AltiVec extension to C makes use of limited function overloading, and you often need zero cost typecasts to efficiently communicate to the compiler which function to use.

 

Function Overloading

Function overloading is a feature of C++ that is not a part of C per se. However, the AltiVec C Programming model makes use of it in C, C++ or Obj C for the new intrinsic functions that the C Programming Model defines. For each conceptual operation (e.g. addition with modulo overflow), there will be one function (e.g. vec_add()) that may accept many different vector types as input. Vec_add() actually has 19 different forms, all with different argument and return types. Some of them are shown below:

vector signed char
vector signed short
vector signed int
vector float
.
.
.

vec_add( vector signed char, vector signed char );
vec_add( vector signed short, vector signed short );
vec_add( vector signed int, vector signed int );
vec_add( vector float, vector float );
.
.
.

These 19 forms of vec_add() map to four different AltiVec instructions. Which flavor of vec_add is used and therefore which AltiVec instruction is compiled into your application depends on the type of the two function arguments of vec_add(). Explicit type coercion of any incorrectly typed inputs is a good method to make sure that you get the instruction that you think you are getting.

The AltiVec C Programming model does not give you the ability to create your own overloaded functions in C. As always, functions you create with different argument types must be given different names. You can, of course, write your own overloaded functions using a C++ compiler -- C++ allows this feature with user defined functions. Note that because the vector data types are intrinsic, a C++ compiler will not allow you to create operator overloads for them.

 

C++ and Objective C

You can program in C++ and Objective C using the AltiVec C programming interface, in the same way that you can use ordinary C functions and data types in C++ and Objective C.

With C++, some attention must be paid to performance when building abstraction. Wrapping a vector data type in a C++ object can have substantial negative performance implications if your compiler does not support passing class data by value in register. Passing small amounts of data by address causes a large amount of unnecessary load/store overhead. Typical slowdowns may be a factor of two. Be sure to check your compiler's output. Newer versions of popular C++ compilers for MacOS X support this feature.

Table of ContentsNextPrevious