Chapter 2. Implementation Details

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

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.

Support for Multiprocessing

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.

Syntax Extensions

The following nonstandard syntax features are accepted by the compiler in order to make it simpler to port programs from Fortran 77.

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.

Support for IRIX Kernel Functions

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


Processor-Dependent Features

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.


Standard and Intrinsic Modules

(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”.

Supported Data Types

(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.).

Numeric Precision

(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


Character Values and Literals

(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.

INCLUDE Processing

(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.

Assumed-Shape and Deferred-Shape Arrays

(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”).

Treatment of the SAVE Attribute

(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.

Global Variables

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.

MODULE Global Variables

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.

Procedure Local Variables

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.

Nonstandard Intrinsic Procedures

(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.

Status From ALLOCATE and DEALLOCATE

(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).

Example 2-1. Displaying a Message on Allocation Failure


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

Partial Evaluation of Array Constructors

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.

Status From I/O Statements

(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

Processor-Dependent Error Codes

(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.

Default Output Record Lengths

(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”).

Implementation of Sign Edit Codes

(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.

Arguments to the Main Program

(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.

Implementation of MODULE and USE

(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,

  1. compile the module source, yielding a .kmo file and an object file

  2. optionally, link the object file as a DSO

  3. 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.

Use of the Keyword RECURSIVE

(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.

Array References in Statement Functions

(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.

Implementation of RANDOM_NUMBER

(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.

Example 2-2. Test of RANDOM_NUMBER


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