Contents


Targeting your applications – what little endian and big endian IBM XL Fortran 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, 16-byte reals, complex numbers, and unformatted data files 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 intrinsic procedures make porting easier with respect to byte ordering of vectors.

This article describes the possible issues encountered when porting Fortran code for use on big endian IBM XL Fortran on Power Systems to little endian IBM XL Fortran 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 intrinsic procedures 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 intrinsic procedures 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 the 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 intrinsic procedures use little endian element order. For vector intrinsic procedures 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 intrinsic procedures use big endian element order. For vector intrinsic procedures that reference specific elements, the compiler assumes that vectors were loaded with big endian element order.

To demonstrate, consider the following program:

       program main
         vector(integer(8)) v
         integer(8) i(2)
         equivalence(v, i)

         i = [z'0001020304050607', z'08090A0B0C0D0E0F']

         print 1, "First vector element:  ", vec_extract(v, 0)
         print 1, "Second vector element: ", vec_extract(v, 1)
1        format(A, z16.16)
       end program

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:  0001020304050607
Second vector element: 08090A0B0C0D0E0F

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

First vector element:  08090A0B0C0D0E0F
Second vector element: 0001020304050607

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 intrinsic procedures described in the next section instead of EQUIVALENCE. Consider the following program:

vector(real(4)) v1, v2, v3, v4
real(4) a(4)

v1 = vec_xl(0, [real(4) :: 1.0, 2.0, 3.0, 4.0])
call vec_xst(v1, 0, a)
print *, 'v1=', a

v2 = vec_neg(v1)
call vec_xst(v2, 0, a)
print *, 'v2=', a

! Merge high and low depend on vector element order
v3 = vec_mergeh(v1, v2)
call vec_xst(v3, 0, a)
print *, 'v3=', a

v4 = vec_mergel(v1, v2)
call vec_xst(v4, 0, a)
print *, 'v4=', a

end

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

v1= 1.000000000 2.000000000 3.000000000 4.000000000
v2= -1.000000000 -2.000000000 -3.000000000 -4.000000000
v3= 1.000000000 -1.000000000 2.000000000 -2.000000000
v4= 3.000000000 -3.000000000 4.000000000 -4.000000000


The vector intrinsic procedures 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.0	 3.0	 2.0	 1.0
v2	-4.0	-3.0	-2.0	-1.0

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

  • vec_mergel similarly knows that vector elements start from the right. It therefore correctly uses -1.0 and -2.0 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.0	 2.0	 3.0	 4.0
v2	-1.0	-2.0	-3.0	-4.0

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

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

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

The POWER8 cryptography intrinsic procedures require that 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 intrinsic procedures to load and store. These vector load and store functions are outlined in the following section.

New vector load and store intrinsic procedures

New vector load and store intrinsic procedures that use VSX instructions have also been added. You can find these intrinsic procedures in the XL Fortran Compiler Reference (XL Fortran for Linux documentation library).

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

ARG1 is an INTENT(IN) integer.

ARG2 is INTENT(IN) of any of the following types:

  • REAL(4) or REAL(8)
  • INTEGER(1), INTEGER(2), INTEGER(4), or INTEGER(8)
  • VECTOR

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

ARG1 is an INTENT(IN) integer.

ARG2 is INTENT(IN) of any of the following types:

  • REAL(4) or REAL(8)
  • INTEGER(1), INTEGER(2), INTEGER(4), or INTEGER(8)
  • VECTOR

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

ARG1 is an INTENT(IN) vector.

ARG2 is an INTENT(IN) integer.

ARG3 is INTENT(OUT) that must be a vector or type of integer or real as follows:

  • If ARG3 is a vector, it must be of the same type as ARG1.
  • If ARG3 is not a vector and ARG1 is an integer vector or an unsigned vector, ARG3 must be of the INTEGER type with the same kind type parameter as the elements of ARG1.
  • If ARG3 is not a vector and ARG1 is a real vector, ARG3 must be of the same type and kind as the elements of ARG1.
  • If ARG3 is not a vector and ARG1 is a pixel vector, ARG3 must be of type INTEGER(2).

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

ARG1 is an INTENT(IN) vector.

ARG2 is an INTENT(IN) integer.

ARG3 is INTENT(OUT) that must be a vector or type of integer or real as follows:

  • If ARG3 is a vector, it must be of the same type as ARG1.
  • If ARG3 is not a vector and ARG1 is an integer vector or an unsigned vector, ARG3 must be of the INTEGER type with the same kind type parameter as the elements of ARG1.
  • If ARG3 is not a vector and ARG1 is a real vector, ARG3 must be of the same type and kind as the elements of ARG1.
  • If ARG3 is not a vector and ARG1 is a pixel vector, ARG3 must be of type INTEGER(2).

