This chapter documents the relationship of MIPSpro Fortran 90 to the ANSI standard for the Fortran 90 language. It includes these main topics:
“Conformance to the Fortran 90 Language Standard” documents the standard compliance and the extensions supported.
“Support for IRIX Kernel Functions” documents the IRIX functions that are available as library routines to a Fortran program.
“Processor-Dependent Features” documents how this compiler implements features the standard calls processor-dependent.
MIPSpro Fortran 90 is a complete implementation of ANSI Fortran 90. It supports all of the language features as defined by the standard, and allows only minor syntactic extensions beyond the standard.
MIPSpro Fortran 90 does not support such common language extensions as HPF (High Performance Fortran) directives. Language extensions present in Cray™ and DEC™ Fortran 90 compilers are also not supported.
The version of MIPSpro Fortran 90 and MIPSpro Power Fortran 90 described in this book support only Silicon Graphics, Inc. Power Challenge and Power Indigo2 systems (that is, systems based on the MIPS R8000 processor) running IRIX 6.0.x. The compiler generates only 64-bit executables.
MIPSpro Fortran 90 supports multiprocessing with user-inserted parallel directives. These directives follow the recently adopted PCF (Parallel Computing Forum) X3H5 guidelines. (See “Using PCF Directives”.)
MIPSpro POWER Fortran 90 is an extended version of MIPSpro Fortran 90 that supports the same language and directives, but adds automatic optimization for multiprocessing. This compiler analyzes a serial program for potential parallelization and when possible, generates an executable that can utilize multiple processors when executed in a Silicon Graphics, Inc. computer that has multiple CPUs in sufficient numbers.
The following nonstandard syntax features are accepted by the compiler in order to make it simpler to port programs from Fortran 77.
Asterisk notation can be used to signify precision of a numeric type. For example, INTEGER*8 is taken as INTEGER(8). (See “Differences in Scalar Declarations”.)
When writing a quad-precision literal floating point number, “Q” can be used as the exponent delimiter. For example, 1Q6 is taken as 1E6_16. (See “Differences in Scalar Declarations”.)
Hollerith-form character literal values are accepted in integer expressions. (See “Character and Hollerith Literals”.)
A numeric variable can be specified as the filename value in an OPEN statement. (See “Numeric Variable for FILE”.)
Special format modes are permitted in the OPEN statement. (See “Special File Formats”.)
None of these extensions adds functionality to the language; they only make it easier to port existing programs that depend on Fortran 77 extensions. Because they are nonportable, you should avoid using them when writing new code.
Some commonly-used IRIX system functions have been made available to Fortran programs. System functions are facilities that are provided by the IRIX system kernel directly, as opposed to functions that are supplied by library code. For an overview of system functions, see the intro(2) reference page.
Table 2-1 summarizes the functions in the Fortran run-time library. In general, the interface routine has the same name as the system function when called from a C program.
For details on any function, use the command man; for example, to get details on the fcntl() function, use man fcntl. This can yield as many as three reference pages with the same name; for example, man chmod produces chmod(1) for the user command, chmod(2) for the C function, and chmod(3f) describing the Fortran interface.
Table 2-1. Summary of System Interface Library Routines
Function | Purpose |
---|---|
abort | abnormal termination |
access | determine accessibility of a file |
acct | enable/disable process accounting |
alarm | execute a subroutine after a specified time |
barrier | perform barrier operations |
blockproc | block processes |
blockprocall | block processes |
brk | change data segment space allocation |
chdir | change default directory |
chmod | change access mode of a file |
chown | change ownership of a file |
chroot | change root directory for a command |
close | close a file descriptor |
creat | create or rewrite a file |
ctime | return system time |
dtime | return elapsed execution time |
dup | duplicate an open file descriptor |
etime | return elapsed execution time |
exit | terminate process with status |
fcntl | file control |
fdate | return date and time in an ASCII string |
fgetc | get a character from a logical unit |
fork | create a copy of this process |
fputc | write a character to a Fortran logical unit |
free_barrier | free barrier |
fseek | reposition a file on a logical unit |
fseek64 | reposition a file on a logical unit for 64-bit architecture |
fstat | get file status |
fstat64 | get file status—64-bit integers |
ftell | reposition a file on a logical unit |
ftell64 | reposition a file on a logical unit for 64-bit architecture |
gerror | get system error message text |
getarg | return command line arguments |
getc | get a character from a logical unit |
getcwd | get pathname of current working directory |
getdents | read directory entries |
getegid | get effective group ID |
gethostid | get unique identifier of current host |
getenv | get value of environment variables |
geteuid | get effective user ID |
getgid | get user or group ID of the caller |
gethostname | get current host ID |
getlog | get user's login name |
getpgrp | get process group ID |
getpid | get process ID |
getppid | get parent process ID |
getsockopt | get options on sockets |
getuid | get user or group ID of caller |
gmtime | return system time |
iargc | return number of command line arguments |
idate | return date or time in numerical form |
ierrno | get system error message number |
ioctl | control device |
isatty | determine if unit is associated with tty |
itime | return date or time in numerical form |
kill | send a signal to a process |
link | make a link to an existing file |
loc | return the address of an object |
lseek | move read/write file pointer |
lseek64 | move read/write file pointer for 64-bit architecture |
lstat | get file status |
lstat64 | get file status—64-bit integers |
ltime | return system time |
m_fork | create parallel processes |
m_get_myid | get task ID |
m_get_numprocs | get number of subtasks |
m_kill_procs | kill process |
m_lock | set global lock |
m_next | return value of counter |
m_park_procs | suspend child processes |
m_rcle_procs | resume child processes |
m_set_procs | set number of subtasks |
m_sync | synchronize all threads |
m_unlock | unset a global lock |
mkdir | make a directory |
mknod | make a directory/file |
mount | mount a filesystem |
new_barrier | initialize a barrier structure |
nice | lower priority of a process |
open | open a file |
oserror | get/set system error |
pause | suspend process until signal |
perror | write system error message to stderr (unit 0) |
pipe | create an interprocess channel |
plock | lock process, test, or data in memory |
prctl | control processes |
profil | execution-time profile |
ptrace | process trace |
putc | write a character to a Fortran logical unit |
putenv | set environment variable |
qsort | quick sort |
read | read from a file descriptor |
readlink | read value of symbolic link |
rename | change the name of a file |
rmdir | remove a directory |
sbrk | change data segment space allocation |
schedctl | call to scheduler control |
send | send a message to a socket |
setblockproccnt | set semaphore count |
setblockproccntall | set semaphore count |
setgid | set group ID |
sethostid | set current host ID |
setoserror | set system error |
setpgrp | set process group ID |
setsockopt | set options on sockets |
setuid | set user ID |
sginap | put process to sleep |
sginap64 | put process to sleep in 64-bit environment |
shmat | attach shared memory |
shmdt | detach shared memory |
sighold | raise priority and hold signal |
sigignore | ignore signal |
signal | change the action for a signal |
sigpause | suspend until receive signal |
sigrelse | release signal and lower priority |
sigset | specify system signal handling |
sleep | suspend execution for an interval |
socket | create an endpoint for communication TCP |
sproc | create a new share group process |
stat | get file status |
stat64 | get file status—64-bit integers |
stime | set time |
symlink | make symbolic link |
sync | update superblock |
sysmp | control multiprocessing |
sysmp64 | control multiprocessing in 64-bit environment |
system | issue a shell command |
taskblock | block tasks |
taskcreate | create a new task |
taskctl | control task |
taskdestroy | kill task |
tasksetblockcnt | set task semaphore count |
taskunblock | unblock task |
time | return system time (available as both function and subroutine) |
ttynam | find name of terminal port |
uadmin | administrative control |
ulimit | get and set user limits |
ulimit64 | get and set user limits in 64-bit architecture |
umask | get and set file creation mask |
umount | dismount a filesystem |
unblockproc | unblock processes |
unblockprocall | unblock processes |
unlink | remove a directory entry |
uscalloc | shared memory allocator |
uscalloc64 | shared memory allocator in 64-bit environment |
uscas | compare and swap operator (default integer arguments) |
uscas32 | compare and swap operator (INTEGER(4) arguments) |
uscasinfo | compare and swap information word of shared arena |
usclosepollsema | detach file descriptor from a pollable semaphore |
usclrerror | disable messages from shared arena (usinit reference page) |
usclrtrace | disable tracing in shared arena (usinit reference page) |
usconfig | semaphore and lock configuration operations |
uscpsema | acquire a semaphore |
uscsetlock | unconditionally set lock |
usctllock | lock control operations |
usctlsema | semaphore control operations |
usdetach | release shared arena |
usdumplock | dump lock information |
usdumpsema | dump semaphore information |
usfree | user shared memory allocation |
usfreelock | free a lock |
usfreepollsema | free a pollable semaphore |
usfreesema | free a semaphore |
usgetinfo | exchange information through an arena |
usinit | semaphore and lock initialize routine |
usinitlock | initialize a lock |
usinitsema | initialize a semaphore |
usmalloc | allocate shared memory |
usmalloc64 | allocate shared memory in 64-bit environment |
usmallopt | control allocation algorithm |
usnewlock | allocate and initialize a lock |
usnewpollsema | allocate and initialize a pollable semaphore |
usnewsema | allocate and initialize a semaphore |
usopenpollsem | attach a file descriptor to a pollable semaphore |
uspsema | acquire a semaphore |
usputinfo | exchange information through an arena |
usrealloc | user share memory allocation |
usrealloc64 | user share memory allocation in 64-bit environment |
usseterror | enable messages from memory arena (usinit reference page) |
ussetlock | set lock |
ussettrace | start tracing in memory arena (usinit reference page) |
ustestlock | test lock |
ustestsema | return value of semaphore |
usunsetlock | unset lock |
usvsema | free a resource to a semaphore |
uswsetlock | set lock |
wait | wait for a process to terminate |
write | write to a file |
The Fortran 90 language standard leaves some details of language semantics to be defined by the compiler. The Fortran 90 language standard and the Fortran 90 Handbook (see “Additional Reading”) refer to each such detail as a processor dependency.
For each point at which the Fortran 90 Handbook mentions a processor dependency, this Guide has a heading explaining the Silicon Graphics implementation of that feature. In many cases, the paragraph number in the Fortran 90 Handbook is given following the heading.
![]() | Note: The behavior of processor-dependent features is by definition nonportable. Fortran 90 systems from other vendors may not behave the same way. Furthermore, future implementations of Silicon Graphics, Inc. Fortran 90 may behave differently in subtle ways. You should never base the correctness of a program on the behavior of a processor dependency. |
(This topic amplifies topic 1.7 in the Fortran 90 Handbook.)
No standard or intrinsic modules are shipped with MIPSpro Fortran 90. One module has been proposed as a standard to ISO (ISO/IEC 1539-2:1994(E)). It is a module that implements varying-length strings of characters. The Fortran 90 source of an exemplary implementation of this module is available on the World Wide Web. See the sources mentioned under “Internet Resources for Fortran 90 Users”.
(This topic amplifies topics 2.9, 3.1, 4.1, 4.3, and 13.3 in the Fortran 90 Handbook.)
MIPSpro Fortran 90 supports the following data types:
INTEGER with kind-parameters of 1, 2, 4, and 8
REAL with kind-parameters of 4, 8, and 16
DOUBLE PRECISION is a synonym for REAL(8)
COMPLEX with kind-parameters of 4, 8, and 16
DOUBLE COMPLEX is a synonym for COMPLEX(8)
LOGICAL with kind-parameters of 1, 2, 4, and 8
CHARACTER
Except for COMPLEX, the supported kind-parameters (1, 2, 4, 8 and 16) represent the size of a scalar value in bytes and the default alignment of one scalar item in memory. For COMPLEX, the kind-parameter represents the size and alignment of each of the components of the number. (This can be slightly confusing when migrating from Fortran 77. In Fortran 77, a complex number composed of two REAL*8 numbers is a COMPLEX*16 variable. But in Fortran 90, a complex number composed of two REAL(8) numbers is a COMPLEX(8) variable.).
(This topic amplifies topics 4.2.2, 4.3, and 5.1 in the Fortran 90 Handbook.)
INTEGER and LOGICAL values are stored as signed binary integers with the size and alignment specified by the kind-parameter. The possible integer values are:
INTEGER(1) | –128…127 |
INTEGER(2) | –32,768…32,767 |
INTEGER(4) | –231…231 –1 |
INTEGER(8) | –263…263 –1 |
REAL(4) and REAL(8) values are stored in IEEE 754 format. REAL(16) values are not stored in IEEE 754 form, but rather are stored as the diffference between two values (see the math(3m) reference page). COMPLEX values consist of two REAL values of the specified kind in adjacent locations. The precisions supported are shown in Table 2-2.
Table 2-2. Floating-Point Precision
Data Type | Exponent | Fraction | Approximate Minimum | Approximate Maximum |
---|---|---|---|---|
REAL(4) | 8 bits | 24 bits | 1.17e-38 | 3.4e+38 |
REAL(8) | 11 bits | 53 bits | 2.22e-308 | 1.797e+308 |
REAL(16) | 11 bits | 107 bits | 1.805e-276 | 1.797e+308 |
(This topic amplifies topics 3.3, 4.3, and 5.1 in the Fortran 90 Handbook.)
The CHARACTER type supports only 8-bit ASCII values. Any 8-bit value can be stored in a CHARACTER variable using the CHAR intrinsic function. Only one kind-parameter is supported for CHARACTER data: the parameter 1, signifying 8-bit ASCII. For example, the lines
CHARACTER(80,1) MSG MSG = 1_"Enter File Name" |
show the declaration of a CHARACTER variable with an explicit kind and the assignment of a literal with an explicit kind.
Literal character values are represented in a source expression using the standard Fortran 90 syntax as described in section 4.3.5.4 of the MIPSpro Fortran 90 Handbook. Any character that can be entered from the keyboard can be contained within a literal string, with the exception of the ASCII newline character (control-J, 10 decimal), which signals the end of the line and the end of the logical statement.
(This topic amplifies topic 3.5 in the Fortran 90 Handbook.)
The Fortran 90 INCLUDE statement causes a specified file to be read by the compiler. When the argument of INCLUDE specifies an absolute path—that is, if it begins with a slash or a dot—the specified file is included.
INCLUDE "../hdrs/header1" |
When the argument of INCLUDE specifies only a filename or a relative pathname, the compiler searches for the specified file in directories specified by the -I option and in standard locations for included files (see “Specifying Compiler Input Files”).
INCLUDE "hdrs/header1" |
There is a limit of 98 on the depth of nesting included files. That is, the compiler supports a total of 99 source files concurrently open: the original source file and up to 98 included files.
(This topic amplifies topics 5.2, 5.3, and 12.5.3 in the Fortran 90 Handbook.)
Fortran 90 supports arrays whose actual shape is not known until run time. Assumed-shape arrays are dummy arguments whose shape is not declared in the procedure—they take the shape of the actual parameter passed. Deferred-shape arrays are array variables with the POINTER or ALLOCATABLE attribute—their shapes are specified when memory is allocated for them.
When a program accesses an element of an assumed-shape or deferred-shape array, the access is not direct, but indirect through a descriptor block in memory. As a result, two to four times as many machine instructions are needed to retrieve an element from one of these arrays than from an array of declared size.
In addition, there is no interface for passing an assumed-shape or deferred-shape array as an argument to a function written in C (as discussed in “Unsupported Array Parameters”).
(This topic amplifies topic 5.6.4 in the Fortran 90 Handbook.)
The SAVE attribute is implemented in different ways for different types of variables. This topic describes the one implementation of the compiler. However, this information is subject to change in future implementations. It would be unwise to write code that depended directly on this information.
Variables declared at the global level of a source unit, but not within a MODULE, are typically allocated as part of the main procedure stack frame. This stack frame persists throughout the program execution.
When SAVE is specified for a global variable, the variable is allocated instead in a block storage section—either .bss or .sbss, depending on its length. This segment persists throughout the program. A side-effect of allocation in block storage is that these sections are initialized to binary zero when they are created at program load time. (Clearly, to rely on this effect would be to make your program nonportable.) For more information on the management of block storage sections, see the MIPSpro Assembly Language Programmer's Guide.
Variables declared at the outer level of a MODULE are typically allocated as COMMON segments whose names are formed from the module name. This ensures that only one instance of a module variable exists in the executable program, no matter how many object files refer to that module in a USE statement.
The use of SAVE with MODULE variables does not change this typical allocation, since common segments persist throughout the execution of the program.
Variables declared local to any procedure are allocated as part of the procedure's stack frame. They are released when the procedure returns.
![]() | Note: This means that in the current implementation, any function can be called recursively. However, Silicon Graphics can change the implementation of local variables in a future implementation. Always specify RECURSIVE with a function that you intend to be recursive. |
A local variable with the SAVE attribute is not allocated in the procedure stack frame, but rather in a block storage segment. This means that there is only one fixed instance of the variable for the procedure. It retains its most recent value from one call of the procedure to another, or from one level of a recursive function to the next.
If different procedures have local variables with the same name and the SAVE attribute, each procedure has a unique block-storage allocation for its variable.
(This topic amplifies topic 5.7.2 in the Fortran 90 Handbook.)
MIPSpro Fortran 90 does not provide any intrinsic functions or subroutines other than the ones standardized in Fortran 90. For information on porting a Fortran 77 program that relies on nonstandard intrinsics, see “Differences in Intrinsic Functions”.
MIPSpro Fortran 90 does provide a large number of library functions for access to IRIX kernel functions (see “Support for IRIX Kernel Functions”). These are not “intrinsic” since their names are not recognized automatically by the compiler.
(This topic amplifies topic 6.5.1 in the Fortran 90 Handbook.)
The status returned from ALLOCATE or DEALLOCATE is 0 when the operation is performed, and 1 when it fails.
When the operation fails owing to a logical error such as deallocating a variable that has not been allocated, no other information is available. When an failure is due to a system condition such as a lack of memory, the system error number is recorded. You can retrieve the system error number with the ierrno() function, or display an error message on unit 0 using perror() (see the perror(3f) reference page).
ALLOCATE (AV(SZ),STAT=STAT) IF (0 /= STAT) THEN IF (0 /= IERRNO()) THEN CALL PERROR("Allocating vector") ELSE WRITE (6,*)"Unknown error allocating vector" END IF END IF |
The MIPSpro Fortran 90 Handbook notes that the Fortran 90 standard permits the processor to skip the evaluation of parts of an array constructor under certain conditions. It is true that, in certain limited cases, MIPSpro Fortran 90 does omit evaluation of zero-sized array constructor elements. However, the rules for when this is done are complex and subject to change. Furthermore, the standard does not specify the order in which expressions and sub-expressions within a constructor are evaluated.
In general, you should assume that any expression within an array constructor will be evaluated. You should never write code that relies on the compiler not evaluating a constructor expression, or on its evaluating the constructor in any particular order.
(This topic amplifies topic 9.2.2 in the Fortran 90 Handbook.)
The values left in an IOSTAT variable following input are as follows:
end of file produces -1
end of record (nonadvancing input) produces -2
(This topic amplifies topic 9.2.3 in the Fortran 90 Handbook.)
For all I/O status values greater than zero (error codes), see Appendix A, “Run-Time Error Codes.” Regarding a specific case mentioned in the MIPSpro Fortran 90 Handbook, a request for input beyond the record size when PAD="NO" causes return of an I/O status code of 177, if an IOSTAT variable is supplied.
(This topic amplifies topic 9.5.5 in the Fortran 90 Handbook.)
When a file is opened for sequential output and no specific RECL= argument is given, there is no maximum record length. The length of each record is determined by the data written to it.
The value of the RECL= specifier is interpreted as a count of bytes for formatted I/O and for sequential unformatted I/O. The value returned by INQUIRE(IOLENGTH) is always in terms of bytes.
In the single case of unformatted direct I/O, RECL= is interpreted as a count of 32-bit words (this behavior is for compatibility with some heritage Fortran 77 programs). You can change this behavior, forcing RECL= to be interpreted as a byte count in every case, by specifying the -bytereclen driver option (see “Specifying Source File Format”).
(This topic amplifies topic 10.9.4 in the Fortran 90 Handbook.)
The treatment of the Sign edit code "S" is processor dependent. MIPSpro Fortran 90 does not display a positive sign for "S" editing.
(This topic amplifies topic 11.2.1 in the Fortran 90 Handbook.)
Although according to the Fortran 90 standard a main program has no provision for receiving arguments, the main program is invoked from the IRIX command line, and it can access the command-line arguments using the getarg() library function (see the getarg(3) reference page). That function may not be available in systems from other vendors.
(This topic amplifies topic 2.1 and 11.6.6 in the Fortran 90 Handbook.)
MIPSpro Fortran 90 implements the MODULE statement automatically. When the compiler front-end encounters a MODULE statement, it checks the syntax of the contents of the module that follow.
When the syntax is valid, the compiler writes a .kmo file in the current directory. This is a small, printable file containing a summary of the accessible identifiers declared in the module. The name of the file is the name given in the MODULE statement, in uppercase letters.
When the compiler encounters a USE statement, it searches for a modname.kmo file (see “Specifying Compiler Input Files” for the search path). The contents of the file establish the names provided in that module.
As a result of these rules, a MODULE must be compiled before any USE statement for the module can be compiled.
The object code contained in a MODULE is generated when the MODULE is compiled. Procedures defined within the MODULE are named modname$procname_ in the object file; that is, the names are qualified by the module name. In other respects, these procedures generate code no different from that of other procedures in the same object file. The object code of a MODULE is stored and linked just like any other unit of object code. Compiled modules are not stored in any special location or format. (For hints on converting a MODULE to a DSO, see “Creating Dynamic Shared Objects”.)
To prepare and distribute a functional package based on a MODULE,
compile the module source, yielding a .kmo file and an object file
optionally, link the object file as a DSO
distribute only the .kmo and the object file (or DSO)
Using this approach, you do not have to distribute the source code of the module, only the summary .kmo file. The binding between accessible names in the module and the code that uses them is established at link time (or at load time for a DSO). As a result, you can distribute updated object files and the client programs do not have to be recompiled—as long as the names and data types of the accessible names are not changed.
(This topic amplifies topic 12.1.3 in the Fortran 90 Handbook.)
The current release of MIPSpro Fortran 90 allocates procedure local variables on the process stack (see “Treatment of the SAVE Attribute”). However, this is not a defined programming interface. You should always use the keyword RECURSIVE for any function that can be called recursively.
(This topic amplifies topic 12.3.4 in the Fortran 90 Handbook.)
The Fortran 90 Handbook indicates (section 12.3.4, rule 2) that there is ambiguity in the language standard regarding the use of array arguments to intrinsic functions (within the context of a statement function). MIPSpro Fortran 90 does not permit the use of array arguments to intrinsics within a statement function.
(This topic amplifies topic A.83 in the Fortran 90 Handbook.)
The pseudorandom number generator used to implement the RANDOM_NUMBER function was originally described in “Toward a Universal Random Number Generator” by George Marsaglia and Arif Zaman (Florida State University Report: FSU-SCRI-87-50 (1987)). It was later modified by F. James and published in “A Review of Pseudo-Random Number Generators.” It is thought to be the best available random generator. It passes all tests for random number generators and has a period of 2144.
The algorithm is a combination of a Fibonacci sequence (with lags of 97 and 33, and operation “subtraction plus one, modulo one”) and an arithmetic sequence using subtraction.
The RANDOM_SEED function takes two seed integers,
0 <= ij <= 31328
0 <= kl <= 30081
A change in either ij or kl produces a new sequence of length approximately 1030. For example, if several groups are working on parts of the same calculation, each group could be assigned its own ij seed number, leaving it with 30,081 choices for kl.
To test the random generator, use the code shown in Example 2-2.
integer seed(2) real first20k(20000), next6(6) seed(1) = 1802 seed(2) = 9373 call random_seed(put=seed(1:2)) call random_number(harvest=first20k) call random_number(harvest=next6) do j=1,6 write (6,"(F10.1)") (4096*4096*next6(j)) end do end |
The output from this test should be the following numbers:
6533892.0 14220222.0 7275067.0 6172232.0 8354498.0 10633180.0 |