Contents


Targeting your applications - what little endian and big endian IBM XL C/C++ compiler differences mean to you

Comments

To migrate from a big endian compiler to a little endian compiler, you might have to change some code to maintain program behavior or results. Vectors, storage association between items of different sizes, long doubles, complex numbers and serialization are aspects of your code that should be considered when porting code from big endian to little endian. The little endian Linux® distributions on IBM Power Systems™ use a different ABI than big endian distributions. Programs that have dependencies on the old ABI will need to be updated. New built-in functions make porting easier with respect to byte ordering of vectors.

This article describes the possible issues encountered when porting C/C++ code for use on big endian IBM XL C/C++ on Power Systems to little endian IBM XL C/C++ on Power Systems. It makes some suggestions about coding changes and describes compiler features and options that help with porting code.

Comparing big endian byte order and little endian byte order

Endianness determines how data is interpreted in memory. The endianness of your platform is determined by the architecture of your processor. The two most common types of endianness used today are big endian and little endian.

On big endian platforms (often referred to as simply big endian in this article), bytes in memory are ordered with the most significant byte first (or on the "left"). On little endian platforms (often referred to as simply little endian in this article), bytes in memory and vector registers are ordered with the least significant byte first (or on the "left").

For example, Figure 1 depicts how 000102030405060716 (interpreted as an 8-byte integer) is stored in memory on big endian and little endian platforms. In Figure 1, a represents the memory address at that location.

Figure 1: Representations of big endian and little endian byte ordering in memory

Vectors

The IBM POWER® processor architecture supports 16-byte vectors containing sixteen 1-byte elements, eight 2-byte elements, four 4-byte element, or two 8-byte elements. The processor has 128-bit vector registers and instructions to load vectors into registers, operate on vectors in registers, and store vector registers to memory. The IBM XL compilers provide built-in functions and language support to work with vectors.

There are differences between big endian and little endian with respect to vector element order. New compiler options and built-in functions have been introduced to help with these differences. These differences and new features are explained in the following sections.

Vector element order and vector element byte order

There are two ways to lay out the elements of a vector in a vector register. You can load the elements from lowest to highest, so that element 0 is the leftmost element in the vector register. Alternatively, you can load the elements from highest to lowest, so that element 0 is the rightmost element in the vector register. The former placement is called big endian vector element order, while the latter is called little endian vector element order.

On big endian, big endian vector element order is always used.

On little endian, you have the choice between using big endian vector element order and little endian vector element order.

Regardless of the vector element order, vector elements on big endian use big endian byte order in memory. Vector elements on little endian use little endian byte order in memory by default.

To demonstrate the differences of big endian and little endian vector element ordering, consider Figure 2 and Figure 3.

Figure 2 depicts how 000102030405060708090A0B0C0D0E0F16 (interpreted as a 16-byte vector) is represented in a vector register in big endian vector element order. The b127 and b0 markings on the figure denote bit 127 and bit 0 of the register respectively. The figure shows representations for vectors filled with elements of 1, 2, 4, and 8 bytes as you move down from top.

Figure 2: Representations of big endian vector element order in vector registers

Figure 3 depicts how 000102030405060708090A0B0C0D0E0F16 (interpreted as a 16-byte vector) is represented in a vector register in little endian vector element order. The b127 and b0 markings on the figure denote bit 127 and bit 0 of the register respectively. The figure shows representations for vectors filled with elements of 1, 2, 4, and 8 bytes as you move down from top.

Figure 3: Representations of little endian vector element order in vector registers

-qaltivec option

The -qaltivec option can be used to tell the little endian compiler how to order vector elements in the vector registers.

With -qaltivec=le, the compiler loads vectors in little endian element order and assumes vectors are loaded with little endian element order for vector stores. The compiler inserts vector permute operations, if necessary, to ensure that the load and store built-in functions use little endian element order. For vector built-in functions that reference specific elements, the compiler assumes that vectors were loaded with little endian element order. On little endian, -qaltivec=le is the default.

With -qaltivec=be, the compiler loads vectors in big endian element order and assumes vectors are loaded with big endian element order for vector stores. The compiler inserts vector permute operations, if necessary, to ensure that the load and store built-in functions use big endian element order. For vector built-in functions that reference specific elements, the compiler assumes that vectors were loaded with big endian element order.

To demonstrate, consider the following program:

#include<stdio.h>
union Example
{
 vector signed int vint;
 int sint[4];
};