Application binary interface (ABI)

XL Fortran 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 require porting to the new ABI. Programs containing non-standard extensions need to be reviewed for ABI sensitivity. One example in Fortran is programs calling C functions with variable argument lists.

Calling C functions with variable arguments lists from Fortran

The C language allows functions to have variable argument lists. This is indicated by the use of ellipsis (…). For example, printf has the following C prototype:

int printf(const char *restrict format, ...);

The ELF V2 ABI requires callers to functions with variable argument list to set up a parameter save area on the stack. As a result, calls to functions with variable argument lists must have accurate prototypes.

The Fortran standard, however, considers C functions with variable argument lists to be non-interoperable and does not provide a way of writing interfaces for them in Fortran. Some programs try to work around this by adding an explicit interface containing the maximum number of arguments they plan to use. For example:

interface
  function printf1int(format, a) bind(c, name='printf')
    use, intrinsic :: iso_c_binding, only: c_int
    implicit none
    integer(c_int) printf1int
    character, intent(in) :: format(*)
    integer(c_int), value :: a
  end function
end interface

Calling printf1int using the interface above might lead to stack corruption with the new ABI due to a missing parameter save area. To allow XL Fortran know about the variable argument list, add the procedure_attribute(varargs) directive to the interface.

interface
  function printf1int(format, a) bind(c, name='printf')
    use, intrinsic :: iso_c_binding, only: c_int
    implicit none
    integer(c_int) printf1int
    character, intent(in) :: format(*)
    integer(c_int), value :: a
    !ibm* procedure_attribute(varargs)
  end function
end interface

Storage association between different sized items

When porting a program from big endian to little endian, storage association between items of different size must be considered. In Fortran, this concerns EQUIVALENCE, common blocks, ENTRY statements, argument association, and format-directed I/O. The following sections outline those items in greater detail.

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

EQUIVALENCE

The Fortran standard restricts the types of objects that can be storage-associated together with the EQUIVALENCE statement. XL Fortran (and most compilers), however, allow objects of almost any type to appear in EQUIVALENCE. When using EQUIVALENCE 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:

       integer(8) j
       integer(4) i(2)
       integer(2) h(4)
       integer(1) k(8)
       equivalence (j, i), (j, h), (j, k)
       j = z'0001020304050607'
       print 1, 'j = ', j
       print 2, 'i = ', i
       print 4, 'h = ', h
       print 8, 'k = ', k
1      format(A, "z'", z16.16, "'")
2      format(A, 2("z'", z8.8, "'", 1x))
4      format(A, 4("z'", z4.4, "'", 1x))
8      format(A, 8("z'", z2.2, "'", 1x))
       end

In the above program, we specified that j shares storage space with i, h, and k – all of which have different kinds. In both big endian and little endian, arrays are laid out from left to right, or more accurately, the lowest array element has the lowest memory address. The byte order of each array element is different on big endian and little endian. On big endian, the most significant byte of each array element is on the left, so j, i, h, and k look the same in memory. The output is:

j = z'0001020304050607'
i = z'00010203' z'04050607'
h = z'0001' z'0203' z'0405' z'0607'
k = z'00' z'01' z'02' z'03' z'04' z'05' z'06' z'07'

On little endian platforms, the least significant byte of each array element is on the left, and therefore, j, i, h, and k look different in memory. The output is:

j = z'0001020304050607'
i = z'04050607' z'00010203'
h = z'0607' z'0405' z'0203' z'0001'
k = z'07' z'06' z'05' z'04' z'03' z'02' z'01' z'00'

Common blocks

Common blocks provide storage association between the items in different compilation units. If the same common block is declared differently in two compilation units, the common block members are storage associated. If corresponding members have different sizes, extra consideration is required when porting code from big endian to little endian. Consider the following program:

       subroutine sub1
         integer(8) j
         common /blk/ j
         j = z'0001020304050607'
         print 1, 'sub1: ', j
1        format(A, "z'", z16.16, "'")
       end subroutine

       subroutine sub2
         integer(4) i(2)
         common /blk/ i
         print 2, 'sub2: ', i
2        format(A, 2("z'", z8.8, "'", 1x))
       end subroutine

       program main
         call sub1
         call sub2
       end program

In the above code, j and i share storage space and have different kinds. The output of the program shows that the elements of i are ordered differently on big endian and little endian. On big endian, running the program results in the following output:

