| Since the IBM AIX XL Fortran compiler was first released in 1990, customers have been requesting features to help meet their porting needs from different platforms, including CRAY. All references to CRAY in this article refer to the Y-MP hardware line and/or the CF77 and CF90 Fortran compilers. XL Fortran includes several extensions that enable you to port your CRAY Fortran code with minimal recoding. Use the compiler options and routines described below to make your move between CRAY and the RISC System/6000 as easy as possible. With Fortran 90 (ISO/IEC 1539:1991(E)) and Fortran 95 (ISO/IEC 1539:1997), most of the extensions discussed below can now be coded using standard-conforming language. When you are writing new code, this method is preferable because it ensures portability across any platform that supports Fortran 90 or Fortran 95. Fortran 90/95 alternatives are discussed at the end of each section. Of course, to port code that has already been written, using the extensions would likely require fewer changes. The features covered in this article are:
-qintsize option The -qintsize compiler option sets the default size of integer and logical data entities whose sizes are not explicitly declared. This option lets you easily port code from 16-bit and 64-bit machines. For example, the declaration explicitly specifies that x has a size of 8 bytes. But the declaration specifies that the compiler should provide the default integer size for x. For XL Fortran, the default size of integer/logical entities is 4 bytes, while for CRAY it is 8 bytes. If you specify -qintsize=8 at compile time, x is declared as a 64-bit entity. This ensures that very large numbers (i.e., larger than the maximum integer(4) value) are not inadvertently truncated because of a different default size. -qintsize affects: - integer/logical literals that do not specify kind type parameters
- default integer/logical data objects and functions
- intrinsic function results of type default integer/logical
- typeless constants in integer contexts
Fortran 90/95 alternative The Fortran 90/95 KIND intrinsic function returns the kind type parameter of an argument. It specifies the representation method for the argument. You can then use the kind type parameter when declaring entities. For example, integer (kind=kind(0)) x indicates that the size of x is the default integer size for the compiler. Compiled by a CRAY product, x is 8 bytes long; compiled by XL Fortran, x is 4 bytes long. To ensure that entities have similar value ranges without specifying platform-specific information during type declaration (i.e., a kind type parameter), use the Fortran 90/95 SELECTED_INT_KIND intrinsic function. This function returns a kind type parameter value of an integer data type that represents all integer values n in the range -10**R < n < 10**R. integer (kind=selected_int_kind(18)) x ! XL Fortran kind type parameter: 8 ! CRAY kind type parameter: 8
-qrealsize option Similar to -qintsize, the -qrealsize compiler option sets the default size of real and complex entities whose sizes are not explicitly declared. The default real size in XL Fortran is 4 bytes, while the default on the CRAY products is 8 bytes. Keep in mind that the precision of entities of type DOUBLE PRECISION is twice that of the default real size. Thus, if you specify -qrealsize=8, entities of type DOUBLE PRECISION have a default size of 16 bytes. Similarly, the size of complex and double complex entities is affected because they are formed from parts of type real. Fortran 90/95 alternative As discussed for integer entities, the KIND intrinsic function is also an alternative way to ensure portability for real entities: KIND(0.0) always returns the kind type parameter of the processor's default real size. Similarly, the SELECTED_REAL_KIND intrinsic function returns the kind type parameter value of a real data type with a minimal decimal precision and exponent range.
-qautodbl option Use the -qautodbl compiler option to convert single-precision entities to double-precision entities and double-precision entities to extended-precision entities. Select from a variety of suboptions:  |  NONE |  Does not promote or pad any objects that share storage. This is the default for -qautodbl. |  |  DBL4 |  Promotes 4-byte floating-point objects, including objects composed of these objects, to 8-byte objects. For example, a complex(4) object is promoted to complex(8). |  |  DBL8 |  Promotes 8-byte floating-point object, including objects composed of these objects, to 16-byte objects. |  |  DBL |  Performs the promotions done by both DBL4 and DBL8. | To help maintain proper storage relationships when code is ported, some suboptions will pad as well as promote objects:  |  DBLPAD4 |  Performs DBL4 promotion, and also pads objects of other types (except character) if they possibly share storage with promoted objects. |  |  DBLPAD8 |  Performs DBL8 promotion, and also pads objects of other types (except character) if they possibly share storage with promoted objects. |  |  DBLPAD |  Performs the promotions done by both DBL4 and DBL8. | Note: If you compile with both the -qautodbl and -qrealsize options, -qrealsize is disregarded. The following example illustrates promotion and padding using -qautodbl=dblpad: @process autodbl(dblpad) complex(4) x8 /(1.123456789e0,2.123456789e0)/ real(16) r16(2) /1.123q0,2.123q0/ integer(8) i8(2) /1000,2000/ character*5 c(2) /"abcde","12345"/ common /named/ x8,r16,i8,c end @process autodbl(none) subroutine s() complex(8) x8 real(16) r16(4) integer(8) i8(4) character*5 c(2) common /named/ x8,r16,i8,c x8 = (1.123456789d0,2.123456789d0) ! promotion occurred r16(1) = 1.123q0 ! padding occurred r16(3) = 2.123q0 ! padding occurred i8(1) = 1000 ! padding occurred i8(3) = 2000 ! padding occurred c(1) = "abcde" ! no padding occurred c(2) = "12345" ! no padding occurred end subroutine s Integer pointers Integer pointers are the XL Fortran version of CRAY pointers. XL Fortran integer pointers provide a means of referencing the address of a variable, which lets you step through a piece of storage or overlay pieces of storage. Given the statement: p is the integer pointer, which references the address of x, a variable, or array declarator (generally called the pointee) An integer pointer is a scalar variable of type integer(4) that cannot have a type explicitly assigned to it. The integer pointer can be used in any expression or statement in which an integer(4) can be used. The compiler does not allocate storage for the pointee. Storage is associated with the pointee at execution time by assigning the address of a block of storage to the pointer. When porting Fortran code between CRAY and the IBM RISC System/6000, you must consider some differences: Pointer size XL Fortran integer pointers are 4 bytes in size, whereas CRAY pointers are 8 bytes. If an absolute address is assigned to a pointer, ensure that:
1. the address can fit in 4 bytes of storage
2. the address is valid on an IBM RISC System/6000 platform Incrementing/decrementing pointers Adding or subtracting an integer n to an integer pointer increments (or decrements) the value of the pointer by n bytes. Adding or subtracting an integer n to a CRAY pointer increments (or decrements) the value of the pointer by n words. To maintain compatibility when porting, multiply the value of n (i.e., CRAY words) by the size of the RISC System/6000 machine word (e.g., 8). pointer (p,a) p = p+1 +- initial memory position of p | V 1 2 3 4 8 +----------------------------------- ... | | | | | | +----------------------------------- ... | | | | position of p+1 position of p+1 with XL Fortran with CRAY To port the code above to XL Fortran, modify the assignment statement: integer, parameter :: word_size = 8
p = p + (word_size*1) LOC intrinsic The LOC intrinsic function returns the address of a pointee. This function is useful for finding the address of a variable and assigning it to the integer pointer of another pointee (overlaying the storage of the two variables). The following examples show the modifications required when you are porting code from CRAY to XL Fortran. Original Code: integer big_array(100)
integer element, dim_size
integer array1(5), array2(5), array3(10) pointer (p1,array1)
pointer (p2,array2)
pointer (p3,array3)
! Assign storage to array1
p1 = loc(big_array)
! Initialize array1
array1 = (/1,3,5,7,9/) ! Assign storage to array2
p2 = p1 + 5
! Initialize array2
array2 = (/2,4,6,8,10/)
! array3 holds data of array1 and array2
p3 = loc(big_array)
if ((array3(3) .ne. 5) .or. (array3(8) .ne. 6)) stop 1
! Increment storage loc where array1 begins by 2 words
p1 = p1 + 2
element = array1(5)
if (element .ne. 4) stop 2 end Ported Version:
@process intsize(8) ! <----- Added code
integer big_array(100)
integer element, dim_size
integer array1(5), array2(5), array3(10)
pointer (p1,array1)
pointer (p2,array2)
pointer (p3,array3) integer word ! <----- Added code
parameter (word = 8) ! <----- Added code
! Assign storage to array1
p1 = loc(big_array)
! Initialize array1
array1 = (/1,3,5,7,9/)
! Assign storage to array2
p2 = p1 + 5*word ! <----- Modified code
! Initialize array2
array2 = (/2,4,6,8,10/)
! array3 holds data of array1 and array2
p3 = loc(big_array)
if ((array3(3) .ne. 5) .or. (array3(8) .ne. 6)) stop 1
! Increment storage loc where array1 begins by 2 words
p1 = p1 + 2*word ! <----- Modified code
element = array1(5)
if (element .ne. 4) stop 2
end Fortran 90/95 alternative To dynamically dimension arrays in Fortran 90/95, use deferred-shape array specifications, and then explicitly allocate memory for the arrays: integer, dimension(:), allocatable :: array
i = 5
allocate(array(5))
array = (/1,2,3,4,5/)
deallocate(array)
end
Service and utility procedures XL Fortran supports several CRAY procedures that are industry extensions. A subset of these are described below. These procedures (except for clock_) have the same names as the corresponding CRAY routines. clock_ The clock_ function returns the time in hh:mm:ss format. (Note: the XL Fortran routine is clock_, not clock, because the libc library of AIX already contains a clock routine) character(8) c,clock_
c = clock_() ! c = "13:30:56" date The date function returns the system date in mm/dd/yy format. character(8) d,date
d = date() ! d = "06/21/94" itrc The irtc function returns an integer(8) value of the number of nanoseconds elapsed since the initial value of the machine's real-time clock. integer(8) :: a,b,elapsed,irtc,x=3
a = irtc()
do m = 1,20000
x = x**2
end do
b = irtc()
elapsed = b-a ! elapsed = 33052928 rtc The rtc function returns a real(8) value of the number of seconds elapsed since the initial value of the machine's real-time clock. real(8) :: a,b,elapsed,rtc,x=2.0
a = rtc()
do m = 1,20000
x = x**2
end do
b = rtc()
elapsed = b-a ! loop required 0.846355768456422978e-02 timef The timef function returns the elapsed time in milliseconds since the first instance timef was called. The first instance timef is called, the value 0.0d0 is returned. real(8) elapsed, timef
elapsed = timef() ! elapsed = 0.0d0
do m = 1,20000
a = a**2
end do
elapsed = timef() ! elapsed = 15.2616500997857362 jdate The jdate function returns the system Julian date in yyddd format. character(5) d,jdate
d = jdate() ! d = '94172' Fortran 90/95 alternatives You can use the DATE_AND_TIME intrinsic function to access date and time information, and the SYSTEM_CLOCK intrinsic function to inquire on your system clock. Fortran 95 alternative You can use the CPU_TIME intrinsic function to return the time, in seconds, taken by a process from the start of a program.
CVMGx procedures XL Fortran supports conditional vector merge functions similar to CRAY's conditional vector merge functions. These functions take three arguments. The values returned by these functions depend on the result of the test that is done on the third argument. The first argument is returned if the test done on the third argument is true. The second argument is returned if the test done on the third argument is false. When the arguments are arrays, testing is done on an element-by-element basis. The conditional vector merge functions are:  | CVMGP | test for positive values or zero |  | CVMGM | test for negative values |  | CVMGZ | test for zero values |  | CVMGN | test for nonzero values |  | CVMGN | test for logical true values |  |  |  | One point of caution if you are porting code to XL Fortran: although the CVMGx routines accept integer and real arguments, these arguments and the function return type are interpreted as Boolean data types on a CRAY. Since XL Fortran does not have a Boolean data type, the argument and function return types are treated as integer, logical, or real intrinsic data types. The only place you would see a difference between the behavior of XL Fortran and that of CRAY is if the function is referenced in an assignment or expression where type conversion is expected to occur. ! CRAY
r = cvmgp(1.0,2.0,3.0) ! r = 32-bit representation of 1.0
i = cvmgp(1.0,2.0,3.0) ! i = 32-bit representation of 1.0
! i = 1065353216
! XL Fortran
r = cvmgp(1.0,2.0,3.0) ! r = 32-bit representation of 1.0
i = cvmgp(1.0,2.0,3.0) ! i = int(1.0)
! i = 1 Fortran 90/95 alternative Use the Fortran 90/95 MERGE intrinsic function instead of the CVMGx intrinsic functions. ! Original Code
integer i
integer i_a(3)
integer array_t(3), array_f(3), mask(3) i = cvmgp(1.0,2.0,3.0) ! i = 1
array_t(1) = 1
array_t(2) = 2
array_t(3) = 3
array_f(1) = 4
array_f(2) = 5
array_f(3) = 6
mask(1) = 7
mask(2) = 0
mask(3) = 8
i_a = cvmgz(array_t,array_f,mask) ! i_a(1)=4, i_a(2)=2, i_a(3)=6
end
! Fortran 90/95 Alternative
integer :: i
integer, dimension(3) :: i_a
integer, dimension(3) :: array_t, array_f, mask
i = merge(1.0,2.0,3.0 >= 0.0) ! i = 1
array_t = (/1,2,3/)
array_f = (/4,5,6/) mask = (/7,0,8/)
i_a = merge(array_t,array_f,mask == 0) ! i_a = (/4,2,6/)
end
Summary XL Fortran Versions 7.1 and 8.1 support a variety of features to help you port code, including several industry extensions found in CRAY products. Also, because XL Fortran fully supports Fortran 90 and Fortran 95, you can modify your code so that it is portable to any platform that supports these Fortran standards. For more information on porting, contact AIX Support Family at 1-800-CALL-AIX (US and Canada only). |