int main() {
 union Example example;

 example.sint[0] = 0x0102;
 example.sint[1] = 0x0304;
 example.sint[2] = 0x0506;
 example.sint[3] = 0x0708;

 printf("First vector element: %04x\n", vec_extract(example.vint,0));
 printf("Second vector element: %04x\n", vec_extract(example.vint,1));
 printf("Third vector element: %04x\n", vec_extract(example.vint,2));
 printf("Fourth vector element: %04x\n", vec_extract(example.vint,3));

 return 0;
}

When this program is compiled on a big endian platform, or when it is compiled on a little endian platform with -qaltivec=le, it produces the following output:

First vector element: 0102
Second vector element: 0304
Third vector element: 0506
Fourth vector element: 0708

However, if the program is compiled on a little endian platform with -qaltivec=be, it produces the following output:

First vector element: 0708
Second vector element: 0506
Third vector element: 0304
Fourth vector element: 0102

The vector was loaded backwards into the vector register, while the order of elements in array i was unchanged.

A more portable way of working with vectors is to load and store using the vec_xl, vec_xl_be, vec_xst, and vec_xst_be built-in functions described in the next section.

Consider the following program:

#include<stdio.h>

int main() {
 vector signed int v1;
 vector signed int v2;
 vector signed int v3;
 vector signed int v4;
 int a[4];

 v1 = vec_xl(0, (int[]){1,2,3,4});
 vec_xst(v1, 0, a);
 printf("v1 via a: %d %d %d %d\n", a[0],a[1],a[2],a[3]);

 v2 = vec_neg(v1);
 vec_xst(v2, 0, a);
 printf("v2 via a: %d %d %d %d\n", a[0],a[1],a[2],a[3]);

 //Merge high and low depend on vector element order
 v3 = vec_mergeh(v1, v2);
 vec_xst(v3, 0, a);
 printf("v3 via a: %d %d %d %d\n", a[0],a[1],a[2],a[3]);

 v4 = vec_mergel(v1, v2);
 vec_xst(v4, 0, a);
 printf("v4 via a: %d %d %d %d\n", a[0],a[1],a[2],a[3]);

 return 0;
}

The program produces the same output on big endian platforms and little endian platforms. The output is:

v1 via a: 1 2 3 4
v2 via a: -1 -2 -3 -4
v3 via a: 1 -1 2 -2
v4 via a: 3 -3 4 -4

The vector built-in functions vec_xl, vec_xst, vec_mergeh, and vec_mergel take the vector element order into account. In other words, when the program is compiled on a little endian platform with -qaltivec=le:

  • vec_xl uses a Vector Scalar eXtension (VSX) load instruction, which always loads in big endian element order. A vector permute instruction is then used to reverse the vector in the register to use little endian element order.
  • vec_xst assumes that the vector in the register is using little endian vector element order so it uses a vector permute instruction to reverse the vector element order to big endian vector element order. It then uses a VSX store instruction, which always stores in big endian element order, to store the vector back to memory.
  • vec_mergeh knows that vector elements start from the right. The vector registers containing v1 and v2 look as follows:
v1	 4	 3	 2	 1
v2	-4	-3	-2	-1

Because vec_mergeh starts counting from the right, it correctly uses 1 and 2 for elements 0 and 2 of the result of vec_mergeh(v1, v2).

  • vec_mergel similarly knows that the vector elements start from the right. It therefore, correctly uses -1 and -2 for elements 1 and 3 of the result of vec_mergel(v1, v2).

When the program is compiled on a big endian platform, or on a little endian platform with -qaltivec=be:

  • vec_xl uses a VSX load instruction, which always loads in big endian element order. No vector permute is necessary.
  • vec_xst assumes that the vector in the register is using big endian vector element order. So, it directly uses a VSX store instruction, which always stores in big endian element order, to store the vector back to memory.
  • vec_mergeh knows that vector elements start from the left. The vector registers containing v1 and v2 look as follows:
v1	 1	 2	 3	 4
v2	-1	-2	-3	-4

Because vec_mergeh starts counting from the left, it correctly uses 1 and 2 for elements 0 and 2 of the result of vec_mergeh(v1, v2).

  • vec_mergel similarly knows that the vector elements start from the left. It therefore, correctly uses -1 and -2 for elements 1 and 3 of the result of vec_mergel(v1, v2).

For programs that do not use unions, the –qaltivec=be option can be useful in porting code from big endian to little endian.