sub1: z'0001020304050607'
sub2: z'00010203' z'04050607'

On little endian, running the program results in the following output:

sub1: z'0001020304050607'
sub2: z'04050607' z'00010203'

ENTRY statements

Storage association between the results of functions and their ENTRY statements occurs when the results have different characteristics. In the following program, f and g are storage associated.

function f(a)
 double precision a, f
 real g
entry g(a)
 f = a
end function

program main
 interface
   function f(a)
     double precision a, f
   end function
   function g(a)
     double precision a
     real g
   end function
 end interface
 double precision x
 x = z'0001020304050607'
 print '(z16.16)', f(x)
 print '(z8.8)', g(x)
end program

On big endian, g, which is a single-precision real, is storage associated with the most significant half of the double precision f. As a result, the output on big endian is:

0001020304050607
00010203

On little endian, g is storage associated with the least significant half of f. As a result, the output on little endian is:

0001020304050607
04050607

Argument association

Calls in the FORTRAN 77 style do not use explicit interfaces and rely on the user to pass the correct type. On big endian, some non-conforming programs could run successfully although the actual arguments and dummy arguments do not match. Consider the following program:

       program main
         integer :: i = 1
         character(5) :: c = 'abcd'
         integer(2) :: h = 2
         real(8) :: d = 1.0

         call hexprint(i, 4)
         call hexprint(c, 5)
         call hexprint(h, 2)
         call hexprint(d, 8)
       end program

       subroutine hexprint(buffer, size)
         character(8) buffer
         integer size
         print 100, buffer(1:size)

100      format (z<2 * size>.<2 * size>)
       end subroutine

The program is non-conforming as it associates actual arguments of various integer kinds with a dummy argument of character type. The program does not use an explicit interface, and therefore, the compiler does not detect the error. On big endian, character and non-character data use the same byte order, and therefore, the program produces the expected output. On little endian, this is not the case. To demonstrate this, consider the output of the program on big endian and little endian.

On big endian, the program produces the following output:

00000001
6162636420
0002
3FF0000000000000

On little endian, the program produces the following output:

01000000
6162636420
0200
000000000000F03F

Format-directed I/O

In format-directed I/O, the edit descriptor used to read or write an I/O item must be appropriate for the type and type parameters of the I/O item. For example, porting issues might occur if the A edit descriptor, which assumes the I/O item to have type character, is used to read or write an I/O item of type integer. For example, consider the following program:

character(4) file
integer(4) a
a = z'61626364'
write(file, '(A)') a
print *, file
end

On big endian, the output is:
abcd

But on little endian, the output is:
dcba

16-byte reals and complex types

XL Fortran's extended-precision floating-point type, REAL(16), is not in the binary128 format suggested by the Institute of Electrical and Electronics Engineers (IEEE) standard. Instead, REAL(16) is composed of two REAL(8) parts with different magnitudes that do not overlap (except when the number is zero or close to zero). The high-order REAL(8) value (the one that comes first in storage) must have the larger magnitude, even on little endian. The value of a REAL(16) number is the sum of its two REAL(8) parts.

Complex types are made of a real and an imaginary part where the real part always comes before the imaginary part.

Consider the following code snippet:

real(8) d(2)
real(16) q
complex(8) z
equivalence (q, d), (q, z)
q = 1.0q0

On both big endian and little endian, the first element of d is 1.0d0 and the second element of d is 0.0d0. The real part of the complex number z is 1.0d0 and the imaginary part is 0.0d0.

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

Unformatted data files

Unformatted Fortran data files are made up of records and record markers. Record markers are 4- or 8-byte integers containing the number of bytes in the record. Record markers appear before and after each record. Consider the following example.

write(10) 10, 11
end

This program writes the following data (in binary) to the file connected to unit 10:

0x00000008 0x0000000a 0x0000000b 0x00000008

Because record markers are integers, they are affected by the byte order. Also, because 10 and 11 above are integers, they are also affected by byte order. As a result, an unformatted data file using one byte order (for example, big endian) cannot be read on a platform using a different byte order (for example, little endian) without conversion. XL Fortran provides several methods of performing the conversion. They are, in order of highest precedence:

  • The XLFRTEOPTS=ufmt_bigendian=<units> and XLFRTEOPTS=ufmt_littleendian=<units> runtime options
  • The CONVERT= specifier in the OPEN statement
  • The @PROCESS UFMT directive
  • The -qufmt compiler option

These methods are outlined in greater detail in the following sections.

Environment variables for runtime conversion