The POWER8 cryptography built-in functions require their input vectors to be in big endian vector element order. You can do this either by using -qaltivec=be, or by using the vec_xl_be and vec_xst_be functions to load and store. These vector load and store functions are outlined in the following section.

New vector load and store built-in functions

New vector load and store built-in functions that use VSX instructions have been added. Note that XL C/C++ for little endian Linux on Power Systems is a 64-bit compiler product so only the prototypes for 64-mode apply. These built-in functions are further described in the XL C/C++ Compiler Reference (XL C/C++ for Linux documentation library).

vec_xl(offset, address)
This function loads a 16-byte vector from the memory address specified by the displacement offset and the address of address with the appropriate element order with respect to the platform and the -qaltivec option.

Prototypes (64-bit mode):

vector signed char vec_xl(long, signed char *);
vector unsigned char vec_xl(long, unsigned char *);
vector signed short vec_xl(long, signed short *);
vector unsigned short vec_xl(long, unsigned short *);
vector signed int vec_xl(long, signed int *);
vector unsigned int vec_xl(long, unsigned int *);
vector signed long long vec_xl(long, signed long long *);
vector unsigned long long vec_xl(long, unsigned long long *);
vector float vec_xl(long, float *);
vector double vec_xl(long, double *);

vec_xl_be(offset, address)
This function loads a 16-byte vector from the memory address specified by the displacement offset and the address of address in big endian order regardless of the platform or the -qaltivec option.

Prototypes (64-bit mode):

vector signed char vec_xl_be(long, signed char *);
vector unsigned char vec_xl_be(long, unsigned char *);
vector signed short vec_xl_be(long, signed short *);
vector unsigned short vec_xl_be(long, unsigned short *);
vector signed int vec_xl_be(long, signed int *);
vector unsigned int vec_xl_be(long, unsigned int *);
vector signed long long vec_xl_be(long, signed long long *);
vector unsigned long long vec_xl_be(long, unsigned long long *);
vector float vec_xl_be(long, float *);
vector double vec_xl_be(long, double *);

vec_xst(vect, offset, address)
This function stores the elements of a 16-byte vector specified by vect into a given memory address. The address is calculated by adding the displacement specified by offset to the memory address specified by address with the appropriate element order with respect to the platform and the -qaltivec option.

Prototypes (64-bit mode):

void vec_xst(vector signed char, long, signed char *);
void vec_xst(vector unsigned char, long, unsigned char *);
void vec_xst(vector signed short, long, signed short *);
void vec_xst(vector unsigned short, long, unsigned short *);
void vec_xst(vector signed int, long, signed int *);
void vec_xst(vector unsigned int, long, unsigned int *);
void vec_xst(vector signed long long, long, signed long long *);
void vec_xst(vector unsigned long long, long, unsigned long long *);
void vec_xst(vector float, long, float *);
void vec_xst(vector double, long, double *);

vec_xst_be(vect, offset, address)
This function stores the elements of a 16-byte vector specified by vect into a given memory address. The address is calculated by adding the displacement specified by offset to the memory address specified by address in big endian order regardless of the platform or the -qaltivec option.

Prototypes (64-bit mode):

void vec_xst_be(vector signed char, long, signed char *);
void vec_xst_be(vector unsigned char, long, unsigned char *);
void vec_xst_be(vector signed short, long, signed short *);
void vec_xst_be(vector unsigned short, long, unsigned short *);
void vec_xst_be(vector signed int, long, signed int *);
void vec_xst_be(vector unsigned int, long, unsigned int *);
void vec_xst_be(vector signed long long, long, signed long long *);
void vec_xst_be(vector unsigned long long, long, unsigned long long *);
void vec_xst_be(vector float, long, float *);
void vec_xst_be(vector double, long, double *);

Vector literals and binary-coded decimals (BCDs)

The binary-coded decimal (BCD) built-in functions operate on signed BCD values loaded in vector registers. Each BCD is made up of a series of 4-byte nibbles containing a value between 0 and 9, with the last nibble containing the sign. For example, the value 10 is represented (in 4-byte nibbles) as:

0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0

Each hexadecimal value above represents a 4-byte nibble. The 0x1 nibble is for the 1 in 10, and the 0x0 nibble after it is for the 0 in 10. The 0xC nibble is a special value that represents a plus sign. Because there is no BCD data type and the BCD numbers need to be loaded into vector registers, the BCD built-in functions use vector unsigned char arguments and results. This makes the BCD built-in functions dependent on vector element order even though BCD numbers are not themselves vectors. In other words, vectors containing BCD numbers need to be loaded in big endian vector element order even when compiling with –qaltivec=le. This is a problem when vectors are statically initialized (for example, using vector literals): a braced static vector initializer expression with the byte elements listed in big endian order populates the vector register in little endian element order on little endian platforms.

To work around this, you can reverse the order of the elements in the vector initializer. For example, consider the following program:

#include <stdio.h>
#if __LITTLE_ENDIAN__
#define BCD_INIT(b0, b1, b2, b3, b4, b5, b6, b7, \
                 b8, b9, ba, bb, bc, bd, be, bf) \
     { bf, be, bd, bc, bb, ba, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0 }
#else
#define BCD_INIT(b0, b1, b2, b3, b4, b5, b6, b7, \
                 b8, b9, ba, bb, bc, bd, be, bf) \
     { b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf }
#endif

vector unsigned char v1001 =
  BCD_INIT(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
           0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1C);

vector unsigned char v9009 =
  BCD_INIT(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
           0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x9C);

static void print_bytes(vector unsigned char v)
{
  long i;
  unsigned char b[16];
  vec_xst_be(v, 0, b);
  printf("%.02hhx", b[0]);
  for (i = 1; i < 16; ++i)
  {
    printf(", %.02hhx", b[i]);
  }
  printf("\n");
}

int main(void)
{
  vector unsigned char result;
  printf("Adding statically initialized vectors\n");
  printf("op1 is    ");  print_bytes(v1001);
  printf("op2 is    ");  print_bytes(v9009);
  result = __bcdadd(v1001, v9009, 0);
  printf("result is ");  print_bytes(result);
  return 0;
}

This program prints the following data on both big endian and little endian platforms.

Adding statically initialized vectors
op1 is    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 10, 00, 1c
op2 is    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 90, 00, 9c
result is 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 01, 00, 01, 0c

The __LITTLE_ENDIAN__ macro is predefined on little endian platforms only. We create a BCD_INIT macro to reverse the bytes in the initializer. Note that the print_bytes function uses the vec_xst_be built-in function because the vectors are in big endian vector element order.

Other workarounds are to initialize at run time using the vec_xl_be built-in function, or to reverse the vector element order of the statically initialized vector at run time using the vec_reve built-in function.

Application binary interface (ABI)

XL C/C++ for little endian Linux on Power Systems uses the new IBM Power Architecture® 64-bit ELF V2 ABI specification. This new ABI improves several areas, including function calls. This means, however, that assembly files targeting the old ABI have to be ported to the new ABI. Fortran, C, and C++ programs that follow their respective language standards do not need any porting to the new ABI. Programs containing non-standard extensions need to be reviewed for ABI sensitivity.

Storage association between different sized items

When porting a program from big endian to little endian, storage association between items of different size need to be considered. In C/C++, this concerns unions and pointer casting. The following sections outline those items in greater detail.

Note that hexadecimal values are always printed in big endian order.

Unions

When using unions with items of different sizes, the result can be different on little endian than it is on big endian. To demonstrate this, consider the following program:

#include<stdio.h>

union Example
{
  char i;
  short j;
  int k;
};

main()
{
  union Example example;

  example.k = 0x01020304;

  printf("example.i: %02x\n", example.i);
  printf("example.j: %04x\n", example.j);
  printf("example.k: %08x\n", example.k);

  return 0;
}

In the above program, we have specified that i, j, and k share storage space – all of which are of different sizes. On big endian, the most significant byte is in the lowest memory address (or on the left), so i, j, and k contain the following data:

example.i: 01
example.j: 0102
example.k: 01020304

On little endian platforms, the least significant byte is on the left, so i, j, and k contain the following data:

example.i: 04
example.j: 0304
example.k: 01020304

Pointer casting

The issues with pointer casting are effectively the same as those introduced by unions. Consider the following program:

#include<stdio.h>

int main() {
  int i = 0x01020304;  
  printf("example.i: %02x\n", *(char*)&i);
  printf("example.j: %04x\n", *(short*)&i);
  printf("example.k: %08x\n", *(int*)&i);
  return 0;
}

Note that the code is invalid by aliasing rules of the language (for example, an integer cannot be handled as a short), however, the code simply demonstrates the issue.