The XLFRTEOPTS=xlf_bigendian=<units> and XLFRTEOPTS=xlf_littleendian=<units> environment variables can be used to specify the endianness of unformatted data files at run time for conversion.

XLFRTEOPTS=xlf_bigendian=<units> is only valid on little endian and is used for units connected to big endian unformatted data files.

XLFRTEOPTS=xlf_littleendian=<units> is only valid on big endian and is used for units connected to little endian unformatted data files.

Examples of valid values for <units> for both xlf_bigendian and xlf_littleendian (the following example shows xlf_bigendian but these <unit> values are applicable to xlf_bigendian as well) are:

XLFRTEOPTS=xlf_bigendian=5
Specifies that unit 5 is connected to a big endian file.

XLFRTEOPTS=xlf_bigendian=5-10
Specifies that units 5 through 10 are connected to big endian files.

XLFRTEOPTS=xlf_bigendian=1,5-10
Specifies that units 1 and 5 through 10 are connected to big endian files.

XLFRTEOPTS=xlf_bigendian=1-
Specifies that all units, from 1 onward, are connected to big endian files.

XLFRTEOPTS=xlf_bigendian=newunit
Specifies that all automatically generated units are connected to big endian files. Automatically generated unformatted units are created with negative identifiers.

XLFRTEOPTS=xlf_bigendian=1-,newunit or XLFRTEOPTS=xlf_bigendian=*Specifies that all units are connected to big endian files.

CONVERT= specifier in OPEN statements

The CONVERT= specifier can be used to specify endianness of unformatted data files for conversion. Valid values for this specifier are:

CONVERT='NATIVE'
Tells the compiler that the endianness of the file is that of the native platform, and no conversion is necessary. This is the default.

CONVERT='BIG_ENDIAN'
Tells the compiler that the unformatted file uses big endian byte ordering. On little endian, performs conversion on data transfer operations to and from the file. On big endian, no conversion is done.

CONVERT='LITTLE_ENDIAN'
Tells the compiler that the unformatted file uses little endian byte ordering. On big endian, performs conversion on data transfer operations to and from the file. On little endian, no conversion is done.

Source directives

@PROCESS UFMT source directives apply to all OPEN statements in the compilation unit before which they appear.

@PROCESS UFMT(big endian)
Assumes that OPEN statements are connecting to big endian data files. On little endian, conversions are performed at run time on data transfer to and from these files. On big endian, no conversion is necessary.

@PROCESS UFMT(little endian)
Assumes that OPEN statements are connecting to little endian data files. On big endian, conversions are performed at run time on data transfer to and from these files. On little endian, no conversion is necessary.

-qufmt compiler option

The -qufmt compiler option allows the user to specify the endianness of unformatted data files at compile time for conversion.

-qufmt=be
Tells the compiler that all unformatted data files are big endian. On little endian, conversions are performed at run time on data transfer to and from these files. On big endian, no conversion is necessary.

-qufmt=le
Tells the compiler that all unformatted data files are little endian. On big endian, conversions are performed at run time on data transfer to and from these files. On little endian, no conversion is necessary.

Loading and storing in reverse byte order

XL Fortran provides the following intrinsic procedures to help with converting byte order:

LOAD2R(X)
Loads the value of X with reverse byte order where X is an INTENT(IN) dummy argument of type INTEGER(2). The result has type INTEGER(2).

LOAD4R(X)
Loads the value of X with reverse byte order where X is an INTENT(IN) dummy argument of type INTEGER(4). The result has type INTEGER(4).

LOAD8R(X)
Loads the value of X with reverse byte order where X is an INTENT(IN) dummy argument of type INTEGER(8). The result has type INTEGER(8).

REVERSE_BYTE_ORDER(X)
Is a generic function that loads the value of X with reverse byte order where X is an INTENT(IN) dummy argument of type INTEGER(2), INTEGER(4) or INTEGER(8). It resolves to LOAD2R, LOAD4R or LOAD8R depending on the type of X. The result has the same type and type parameters as that of X.

VEC_REVB(ARG1)
Returns a vector of the same type as ARG1 containing the bytes of the corresponding elements of ARG1 in reversed byte order. ARG1 is an INTENT(IN) integer, unsigned, or real vector.

VEC_REVE(ARG1)
Returns a vector of the same type as ARG1 containing the elements of ARG1 in reversed element order. ARG1 is an INTENT(IN) integer, unsigned, or real vector.It returns a vector which is the same type as that of X containing the INTENT(IN) integer, unsigned, or real vector.

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=992208
ArticleTitle=Targeting your applications – what little endian and big endian IBM XL Fortran compiler differences mean to you
publish-date=12122014