In the above program, pointer casting is used to cast the integer i to char, short, and int. On big endian, the most significant byte of i is in the lowest memory address. The output of the program on big endian is:

example.i: 01
example.j: 0102
example.k: 01020304

On little endian, the least significant byte of i is in the lowest memory address. The output of the program on little endian is:

example.i: 04
example.j: 0304
example.k: 01020304

Long double and complex types

XL C/C++'s long double types are composed of two parts of type double with different magnitudes that do not overlap (except when the number is zero or close to zero). The high-order double (the one that comes first in storage) must have the larger magnitude, even on little endian. The value of a long double number is the sum of its two real parts.

Complex types are made of a real and an imaginary part where the real part is always before the imaginary part. In C/C++, you can access the real and imaginary parts using the __real__ and __imag__ unary operators or the creal and cimag function sets.

Consider the following program:

#include<stdio.h>
#include<complex.h>

union Example
{
 float f[2];
 float complex c;
};

int main()
{
 union Example example;
 example.c = 1.0f + 0.0f*I;

 printf("First element of float: %.4f\n", example.f[0]);
 printf("Second element of float: %.4f\n", example.f[1]);
 printf("Real part of complex: %.4f\n", __real__(example.c));
 printf("Imaginary part of complex: %.4fi\n", __imag__(example.c));

 return 0;
}

On both big endian and little endian, the first element of f is 1.0000 and the second element of f is 0.0000. The real part of the complex number c is 1.0000 and the imaginary part is 0.0000i.

First element of float: 1.0000
Second element of float: 0.0000
Real part of complex: 1.0000
Imaginary part of complex: 0.0000i

The byte order of the elements of a floating-point and a complex number is different between big endian and little endian, but the element order is the same.

Serialization

Binary data files depend on the byte order of the data. If you have a binary data file generated on a big endian platform, you will need to convert the byte order of the data when reading the file on a little endian platform. You can use the __load2r, __load4r, __load8r, __store2r, __store4r, and __store8r built-in functions to convert the byte order. Consider, for example, the following program which, when compiled and run on a big endian platform, generates a binary file bigendian.data:

$ cat writefile.c
#include <stdlib.h>
#include <stdio.h>
#include "data.h"
int main() {
  FILE *fp;
  data_t data = { {1,2,3,4,5,6,7,8}, {1,2,3,4}, {-1,-2}, 3.0, 4.0, "abcdefgh" };
  size_t res;
  fp = fopen("bigendian.data", "w");
  if (fp == NULL) {
    perror("fopen");
    exit(1);
  }
  res = fwrite(&data, sizeof(data), 1, fp);
  if (res != 1) {
    perror("fwrite");
    exit(1);
  }
  fclose(fp);
  printf("Wrote:\n");
  print_data(data);
  return 0;
}

$ cat data.h
#ifndef DATA_H
#define DATA_H
#include <stdint.h>
typedef struct {
  int64_t ll[8];
  int32_t i[4];
  int16_t s[2];
  float f;
  double d;
  char c[10];
} data_t;

static void print_data(data_t data) {
  long i;
  printf("data: ll={ ");
 
  for (i = 0; i < 8; ++i) {
    printf("0x%016lx ", data.ll[i]);
  }
  printf("}\n");
  printf("       i={ ");
  for (i = 0; i < 4; ++i) {
    printf("0x%08x ", data.i[i]);
  }
  printf("}\n");
  printf("       s={ ");
  for (i = 0; i < 2; ++i) {
    printf("0x%04hx ", data.s[i]);
  }
  printf("}\n");
  printf("       f=%f\n", data.f);
  printf("       d=%f\n", data.d);
  printf("       c=");
  i = 0;
  while(i < 10 && data.c[i] != '\0') {
    printf("%c", data.c[i]);
    ++i;
  }
  printf("\n");
}
#endif

fwrite writes data as a stream of bytes. As a result, ll, i, s, f, and d will be in big endian byte order. To read the data file on a little endian platform, the read routine can't just use fread. It will need to convert the data too. For example:

$ cat readfile.c
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "data.h"
static void print_data(data_t data);
int main() {
  FILE *fp;
  data_t data;
  size_t res;
  fp = fopen("bigendian.data", "r");
  if (fp == NULL) {
    perror("fopen");
    exit(1);
  }
  /* This fread call will read all non-character data
     in the wrong byte order */
  res = fread(&data, sizeof(data), 1, fp);
  if (res != 1) {
    perror("fread");
    exit(1);
  }
  printf("Read:\n");
  print_data(data);
  /* Convert the byte order */
  {
    union {
      uint64_t u64;
      uint32_t u32;
      double d;
      float f;
    } tmp;
    long i;
    /* convert the long long data */
    for (i = 0; i < 8; ++i) {
      data.ll[i] = __load8r((uint64_t *) &data.ll[i]);
    }
    /* convert the integer data */
    for (i = 0; i < 4; ++i) {
      data.i[i] = __load4r((uint32_t *) &data.i[i]);
    }      
    /* convert the short data */
    for (i = 0; i < 2; ++i) {
      data.s[i] = __load2r((uint16_t *) &data.s[i]);
    }
    /* convert the float data */
      tmp.f = data.f;
      __store4r(tmp.u32, &data.f);
    /* convert the double data */
    tmp.d = data.d;
    __store8r(tmp.u64, &data.d);
  }
  printf("After conversion:\n");
  print_data(data);
  return 0;
}

When readfile.c is compiled and run on a little endian platform, the following output is generated.

Read:
data: ll={ 0x0100000000000000 0x0200000000000000 0x0300000000000000 0x0400000000000000 
0x0500000000000000 0x0600000000000000 0x0700000000000000 0x0800000000000000 }
       i={ 0x01000000 0x02000000 0x03000000 0x04000000 }
       s={ 0xffff 0xfeff }
       f=0.000000
       d=0.000000
       c=abcdefgh
After conversion:
data: ll={ 0x0000000000000001 0x0000000000000002 0x0000000000000003 0x0000000000000004 
0x0000000000000005 0x0000000000000006 0x0000000000000007 0x0000000000000008 }
       i={ 0x00000001 0x00000002 0x00000003 0x00000004 }
       s={ 0xffff 0xfffe }
       f=3.000000
       d=4.000000
       c=abcdefgh

Similar considerations are needed when porting algorithms that depend on the byte order of the data. For example, a function that reads a text file containing a hexadecimal string of arbitrary length and converts it to an array of uint64_t can cast the character string to a uint64_t *. While this violates the ANSI aliasing rules, it works on a big endian platform because the byte orders of a char[8] array and uint64_t match. This is not the case on little endian platforms.

Loading and storing in reverse byte order

XL C/C++ provides the following built-in functions to help with converting byte order:

unsigned short __load2r(unsigned short* address)
Loads an unsigned short from address with reversed byte order.

unsigned int __load4r(unsigned int* address)
Loads an unsigned integer from address with reversed byte order.

unsigned long long __load8r(unsigned long long* address)
Loads an unsigned long long from address with reversed byte order.

void __store2r(unsigned short source, unsigned short* address)
Stores an unsigned short source to address with reversed byte order.

void __store4r(unsigned int source, unsigned int* address)
Stores an unsigned integer source to address with reversed byte order.

void __store8r(unsigned long long source, unsigned long long* address)
Stores an unsigned long long source to address with reversed byte order.

vec_revb(address)
Returns a vector that is of the same type as address containing the bytes of the corresponding element of address in the reversed byte order.

Prototypes:

vector signed char vec_revb(vector signed char);
vector unsigned char vec_revb(vector unsigned char);
vector signed short vec_revb(vector signed short);
vector unsigned short vec_revb(vector unsigned short);
vector signed int vec_revb(vector signed int);
vector unsigned int vec_revb(vector unsigned int);
vector signed long long vec_revb(vector signed long long);
vector unsigned long long vec_revb(vector unsigned long long);
vector float vec_revb(vector float)
vector double vec_revb(vector double);

vec_reve(address)
Returns a vector that is of the same type as address containing the elements of address in the reversed element order.

Prototypes:

vector signed char vec_reve(vector signed char);
vector unsigned char vec_reve(vector unsigned char);
vector signed short vec_reve(vector signed short);
vector unsigned short vec_reve(vector unsigned short);
vector signed int vec_reve(vector signed int);
vector unsigned int vec_reve(vector unsigned int);
vector signed long long vec_reve(vector signed long long);
vector unsigned long long vec_reve(vector unsigned long long);
vector float vec_reve(vector float);
vector double vec_reve(vector double);

Resources


Downloadable resources


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Linux
ArticleID=992655
ArticleTitle=Targeting your applications - what little endian and big endian IBM XL C/C++ compiler differences mean to you
publish-date=12122014