| <!--===- docs/Intrinsics.md |
| |
| Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| See https://llvm.org/LICENSE.txt for license information. |
| SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| |
| --> |
| |
| # A categorization of standard (2018) and extended Fortran intrinsic procedures |
| |
| ```{contents} |
| --- |
| local: |
| --- |
| ``` |
| |
| This note attempts to group the intrinsic procedures of Fortran into categories |
| of functions or subroutines with similar interfaces as an aid to |
| comprehension beyond that which might be gained from the standard's |
| alphabetical list. |
| |
| A brief status of intrinsic procedure support in f18 is also given at the end. |
| |
| Few procedures are actually described here apart from their interfaces; see the |
| Fortran 2018 standard (section 16) for the complete story. |
| |
| Intrinsic modules are not covered here. |
| |
| ## General rules |
| |
| 1. The value of any intrinsic function's `KIND` actual argument, if present, |
| must be a scalar constant integer expression, of any kind, whose value |
| resolves to some supported kind of the function's result type. |
| If optional and absent, the kind of the function's result is |
| either the default kind of that category or to the kind of an argument |
| (e.g., as in `AINT`). |
| 1. Procedures are summarized with a non-Fortran syntax for brevity. |
| Wherever a function has a short definition, it appears after an |
| equal sign as if it were a statement function. Any functions referenced |
| in these short summaries are intrinsic. |
| 1. Unless stated otherwise, an actual argument may have any supported kind |
| of a particular intrinsic type. Sometimes a pattern variable |
| can appear in a description (e.g., `REAL(k)`) when the kind of an |
| actual argument's type must match the kind of another argument, or |
| determines the kind type parameter of the function result. |
| 1. When an intrinsic type name appears without a kind (e.g., `REAL`), |
| it refers to the default kind of that type. Sometimes the word |
| `default` will appear for clarity. |
| 1. The names of the dummy arguments actually matter because they can |
| be used as keywords for actual arguments. |
| 1. All standard intrinsic functions are pure, even when not elemental. |
| 1. Assumed-rank arguments may not appear as actual arguments unless |
| expressly permitted. |
| 1. When an argument is described with a default value, e.g. `KIND=KIND(0)`, |
| it is an optional argument. Optional arguments without defaults, |
| e.g. `DIM` on many transformationals, are wrapped in `[]` brackets |
| as in the Fortran standard. When an intrinsic has optional arguments |
| with and without default values, the arguments with default values |
| may appear within the brackets to preserve the order of arguments |
| (e.g., `COUNT`). |
| |
| ## Elemental intrinsic functions |
| |
| Pure elemental semantics apply to these functions, to wit: when one or more of |
| the actual arguments are arrays, the arguments must be conformable, and |
| the result is also an array. |
| Scalar arguments are expanded when the arguments are not all scalars. |
| |
| ### Elemental intrinsic functions that may have unrestricted specific procedures |
| |
| When an elemental intrinsic function is documented here as having an |
| _unrestricted specific name_, that name may be passed as an actual |
| argument, used as the target of a procedure pointer, appear in |
| a generic interface, and be otherwise used as if it were an external |
| procedure. |
| An `INTRINSIC` statement or attribute may have to be applied to an |
| unrestricted specific name to enable such usage. |
| |
| When a name is being used as a specific procedure for any purpose other |
| than that of a called function, the specific instance of the function |
| that accepts and returns values of the default kinds of the intrinsic |
| types is used. |
| A Fortran `INTERFACE` could be written to define each of |
| these unrestricted specific intrinsic function names. |
| |
| Calls to dummy arguments and procedure pointers that correspond to these |
| specific names must pass only scalar actual argument values. |
| |
| No other intrinsic function name can be passed as an actual argument, |
| used as a pointer target, appear in a generic interface, or be otherwise |
| used except as the name of a called function. |
| Some of these _restricted specific intrinsic functions_, e.g. `FLOAT`, |
| provide a means for invoking a corresponding generic (`REAL` in the case of `FLOAT`) |
| with forced argument and result kinds. |
| Others, viz. `CHAR`, `ICHAR`, `INT`, `REAL`, and the lexical comparisons like `LGE`, |
| have the same name as their generic functions, and it is not clear what purpose |
| is accomplished by the standard by defining them as specific functions. |
| |
| ### Trigonometric elemental intrinsic functions, generic and (mostly) specific |
| All of these functions can be used as unrestricted specific names. |
| |
| ``` |
| ACOS(REAL(k) X) -> REAL(k) |
| ASIN(REAL(k) X) -> REAL(k) |
| ATAN(REAL(k) X) -> REAL(k) |
| ATAN(REAL(k) Y, REAL(k) X) -> REAL(k) = ATAN2(Y, X) |
| ATAN2(REAL(k) Y, REAL(k) X) -> REAL(k) |
| COS(REAL(k) X) -> REAL(k) |
| COSH(REAL(k) X) -> REAL(k) |
| SIN(REAL(k) X) -> REAL(k) |
| SINH(REAL(k) X) -> REAL(k) |
| TAN(REAL(k) X) -> REAL(k) |
| TANH(REAL(k) X) -> REAL(k) |
| ``` |
| |
| These `COMPLEX` versions of some of those functions, and the |
| inverse hyperbolic functions, cannot be used as specific names. |
| ``` |
| ACOS(COMPLEX(k) X) -> COMPLEX(k) |
| ASIN(COMPLEX(k) X) -> COMPLEX(k) |
| ATAN(COMPLEX(k) X) -> COMPLEX(k) |
| ACOSH(REAL(k) X) -> REAL(k) |
| ACOSH(COMPLEX(k) X) -> COMPLEX(k) |
| ASINH(REAL(k) X) -> REAL(k) |
| ASINH(COMPLEX(k) X) -> COMPLEX(k) |
| ATANH(REAL(k) X) -> REAL(k) |
| ATANH(COMPLEX(k) X) -> COMPLEX(k) |
| COS(COMPLEX(k) X) -> COMPLEX(k) |
| COSH(COMPLEX(k) X) -> COMPLEX(k) |
| SIN(COMPLEX(k) X) -> COMPLEX(k) |
| SINH(COMPLEX(k) X) -> COMPLEX(k) |
| TAN(COMPLEX(k) X) -> COMPLEX(k) |
| TANH(COMPLEX(k) X) -> COMPLEX(k) |
| ``` |
| |
| ### Non-trigonometric elemental intrinsic functions, generic and specific |
| These functions *can* be used as unrestricted specific names. |
| ``` |
| ABS(REAL(k) A) -> REAL(k) = SIGN(A, 0.0) |
| AIMAG(COMPLEX(k) Z) -> REAL(k) = Z%IM |
| AINT(REAL(k) A, KIND=k) -> REAL(KIND) |
| ANINT(REAL(k) A, KIND=k) -> REAL(KIND) |
| CONJG(COMPLEX(k) Z) -> COMPLEX(k) = CMPLX(Z%RE, -Z%IM) |
| DIM(REAL(k) X, REAL(k) Y) -> REAL(k) = X-MIN(X,Y) |
| DPROD(default REAL X, default REAL Y) -> DOUBLE PRECISION = DBLE(X)*DBLE(Y) |
| EXP(REAL(k) X) -> REAL(k) |
| INDEX(CHARACTER(k) STRING, CHARACTER(k) SUBSTRING, LOGICAL(any) BACK=.FALSE., KIND=KIND(0)) -> INTEGER(KIND) |
| LEN(CHARACTER(k,n) STRING, KIND=KIND(0)) -> INTEGER(KIND) = n |
| LOG(REAL(k) X) -> REAL(k) |
| LOG10(REAL(k) X) -> REAL(k) |
| MOD(INTEGER(k) A, INTEGER(k) P) -> INTEGER(k) = A-P*INT(A/P) |
| NINT(REAL(k) A, KIND=KIND(0)) -> INTEGER(KIND) |
| SIGN(REAL(k) A, REAL(k) B) -> REAL(k) |
| SQRT(REAL(k) X) -> REAL(k) = X ** 0.5 |
| ``` |
| |
| These variants, however *cannot* be used as specific names without recourse to an alias |
| from the following section: |
| ``` |
| ABS(INTEGER(k) A) -> INTEGER(k) = SIGN(A, 0) |
| ABS(COMPLEX(k) A) -> REAL(k) = HYPOT(A%RE, A%IM) |
| DIM(INTEGER(k) X, INTEGER(k) Y) -> INTEGER(k) = X-MIN(X,Y) |
| EXP(COMPLEX(k) X) -> COMPLEX(k) |
| LOG(COMPLEX(k) X) -> COMPLEX(k) |
| MOD(REAL(k) A, REAL(k) P) -> REAL(k) = A-P*INT(A/P) |
| SIGN(INTEGER(k) A, INTEGER(k) B) -> INTEGER(k) |
| SQRT(COMPLEX(k) X) -> COMPLEX(k) |
| ``` |
| |
| ### Unrestricted specific aliases for some elemental intrinsic functions with distinct names |
| |
| ``` |
| ALOG(REAL X) -> REAL = LOG(X) |
| ALOG10(REAL X) -> REAL = LOG10(X) |
| AMOD(REAL A, REAL P) -> REAL = MOD(A, P) |
| CABS(COMPLEX A) = ABS(A) |
| CCOS(COMPLEX X) = COS(X) |
| CEXP(COMPLEX A) -> COMPLEX = EXP(A) |
| CLOG(COMPLEX X) -> COMPLEX = LOG(X) |
| CSIN(COMPLEX X) -> COMPLEX = SIN(X) |
| CSQRT(COMPLEX X) -> COMPLEX = SQRT(X) |
| CTAN(COMPLEX X) -> COMPLEX = TAN(X) |
| DABS(DOUBLE PRECISION A) -> DOUBLE PRECISION = ABS(A) |
| DACOS(DOUBLE PRECISION X) -> DOUBLE PRECISION = ACOS(X) |
| DASIN(DOUBLE PRECISION X) -> DOUBLE PRECISION = ASIN(X) |
| DATAN(DOUBLE PRECISION X) -> DOUBLE PRECISION = ATAN(X) |
| DATAN2(DOUBLE PRECISION Y, DOUBLE PRECISION X) -> DOUBLE PRECISION = ATAN2(Y, X) |
| DCOS(DOUBLE PRECISION X) -> DOUBLE PRECISION = COS(X) |
| DCOSH(DOUBLE PRECISION X) -> DOUBLE PRECISION = COSH(X) |
| DDIM(DOUBLE PRECISION X, DOUBLE PRECISION Y) -> DOUBLE PRECISION = X-MIN(X,Y) |
| DEXP(DOUBLE PRECISION X) -> DOUBLE PRECISION = EXP(X) |
| DINT(DOUBLE PRECISION A) -> DOUBLE PRECISION = AINT(A) |
| DLOG(DOUBLE PRECISION X) -> DOUBLE PRECISION = LOG(X) |
| DLOG10(DOUBLE PRECISION X) -> DOUBLE PRECISION = LOG10(X) |
| DMOD(DOUBLE PRECISION A, DOUBLE PRECISION P) -> DOUBLE PRECISION = MOD(A, P) |
| DNINT(DOUBLE PRECISION A) -> DOUBLE PRECISION = ANINT(A) |
| DSIGN(DOUBLE PRECISION A, DOUBLE PRECISION B) -> DOUBLE PRECISION = SIGN(A, B) |
| DSIN(DOUBLE PRECISION X) -> DOUBLE PRECISION = SIN(X) |
| DSINH(DOUBLE PRECISION X) -> DOUBLE PRECISION = SINH(X) |
| DSQRT(DOUBLE PRECISION X) -> DOUBLE PRECISION = SQRT(X) |
| DTAN(DOUBLE PRECISION X) -> DOUBLE PRECISION = TAN(X) |
| DTANH(DOUBLE PRECISION X) -> DOUBLE PRECISION = TANH(X) |
| IABS(INTEGER A) -> INTEGER = ABS(A) |
| IDIM(INTEGER X, INTEGER Y) -> INTEGER = X-MIN(X,Y) |
| IDNINT(DOUBLE PRECISION A) -> INTEGER = NINT(A) |
| ISIGN(INTEGER A, INTEGER B) -> INTEGER = SIGN(A, B) |
| ``` |
| |
| ## Generic elemental intrinsic functions without specific names |
| |
| (No procedures after this point can be passed as actual arguments, used as |
| pointer targets, or appear as specific procedures in generic interfaces.) |
| |
| ### Elemental conversions |
| |
| ``` |
| ACHAR(INTEGER(k) I, KIND=KIND('')) -> CHARACTER(KIND,LEN=1) |
| CEILING(REAL() A, KIND=KIND(0)) -> INTEGER(KIND) |
| CHAR(INTEGER(any) I, KIND=KIND('')) -> CHARACTER(KIND,LEN=1) |
| CMPLX(COMPLEX(k) X, KIND=KIND(0.0D0)) -> COMPLEX(KIND) |
| CMPLX(INTEGER or REAL or BOZ X, INTEGER or REAL or BOZ Y=0, KIND=KIND((0,0))) -> COMPLEX(KIND) |
| DBLE(INTEGER or REAL or COMPLEX or BOZ A) = REAL(A, KIND=KIND(0.0D0)) |
| EXPONENT(REAL(any) X) -> default INTEGER |
| FLOOR(REAL(any) A, KIND=KIND(0)) -> INTEGER(KIND) |
| IACHAR(CHARACTER(KIND=k,LEN=1) C, KIND=KIND(0)) -> INTEGER(KIND) |
| ICHAR(CHARACTER(KIND=k,LEN=1) C, KIND=KIND(0)) -> INTEGER(KIND) |
| INT(INTEGER or REAL or COMPLEX or BOZ A, KIND=KIND(0)) -> INTEGER(KIND) |
| LOGICAL(LOGICAL(any) L, KIND=KIND(.TRUE.)) -> LOGICAL(KIND) |
| REAL(INTEGER or REAL or COMPLEX or BOZ A, KIND=KIND(0.0)) -> REAL(KIND) |
| ``` |
| |
| ### Other generic elemental intrinsic functions without specific names |
| N.B. `BESSEL_JN(N1, N2, X)` and `BESSEL_YN(N1, N2, X)` are categorized |
| below with the _transformational_ intrinsic functions. |
| |
| ``` |
| BESSEL_J0(REAL(k) X) -> REAL(k) |
| BESSEL_J1(REAL(k) X) -> REAL(k) |
| BESSEL_JN(INTEGER(n) N, REAL(k) X) -> REAL(k) |
| BESSEL_Y0(REAL(k) X) -> REAL(k) |
| BESSEL_Y1(REAL(k) X) -> REAL(k) |
| BESSEL_YN(INTEGER(n) N, REAL(k) X) -> REAL(k) |
| ERF(REAL(k) X) -> REAL(k) |
| DERF(REAL(8) X) -> REAL(8) |
| QERF(REAL(16) X) -> REAL(16) |
| ERFC(REAL(k) X) -> REAL(k) |
| DERFC(REAL(8) X) -> REAL(8) |
| QERFC(REAL(16) X) -> REAL(16) |
| ERFC_SCALED(REAL(k) X) -> REAL(k) |
| DERFC_SCALED(REAL(8) X) -> REAL(8) |
| QERFC_SCALED(REAL(16) X) -> REAL(16) |
| FRACTION(REAL(k) X) -> REAL(k) |
| GAMMA(REAL(k) X) -> REAL(k) |
| HYPOT(REAL(k) X, REAL(k) Y) -> REAL(k) = SQRT(X*X+Y*Y) without spurious overflow |
| IMAGE_STATUS(INTEGER(any) IMAGE [, scalar TEAM_TYPE TEAM ]) -> default INTEGER |
| IS_IOSTAT_END(INTEGER(any) I) -> default LOGICAL |
| IS_IOSTAT_EOR(INTEGER(any) I) -> default LOGICAL |
| LOG_GAMMA(REAL(k) X) -> REAL(k) |
| MAX(INTEGER(k) ...) -> INTEGER(k) |
| MAX(REAL(k) ...) -> REAL(k) |
| MAX(CHARACTER(KIND=k) ...) -> CHARACTER(KIND=k,LEN=MAX(LEN(...))) |
| MERGE(any type TSOURCE, same type FSOURCE, LOGICAL(any) MASK) -> type of FSOURCE |
| MIN(INTEGER(k) ...) -> INTEGER(k) |
| MIN(REAL(k) ...) -> REAL(k) |
| MIN(CHARACTER(KIND=k) ...) -> CHARACTER(KIND=k,LEN=MAX(LEN(...))) |
| MODULO(INTEGER(k) A, INTEGER(k) P) -> INTEGER(k); P*result >= 0 |
| MODULO(REAL(k) A, REAL(k) P) -> REAL(k) = A - P*FLOOR(A/P) |
| NEAREST(REAL(k) X, REAL(any) S) -> REAL(k) |
| OUT_OF_RANGE(INTEGER(any) X, scalar INTEGER or REAL(k) MOLD) -> default LOGICAL |
| OUT_OF_RANGE(REAL(any) X, scalar REAL(k) MOLD) -> default LOGICAL |
| OUT_OF_RANGE(REAL(any) X, scalar INTEGER(any) MOLD, scalar LOGICAL(any) ROUND=.FALSE.) -> default LOGICAL |
| RRSPACING(REAL(k) X) -> REAL(k) |
| SCALE(REAL(k) X, INTEGER(any) I) -> REAL(k) |
| SET_EXPONENT(REAL(k) X, INTEGER(any) I) -> REAL(k) |
| SPACING(REAL(k) X) -> REAL(k) |
| ``` |
| |
| ### Restricted specific aliases for elemental conversions &/or extrema with default intrinsic types |
| |
| ``` |
| AMAX0(INTEGER ...) = REAL(MAX(...)) |
| AMAX1(REAL ...) = MAX(...) |
| AMIN0(INTEGER...) = REAL(MIN(...)) |
| AMIN1(REAL ...) = MIN(...) |
| DMAX1(DOUBLE PRECISION ...) = MAX(...) |
| DMIN1(DOUBLE PRECISION ...) = MIN(...) |
| FLOAT(INTEGER I) = REAL(I) |
| IDINT(DOUBLE PRECISION A) = INT(A) |
| IFIX(REAL A) = INT(A) |
| MAX0(INTEGER ...) = MAX(...) |
| MAX1(REAL ...) = INT(MAX(...)) |
| MIN0(INTEGER ...) = MIN(...) |
| MIN1(REAL ...) = INT(MIN(...)) |
| SNGL(DOUBLE PRECISION A) = REAL(A) |
| ``` |
| |
| ### Generic elemental bit manipulation intrinsic functions |
| Many of these accept a typeless "BOZ" literal as an actual argument. |
| It is interpreted as having the kind of intrinsic `INTEGER` type |
| as another argument, as if the typeless were implicitly wrapped |
| in a call to `INT()`. |
| When multiple arguments can be either `INTEGER` values or typeless |
| constants, it is forbidden for *all* of them to be typeless |
| constants if the result of the function is `INTEGER` |
| (i.e., only `BGE`, `BGT`, `BLE`, and `BLT` can have multiple |
| typeless arguments). |
| |
| ``` |
| BGE(INTEGER(n1) or BOZ I, INTEGER(n2) or BOZ J) -> default LOGICAL |
| BGT(INTEGER(n1) or BOZ I, INTEGER(n2) or BOZ J) -> default LOGICAL |
| BLE(INTEGER(n1) or BOZ I, INTEGER(n2) or BOZ J) -> default LOGICAL |
| BLT(INTEGER(n1) or BOZ I, INTEGER(n2) or BOZ J) -> default LOGICAL |
| BTEST(INTEGER(n1) I, INTEGER(n2) POS) -> default LOGICAL |
| DSHIFTL(INTEGER(k) I, INTEGER(k) or BOZ J, INTEGER(any) SHIFT) -> INTEGER(k) |
| DSHIFTL(BOZ I, INTEGER(k), INTEGER(any) SHIFT) -> INTEGER(k) |
| DSHIFTR(INTEGER(k) I, INTEGER(k) or BOZ J, INTEGER(any) SHIFT) -> INTEGER(k) |
| DSHIFTR(BOZ I, INTEGER(k), INTEGER(any) SHIFT) -> INTEGER(k) |
| IAND(INTEGER(k) I, INTEGER(k) or BOZ J) -> INTEGER(k) |
| IAND(BOZ I, INTEGER(k) J) -> INTEGER(k) |
| IBCLR(INTEGER(k) I, INTEGER(any) POS) -> INTEGER(k) |
| IBITS(INTEGER(k) I, INTEGER(n1) POS, INTEGER(n2) LEN) -> INTEGER(k) |
| IBSET(INTEGER(k) I, INTEGER(any) POS) -> INTEGER(k) |
| IEOR(INTEGER(k) I, INTEGER(k) or BOZ J) -> INTEGER(k) |
| IEOR(BOZ I, INTEGER(k) J) -> INTEGER(k) |
| IOR(INTEGER(k) I, INTEGER(k) or BOZ J) -> INTEGER(k) |
| IOR(BOZ I, INTEGER(k) J) -> INTEGER(k) |
| ISHFT(INTEGER(k) I, INTEGER(any) SHIFT) -> INTEGER(k) |
| ISHFTC(INTEGER(k) I, INTEGER(n1) SHIFT, INTEGER(n2) SIZE=BIT_SIZE(I)) -> INTEGER(k) |
| LEADZ(INTEGER(any) I) -> default INTEGER |
| MASKL(INTEGER(any) I, KIND=KIND(0)) -> INTEGER(KIND) |
| MASKR(INTEGER(any) I, KIND=KIND(0)) -> INTEGER(KIND) |
| MERGE_BITS(INTEGER(k) I, INTEGER(k) or BOZ J, INTEGER(k) or BOZ MASK) = IOR(IAND(I,MASK),IAND(J,NOT(MASK))) |
| MERGE_BITS(BOZ I, INTEGER(k) J, INTEGER(k) or BOZ MASK) = IOR(IAND(I,MASK),IAND(J,NOT(MASK))) |
| NOT(INTEGER(k) I) -> INTEGER(k) |
| POPCNT(INTEGER(any) I) -> default INTEGER |
| POPPAR(INTEGER(any) I) -> default INTEGER = IAND(POPCNT(I), Z'1') |
| SHIFTA(INTEGER(k) I, INTEGER(any) SHIFT) -> INTEGER(k) |
| SHIFTL(INTEGER(k) I, INTEGER(any) SHIFT) -> INTEGER(k) |
| SHIFTR(INTEGER(k) I, INTEGER(any) SHIFT) -> INTEGER(k) |
| TRAILZ(INTEGER(any) I) -> default INTEGER |
| ``` |
| |
| ### Character elemental intrinsic functions |
| See also `INDEX` and `LEN` above among the elemental intrinsic functions with |
| unrestricted specific names. |
| ``` |
| ADJUSTL(CHARACTER(k,LEN=n) STRING) -> CHARACTER(k,LEN=n) |
| ADJUSTR(CHARACTER(k,LEN=n) STRING) -> CHARACTER(k,LEN=n) |
| LEN_TRIM(CHARACTER(k,n) STRING, KIND=KIND(0)) -> INTEGER(KIND) = n |
| LGE(CHARACTER(k,n1) STRING_A, CHARACTER(k,n2) STRING_B) -> default LOGICAL |
| LGT(CHARACTER(k,n1) STRING_A, CHARACTER(k,n2) STRING_B) -> default LOGICAL |
| LLE(CHARACTER(k,n1) STRING_A, CHARACTER(k,n2) STRING_B) -> default LOGICAL |
| LLT(CHARACTER(k,n1) STRING_A, CHARACTER(k,n2) STRING_B) -> default LOGICAL |
| SCAN(CHARACTER(k,n) STRING, CHARACTER(k,m) SET, LOGICAL(any) BACK=.FALSE., KIND=KIND(0)) -> INTEGER(KIND) |
| VERIFY(CHARACTER(k,n) STRING, CHARACTER(k,m) SET, LOGICAL(any) BACK=.FALSE., KIND=KIND(0)) -> INTEGER(KIND) |
| ``` |
| |
| `SCAN` returns the index of the first (or last, if `BACK=.TRUE.`) character in `STRING` |
| that is present in `SET`, or zero if none is. |
| |
| `VERIFY` is essentially the opposite: it returns the index of the first (or last) character |
| in `STRING` that is *not* present in `SET`, or zero if all are. |
| |
| ## Transformational intrinsic functions |
| |
| This category comprises a large collection of intrinsic functions that |
| are collected together because they somehow transform their arguments |
| in a way that prevents them from being elemental. |
| All of them are pure, however. |
| |
| Some general rules apply to the transformational intrinsic functions: |
| |
| 1. `DIM` arguments are optional; if present, the actual argument must be |
| a scalar integer of any kind. |
| 1. When an optional `DIM` argument is absent, or an `ARRAY` or `MASK` |
| argument is a vector, the result of the function is scalar; otherwise, |
| the result is an array of the same shape as the `ARRAY` or `MASK` |
| argument with the dimension `DIM` removed from the shape. |
| 1. When a function takes an optional `MASK` argument, it must be conformable |
| with its `ARRAY` argument if it is present, and the mask can be any kind |
| of `LOGICAL`. It can be scalar. |
| 1. The type `numeric` here can be any kind of `INTEGER`, `REAL`, or `COMPLEX`. |
| 1. The type `relational` here can be any kind of `INTEGER`, `REAL`, or `CHARACTER`. |
| 1. The type `any` here denotes any intrinsic or derived type. |
| 1. The notation `(..)` denotes an array of any rank (but not an assumed-rank array). |
| |
| ### Logical reduction transformational intrinsic functions |
| ``` |
| ALL(LOGICAL(k) MASK(..) [, DIM ]) -> LOGICAL(k) |
| ANY(LOGICAL(k) MASK(..) [, DIM ]) -> LOGICAL(k) |
| COUNT(LOGICAL(any) MASK(..) [, DIM, KIND=KIND(0) ]) -> INTEGER(KIND) |
| PARITY(LOGICAL(k) MASK(..) [, DIM ]) -> LOGICAL(k) |
| ``` |
| |
| ### Numeric reduction transformational intrinsic functions |
| ``` |
| IALL(INTEGER(k) ARRAY(..) [, DIM, MASK ]) -> INTEGER(k) |
| IANY(INTEGER(k) ARRAY(..) [, DIM, MASK ]) -> INTEGER(k) |
| IPARITY(INTEGER(k) ARRAY(..) [, DIM, MASK ]) -> INTEGER(k) |
| NORM2(REAL(k) X(..) [, DIM ]) -> REAL(k) |
| PRODUCT(numeric ARRAY(..) [, DIM, MASK ]) -> numeric |
| SUM(numeric ARRAY(..) [, DIM, MASK ]) -> numeric |
| ``` |
| |
| `NORM2` generalizes `HYPOT` by computing `SQRT(SUM(X*X))` while avoiding spurious overflows. |
| |
| ### Extrema reduction transformational intrinsic functions |
| ``` |
| MAXVAL(relational(k) ARRAY(..) [, DIM, MASK ]) -> relational(k) |
| MINVAL(relational(k) ARRAY(..) [, DIM, MASK ]) -> relational(k) |
| ``` |
| |
| ### Locational transformational intrinsic functions |
| When the optional `DIM` argument is absent, the result is an `INTEGER(KIND)` |
| vector whose length is the rank of `ARRAY`. |
| When the optional `DIM` argument is present, the result is an `INTEGER(KIND)` |
| array of rank `RANK(ARRAY)-1` and shape equal to that of `ARRAY` with |
| the dimension `DIM` removed. |
| |
| The optional `BACK` argument is a scalar LOGICAL value of any kind. |
| When present and `.TRUE.`, it causes the function to return the index |
| of the *last* occurence of the target or extreme value. |
| |
| For `FINDLOC`, `ARRAY` may have any of the five intrinsic types, and `VALUE` |
| must a scalar value of a type for which `ARRAY==VALUE` or `ARRAY .EQV. VALUE` |
| is an acceptable expression. |
| |
| ``` |
| FINDLOC(intrinsic ARRAY(..), scalar VALUE [, DIM, MASK, KIND=KIND(0), BACK=.FALSE. ]) |
| MAXLOC(relational ARRAY(..) [, DIM, MASK, KIND=KIND(0), BACK=.FALSE. ]) |
| MINLOC(relational ARRAY(..) [, DIM, MASK, KIND=KIND(0), BACK=.FALSE. ]) |
| ``` |
| |
| ### Data rearrangement transformational intrinsic functions |
| The optional `DIM` argument to these functions must be a scalar integer of |
| any kind, and it takes a default value of 1 when absent. |
| |
| ``` |
| CSHIFT(any ARRAY(..), INTEGER(any) SHIFT(..) [, DIM ]) -> same type/kind/shape as ARRAY |
| ``` |
| Either `SHIFT` is scalar or `RANK(SHIFT) == RANK(ARRAY) - 1` and `SHAPE(SHIFT)` is that of `SHAPE(ARRAY)` with element `DIM` removed. |
| |
| ``` |
| EOSHIFT(any ARRAY(..), INTEGER(any) SHIFT(..) [, BOUNDARY, DIM ]) -> same type/kind/shape as ARRAY |
| ``` |
| * `SHIFT` is scalar or `RANK(SHIFT) == RANK(ARRAY) - 1` and `SHAPE(SHIFT)` is that of `SHAPE(ARRAY)` with element `DIM` removed. |
| * If `BOUNDARY` is present, it must have the same type and parameters as `ARRAY`. |
| * If `BOUNDARY` is absent, `ARRAY` must be of an intrinsic type, and the default `BOUNDARY` is the obvious `0`, `' '`, or `.FALSE.` value of `KIND(ARRAY)`. |
| * If `BOUNDARY` is present, either it is scalar, or `RANK(BOUNDARY) == RANK(ARRAY) - 1` and `SHAPE(BOUNDARY)` is that of `SHAPE(ARRAY)` with element `DIM` |
| removed. |
| |
| ``` |
| PACK(any ARRAY(..), LOGICAL(any) MASK(..)) -> vector of same type and kind as ARRAY |
| ``` |
| * `MASK` is conformable with `ARRAY` and may be scalar. |
| * The length of the result vector is `COUNT(MASK)` if `MASK` is an array, else `SIZE(ARRAY)` if `MASK` is `.TRUE.`, else zero. |
| |
| ``` |
| PACK(any ARRAY(..), LOGICAL(any) MASK(..), any VECTOR(n)) -> vector of same type, kind, and size as VECTOR |
| ``` |
| * `MASK` is conformable with `ARRAY` and may be scalar. |
| * `VECTOR` has the same type and kind as `ARRAY`. |
| * `VECTOR` must not be smaller than result of `PACK` with no `VECTOR` argument. |
| * The leading elements of `VECTOR` are replaced with elements from `ARRAY` as |
| if `PACK` had been invoked without `VECTOR`. |
| |
| ``` |
| RESHAPE(any SOURCE(..), INTEGER(k) SHAPE(n) [, PAD(..), INTEGER(k2) ORDER(n) ]) -> SOURCE array with shape SHAPE |
| ``` |
| * If `ORDER` is present, it is a vector of the same size as `SHAPE`, and |
| contains a permutation. |
| * The element(s) of `PAD` are used to fill out the result once `SOURCE` |
| has been consumed. |
| |
| ``` |
| SPREAD(any SOURCE, DIM, scalar INTEGER(any) NCOPIES) -> same type as SOURCE, rank=RANK(SOURCE)+1 |
| TRANSFER(any SOURCE, any MOLD) -> scalar if MOLD is scalar, else vector; same type and kind as MOLD |
| TRANSFER(any SOURCE, any MOLD, scalar INTEGER(any) SIZE) -> vector(SIZE) of type and kind of MOLD |
| TRANSPOSE(any MATRIX(n,m)) -> matrix(m,n) of same type and kind as MATRIX |
| ``` |
| |
| The shape of the result of `SPREAD` is the same as that of `SOURCE`, with `NCOPIES` inserted |
| at position `DIM`. |
| |
| ``` |
| UNPACK(any VECTOR(n), LOGICAL(any) MASK(..), FIELD) -> type and kind of VECTOR, shape of MASK |
| ``` |
| `FIELD` has same type and kind as `VECTOR` and is conformable with `MASK`. |
| |
| ### Other transformational intrinsic functions |
| ``` |
| BESSEL_JN(INTEGER(n1) N1, INTEGER(n2) N2, REAL(k) X) -> REAL(k) vector (MAX(N2-N1+1,0)) |
| BESSEL_YN(INTEGER(n1) N1, INTEGER(n2) N2, REAL(k) X) -> REAL(k) vector (MAX(N2-N1+1,0)) |
| COMMAND_ARGUMENT_COUNT() -> scalar default INTEGER |
| DOT_PRODUCT(LOGICAL(k) VECTOR_A(n), LOGICAL(k) VECTOR_B(n)) -> LOGICAL(k) = ANY(VECTOR_A .AND. VECTOR_B) |
| DOT_PRODUCT(COMPLEX(any) VECTOR_A(n), numeric VECTOR_B(n)) = SUM(CONJG(VECTOR_A) * VECTOR_B) |
| DOT_PRODUCT(INTEGER(any) or REAL(any) VECTOR_A(n), numeric VECTOR_B(n)) = SUM(VECTOR_A * VECTOR_B) |
| MATMUL(numeric ARRAY_A(j), numeric ARRAY_B(j,k)) -> numeric vector(k) |
| MATMUL(numeric ARRAY_A(j,k), numeric ARRAY_B(k)) -> numeric vector(j) |
| MATMUL(numeric ARRAY_A(j,k), numeric ARRAY_B(k,m)) -> numeric matrix(j,m) |
| MATMUL(LOGICAL(n1) ARRAY_A(j), LOGICAL(n2) ARRAY_B(j,k)) -> LOGICAL vector(k) |
| MATMUL(LOGICAL(n1) ARRAY_A(j,k), LOGICAL(n2) ARRAY_B(k)) -> LOGICAL vector(j) |
| MATMUL(LOGICAL(n1) ARRAY_A(j,k), LOGICAL(n2) ARRAY_B(k,m)) -> LOGICAL matrix(j,m) |
| NULL([POINTER/ALLOCATABLE MOLD]) -> POINTER |
| REDUCE(any ARRAY(..), function OPERATION [, DIM, LOGICAL(any) MASK(..), IDENTITY, LOGICAL ORDERED=.FALSE. ]) |
| REPEAT(CHARACTER(k,n) STRING, INTEGER(any) NCOPIES) -> CHARACTER(k,n*NCOPIES) |
| SELECTED_CHAR_KIND('DEFAULT' or 'ASCII' or 'ISO_10646' or ...) -> scalar default INTEGER |
| SELECTED_INT_KIND(scalar INTEGER(any) R) -> scalar default INTEGER |
| SELECTED_REAL_KIND([scalar INTEGER(any) P, scalar INTEGER(any) R, scalar INTEGER(any) RADIX]) -> scalar default INTEGER |
| SHAPE(SOURCE, KIND=KIND(0)) -> INTEGER(KIND)(RANK(SOURCE)) |
| TRIM(CHARACTER(k,n) STRING) -> CHARACTER(k) |
| ``` |
| |
| The type and kind of the result of a numeric `MATMUL` is the same as would result from |
| a multiplication of an element of ARRAY_A and an element of ARRAY_B. |
| |
| The kind of the `LOGICAL` result of a `LOGICAL` `MATMUL` is the same as would result |
| from an intrinsic `.AND.` operation between an element of `ARRAY_A` and an element |
| of `ARRAY_B`. |
| |
| Note that `DOT_PRODUCT` with a `COMPLEX` first argument operates on its complex conjugate, |
| but that `MATMUL` with a `COMPLEX` argument does not. |
| |
| The `MOLD` argument to `NULL` may be omitted only in a context where the type of the pointer is known, |
| such as an initializer or pointer assignment statement. |
| |
| At least one argument must be present in a call to `SELECTED_REAL_KIND`. |
| |
| An assumed-rank array may be passed to `SHAPE`, and if it is associated with an assumed-size array, |
| the last element of the result will be -1. |
| |
| ### Coarray transformational intrinsic functions |
| ``` |
| FAILED_IMAGES([scalar TEAM_TYPE TEAM, KIND=KIND(0)]) -> INTEGER(KIND) vector |
| GET_TEAM([scalar INTEGER(?) LEVEL]) -> scalar TEAM_TYPE |
| IMAGE_INDEX(COARRAY, INTEGER(any) SUB(n) [, scalar TEAM_TYPE TEAM ]) -> scalar default INTEGER |
| IMAGE_INDEX(COARRAY, INTEGER(any) SUB(n), scalar INTEGER(any) TEAM_NUMBER) -> scalar default INTEGER |
| NUM_IMAGES([scalar TEAM_TYPE TEAM]) -> scalar default INTEGER |
| NUM_IMAGES(scalar INTEGER(any) TEAM_NUMBER) -> scalar default INTEGER |
| STOPPED_IMAGES([scalar TEAM_TYPE TEAM, KIND=KIND(0)]) -> INTEGER(KIND) vector |
| TEAM_NUMBER([scalar TEAM_TYPE TEAM]) -> scalar default INTEGER |
| THIS_IMAGE([COARRAY, DIM, scalar TEAM_TYPE TEAM]) -> default INTEGER |
| ``` |
| The result of `THIS_IMAGE` is a scalar if `DIM` is present or if `COARRAY` is absent, |
| and a vector whose length is the corank of `COARRAY` otherwise. |
| |
| ## Inquiry intrinsic functions |
| These are neither elemental nor transformational; all are pure. |
| |
| ### Type inquiry intrinsic functions |
| All of these functions return constants. |
| The value of the argument is not used, and may well be undefined. |
| ``` |
| BIT_SIZE(INTEGER(k) I(..)) -> INTEGER(k) |
| DIGITS(INTEGER or REAL X(..)) -> scalar default INTEGER |
| EPSILON(REAL(k) X(..)) -> scalar REAL(k) |
| HUGE(INTEGER(k) X(..)) -> scalar INTEGER(k) |
| HUGE(REAL(k) X(..)) -> scalar of REAL(k) |
| KIND(intrinsic X(..)) -> scalar default INTEGER |
| MAXEXPONENT(REAL(k) X(..)) -> scalar default INTEGER |
| MINEXPONENT(REAL(k) X(..)) -> scalar default INTEGER |
| NEW_LINE(CHARACTER(k,n) A(..)) -> scalar CHARACTER(k,1) = CHAR(10) |
| PRECISION(REAL(k) or COMPLEX(k) X(..)) -> scalar default INTEGER |
| RADIX(INTEGER(k) or REAL(k) X(..)) -> scalar default INTEGER, always 2 |
| RANGE(INTEGER(k) or REAL(k) or COMPLEX(k) X(..)) -> scalar default INTEGER |
| TINY(REAL(k) X(..)) -> scalar REAL(k) |
| ``` |
| |
| ### Bound and size inquiry intrinsic functions |
| The results are scalar when `DIM` is present, and a vector of length=(co)rank(`(CO)ARRAY`) |
| when `DIM` is absent. |
| ``` |
| LBOUND(any ARRAY(..) [, DIM, KIND=KIND(0) ]) -> INTEGER(KIND) |
| LCOBOUND(any COARRAY [, DIM, KIND=KIND(0) ]) -> INTEGER(KIND) |
| SIZE(any ARRAY(..) [, DIM, KIND=KIND(0) ]) -> INTEGER(KIND) |
| UBOUND(any ARRAY(..) [, DIM, KIND=KIND(0) ]) -> INTEGER(KIND) |
| UCOBOUND(any COARRAY [, DIM, KIND=KIND(0) ]) -> INTEGER(KIND) |
| ``` |
| |
| Assumed-rank arrays may be used with `LBOUND`, `SIZE`, and `UBOUND`. |
| |
| ### Object characteristic inquiry intrinsic functions |
| ``` |
| ALLOCATED(any type ALLOCATABLE ARRAY) -> scalar default LOGICAL |
| ALLOCATED(any type ALLOCATABLE SCALAR) -> scalar default LOGICAL |
| ASSOCIATED(any type POINTER POINTER [, same type TARGET]) -> scalar default LOGICAL |
| COSHAPE(COARRAY, KIND=KIND(0)) -> INTEGER(KIND) vector of length corank(COARRAY) |
| EXTENDS_TYPE_OF(A, MOLD) -> default LOGICAL |
| IS_CONTIGUOUS(any data ARRAY(..)) -> scalar default LOGICAL |
| PRESENT(OPTIONAL A) -> scalar default LOGICAL |
| RANK(any data A) -> scalar default INTEGER = 0 if A is scalar, SIZE(SHAPE(A)) if A is an array, rank if assumed-rank |
| SAME_TYPE_AS(A, B) -> scalar default LOGICAL |
| STORAGE_SIZE(any data A, KIND=KIND(0)) -> INTEGER(KIND) |
| ``` |
| The arguments to `EXTENDS_TYPE_OF` must be of extensible derived types or be unlimited polymorphic. |
| |
| An assumed-rank array may be used with `IS_CONTIGUOUS` and `RANK`. |
| |
| ## Intrinsic subroutines |
| |
| (*TODO*: complete these descriptions) |
| |
| ### One elemental intrinsic subroutine |
| ``` |
| INTERFACE |
| SUBROUTINE MVBITS(FROM, FROMPOS, LEN, TO, TOPOS) |
| INTEGER(k1) :: FROM, TO |
| INTENT(IN) :: FROM |
| INTENT(INOUT) :: TO |
| INTEGER(k2), INTENT(IN) :: FROMPOS |
| INTEGER(k3), INTENT(IN) :: LEN |
| INTEGER(k4), INTENT(IN) :: TOPOS |
| END SUBROUTINE |
| END INTERFACE |
| ``` |
| |
| ### Non-elemental intrinsic subroutines |
| ``` |
| CALL CPU_TIME(REAL INTENT(OUT) TIME) |
| ``` |
| The kind of `TIME` is not specified in the standard. |
| |
| ``` |
| CALL DATE_AND_TIME([DATE, TIME, ZONE, VALUES]) |
| ``` |
| * All arguments are `OPTIONAL` and `INTENT(OUT)`. |
| * `DATE`, `TIME`, and `ZONE` are scalar default `CHARACTER`. |
| * `VALUES` is a vector of at least 8 elements of `INTEGER(KIND >= 2)`. |
| ``` |
| CALL EVENT_QUERY(EVENT, COUNT [, STAT]) |
| CALL EXECUTE_COMMAND_LINE(COMMAND [, WAIT, EXITSTAT, CMDSTAT, CMDMSG ]) |
| CALL GET_COMMAND([COMMAND, LENGTH, STATUS, ERRMSG ]) |
| CALL GET_COMMAND_ARGUMENT(NUMBER [, VALUE, LENGTH, STATUS, ERRMSG ]) |
| CALL GET_ENVIRONMENT_VARIABLE(NAME [, VALUE, LENGTH, STATUS, TRIM_NAME, ERRMSG ]) |
| CALL MOVE_ALLOC(ALLOCATABLE INTENT(INOUT) FROM, ALLOCATABLE INTENT(OUT) TO [, STAT, ERRMSG ]) |
| CALL RANDOM_INIT(LOGICAL(k1) INTENT(IN) REPEATABLE, LOGICAL(k2) INTENT(IN) IMAGE_DISTINCT) |
| CALL RANDOM_NUMBER(REAL(k) INTENT(OUT) HARVEST(..)) |
| CALL RANDOM_SEED([SIZE, PUT, GET]) |
| CALL SYSTEM_CLOCK([COUNT, COUNT_RATE, COUNT_MAX]) |
| ``` |
| |
| ### Atomic intrinsic subroutines |
| ``` |
| CALL ATOMIC_ADD(ATOM, VALUE [, STAT=]) |
| CALL ATOMIC_AND(ATOM, VALUE [, STAT=]) |
| CALL ATOMIC_CAS(ATOM, OLD, COMPARE, NEW [, STAT=]) |
| CALL ATOMIC_DEFINE(ATOM, VALUE [, STAT=]) |
| CALL ATOMIC_FETCH_ADD(ATOM, VALUE, OLD [, STAT=]) |
| CALL ATOMIC_FETCH_AND(ATOM, VALUE, OLD [, STAT=]) |
| CALL ATOMIC_FETCH_OR(ATOM, VALUE, OLD [, STAT=]) |
| CALL ATOMIC_FETCH_XOR(ATOM, VALUE, OLD [, STAT=]) |
| CALL ATOMIC_OR(ATOM, VALUE [, STAT=]) |
| CALL ATOMIC_REF(VALUE, ATOM [, STAT=]) |
| CALL ATOMIC_XOR(ATOM, VALUE [, STAT=]) |
| ``` |
| |
| ### Collective intrinsic subroutines |
| ``` |
| CALL CO_BROADCAST |
| CALL CO_MAX |
| CALL CO_MIN |
| CALL CO_REDUCE |
| CALL CO_SUM |
| ``` |
| |
| ### Inquiry Functions |
| ACCESS (GNU extension) is not supported on Windows. Otherwise: |
| ``` |
| CHARACTER(LEN=*) :: path = 'path/to/file' |
| IF (ACCESS(path, 'rwx')) & |
| ... |
| ``` |
| |
| ## Non-standard intrinsics |
| ### PGI |
| ``` |
| AND, OR, XOR |
| LSHIFT, RSHIFT, SHIFT |
| ZEXT, IZEXT |
| COSD, SIND, TAND, ACOSD, ASIND, ATAND, ATAN2D |
| COMPL |
| DCMPLX |
| EQV, NEQV |
| INT8 |
| JINT, JNINT, KNINT |
| LOC |
| ``` |
| |
| ### Intel |
| ``` |
| DCMPLX(X,Y), QCMPLX(X,Y) |
| DREAL(DOUBLE COMPLEX A) -> DOUBLE PRECISION |
| DFLOAT, DREAL |
| QEXT, QFLOAT, QREAL |
| DNUM, INUM, JNUM, KNUM, QNUM, RNUM - scan value from string |
| ZEXT |
| RAN, RANF |
| ILEN(I) = BIT_SIZE(I) |
| SIZEOF |
| MCLOCK, SECNDS |
| COTAN(X) = 1.0/TAN(X) |
| COSD, SIND, TAND, ACOSD, ASIND, ATAND, ATAN2D, COTAND - degrees |
| AND, OR, XOR |
| LSHIFT, RSHIFT |
| IBCHNG, ISHA, ISHC, ISHL, IXOR |
| IARG, IARGC, NARGS, NUMARG |
| BADDRESS, IADDR |
| CACHESIZE, EOF, FP_CLASS, INT_PTR_KIND, ISNAN, LOC |
| MALLOC, FREE |
| ``` |
| |
| ### Library subroutine |
| ``` |
| CALL BACKTRACE() |
| CALL FDATE(TIME) |
| CALL GETLOG(USRNAME) |
| CALL GETENV(NAME [, VALUE, LENGTH, STATUS, TRIM_NAME, ERRMSG ]) |
| ``` |
| |
| ## Intrinsic Procedure Name Resolution |
| |
| When the name of a procedure in a program is the same as the one of an intrinsic |
| procedure, and nothing other than its usage allows to decide whether the procedure |
| is the intrinsic or not (i.e, it does not appear in an INTRINSIC or EXTERNAL attribute |
| statement, is not an use/host associated procedure...), Fortran 2018 standard |
| section 19.5.1.4 point 6 rules that the procedure is established to be intrinsic if it is |
| invoked as an intrinsic procedure. |
| |
| In case the invocation would be an error if the procedure were the intrinsic |
| (e.g. wrong argument number or type), the broad wording of the standard |
| leaves two choices to the compiler: emit an error about the intrinsic invocation, |
| or consider this is an external procedure and emit no error. |
| |
| f18 will always consider this case to be the intrinsic and emit errors, unless the procedure |
| is used as a function (resp. subroutine) and the intrinsic is a subroutine (resp. function). |
| The table below gives some examples of decisions made by Fortran compilers in such case. |
| |
| | What is ACOS ? | Bad intrinsic call | External with warning | External no warning | Other error | |
| | --- | --- | --- | --- | --- | |
| | `print*, ACOS()` | gfortran, nag, xlf, f18 | ifort | nvfortran | | |
| | `print*, ACOS(I)` | gfortran, nag, xlf, f18 | ifort | nvfortran | | |
| | `print*, ACOS(X=I)` | gfortran, nag, xlf, f18 | ifort | | nvfortran (keyword on implicit extrenal )| |
| | `print*, ACOS(X, X)` | gfortran, nag, xlf, f18 | ifort | nvfortran | | |
| | `CALL ACOS(X)` | | | gfortran, nag, xlf, nvfortran, ifort, f18 | | |
| |
| |
| The rationale for f18 behavior is that when referring to a procedure with an |
| argument number or type that does not match the intrinsic specification, it seems safer to block |
| the rather likely case where the user is using the intrinsic the wrong way. |
| In case the user wanted to refer to an external function, he can add an explicit EXTERNAL |
| statement with no other consequences on the program. |
| However, it seems rather unlikely that a user would confuse an intrinsic subroutine for a |
| function and vice versa. Given no compiler is issuing an error here, changing the behavior might |
| affect existing programs that omit the EXTERNAL attribute in such case. |
| |
| Also note that in general, the standard gives the compiler the right to consider |
| any procedure that is not explicitly external as a non standard intrinsic (section 4.2 point 4). |
| So it is highly advised for the programmer to use EXTERNAL statements to prevent any ambiguity. |
| |
| ## Intrinsic Procedure Support in f18 |
| This section gives an overview of the support inside f18 libraries for the |
| intrinsic procedures listed above. |
| It may be outdated, refer to f18 code base for the actual support status. |
| |
| ### Semantic Analysis |
| F18 semantic expression analysis phase detects intrinsic procedure references, |
| validates the argument types and deduces the return types. |
| This phase currently supports all the intrinsic procedures listed above but the ones in the table below. |
| |
| | Intrinsic Category | Intrinsic Procedures Lacking Support | |
| | --- | --- | |
| | Coarray intrinsic functions | COSHAPE | |
| | Object characteristic inquiry functions | ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, IS_CONTIGUOUS, PRESENT, RANK, SAME_TYPE, STORAGE_SIZE | |
| | Type inquiry intrinsic functions | BIT_SIZE, DIGITS, EPSILON, HUGE, KIND, MAXEXPONENT, MINEXPONENT, NEW_LINE, PRECISION, RADIX, RANGE, TINY| |
| | Non-standard intrinsic functions | AND, OR, XOR, SHIFT, ZEXT, IZEXT, COSD, SIND, TAND, ACOSD, ASIND, ATAND, ATAN2D, COMPL, EQV, NEQV, INT8, JINT, JNINT, KNINT, QCMPLX, DREAL, DFLOAT, QEXT, QFLOAT, QREAL, DNUM, NUM, JNUM, KNUM, QNUM, RNUM, RAN, RANF, ILEN, SIZEOF, MCLOCK, SECNDS, COTAN, IBCHNG, ISHA, ISHC, ISHL, IXOR, IARG, IARGC, NARGS, GETPID, NUMARG, BADDRESS, IADDR, CACHESIZE, EOF, FP_CLASS, INT_PTR_KIND, ISNAN, MALLOC, FREE, GETUID, GETGID | |
| | Intrinsic subroutines |MVBITS (elemental), CHDIR, CPU_TIME, DATE_AND_TIME, EVENT_QUERY, EXECUTE_COMMAND_LINE, GET_COMMAND, GET_COMMAND_ARGUMENT, GET_ENVIRONMENT_VARIABLE, MOVE_ALLOC, RANDOM_INIT, RANDOM_NUMBER, RANDOM_SEED, SIGNAL, SLEEP, SYSTEM, SYSTEM_CLOCK | |
| | Atomic intrinsic subroutines | ATOMIC_ADD | |
| | Collective intrinsic subroutines | CO_REDUCE | |
| | Library subroutines | BACKTRACE, FDATE, GETLOG, GETENV | |
| |
| |
| ### Intrinsic Function Folding |
| Fortran Constant Expressions can contain references to a certain number of |
| intrinsic functions (see Fortran 2018 standard section 10.1.12 for more details). |
| Constant Expressions may be used to define kind arguments. Therefore, the semantic |
| expression analysis phase must be able to fold references to intrinsic functions |
| listed in section 10.1.12. |
| |
| F18 intrinsic function folding is either performed by implementations directly |
| operating on f18 scalar types or by using host runtime functions and |
| host hardware types. F18 supports folding elemental intrinsic functions over |
| arrays when an implementation is provided for the scalars (regardless of whether |
| it is using host hardware types or not). |
| The status of intrinsic function folding support is given in the sub-sections below. |
| |
| #### Intrinsic Functions with Host Independent Folding Support |
| Implementations using f18 scalar types enables folding intrinsic functions |
| on any host and with any possible type kind supported by f18. The intrinsic functions |
| listed below are folded using host independent implementations. |
| |
| | Return Type | Intrinsic Functions with Host Independent Folding Support| |
| | --- | --- | |
| | INTEGER| ABS(INTEGER(k)), DIM(INTEGER(k), INTEGER(k)), DSHIFTL, DSHIFTR, IAND, IBCLR, IBSET, IEOR, INT, IOR, ISHFT, KIND, LEN, LEADZ, MASKL, MASKR, MERGE_BITS, POPCNT, POPPAR, SHIFTA, SHIFTL, SHIFTR, TRAILZ | |
| | REAL | ABS(REAL(k)), ABS(COMPLEX(k)), AIMAG, AINT, DPROD, REAL | |
| | COMPLEX | CMPLX, CONJG | |
| | LOGICAL | BGE, BGT, BLE, BLT | |
| |
| #### Intrinsic Functions with Host Dependent Folding Support |
| Implementations using the host runtime may not be available for all supported |
| f18 types depending on the host hardware types and the libraries available on the host. |
| The actual support on a host depends on what the host hardware types are. |
| The list below gives the functions that are folded using host runtime and the related C/C++ types. |
| F18 automatically detects if these types match an f18 scalar type. If so, |
| folding of the intrinsic functions will be possible for the related f18 scalar type, |
| otherwise an error message will be produced by f18 when attempting to fold related intrinsic functions. |
| |
| | C/C++ Host Type | Intrinsic Functions with Host Standard C++ Library Based Folding Support | |
| | --- | --- | |
| | float, double and long double | ACOS, ACOSH, ASINH, ATAN, ATAN2, ATANH, COS, COSH, DERF, DERFC, ERF, ERFC, EXP, GAMMA, HYPOT, LOG, LOG10, LOG_GAMMA, MOD, QERF, QERFC, SIN, SQRT, SINH, SQRT, TAN, TANH | |
| | std::complex for float, double and long double| ACOS, ACOSH, ASIN, ASINH, ATAN, ATANH, COS, COSH, EXP, LOG, SIN, SINH, SQRT, TAN, TANH | |
| |
| On top of the default usage of C++ standard library functions for folding described |
| in the table above, it is possible to compile f18 evaluate library with |
| [libpgmath](https://github.com/flang-compiler/flang/tree/master/runtime/libpgmath) |
| so that it can be used for folding. To do so, one must have a compiled version |
| of the libpgmath library available on the host and add |
| `-DLIBPGMATH_DIR=<path to the compiled shared libpgmath library>` to the f18 cmake command. |
| |
| Libpgmath comes with real and complex functions that replace C++ standard library |
| float and double functions to fold all the intrinsic functions listed in the table above. |
| It has no long double versions. If the host long double matches an f18 scalar type, |
| C++ standard library functions will still be used for folding expressions with this scalar type. |
| Libpgmath adds the possibility to fold the following functions for f18 real scalar |
| types related to host float and double types. |
| |
| | C/C++ Host Type | Additional Intrinsic Function Folding Support with Libpgmath (Optional) | |
| | --- | --- | |
| |float and double| BESSEL_J0, BESSEL_J1, BESSEL_JN (elemental only), BESSEL_Y0, BESSEL_Y1, BESSEL_Yn (elemental only), DERFC_SCALED, ERFC_SCALED, QERFC_SCALED | |
| |
| Libpgmath comes in three variants (precise, relaxed and fast). So far, only the |
| precise version is used for intrinsic function folding in f18. It guarantees the greatest numerical precision. |
| |
| ### Intrinsic Functions with Missing Folding Support |
| The following intrinsic functions are allowed in constant expressions but f18 |
| is not yet able to fold them. Note that there might be constraints on the arguments |
| so that these intrinsics can be used in constant expressions (see section 10.1.12 of Fortran 2018 standard). |
| |
| ALL, ACHAR, ADJUSTL, ADJUSTR, ANINT, ANY, BESSEL_JN (transformational only), |
| BESSEL_YN (transformational only), BTEST, CEILING, CHAR, COUNT, CSHIFT, DOT_PRODUCT, |
| DIM (REAL only), DOT_PRODUCT, EOSHIFT, FINDLOC, FLOOR, FRACTION, HUGE, IACHAR, IALL, |
| IANY, IPARITY, IBITS, ICHAR, IMAGE_STATUS, INDEX, ISHFTC, IS_IOSTAT_END, |
| IS_IOSTAT_EOR, LBOUND, LEN_TRIM, LGE, LGT, LLE, LLT, LOGICAL, MATMUL, MAX, MAXLOC, |
| MAXVAL, MERGE, MIN, MINLOC, MINVAL, MOD (INTEGER only), MODULO, NEAREST, NINT, |
| NORM2, NOT, OUT_OF_RANGE, PACK, PARITY, PRODUCT, REPEAT, REDUCE, RESHAPE, |
| RRSPACING, SCAN, SCALE, SELECTED_CHAR_KIND, SELECTED_INT_KIND, SELECTED_REAL_KIND, |
| SET_EXPONENT, SHAPE, SIGN, SIZE, SPACING, SPREAD, SUM, TINY, TRANSFER, TRANSPOSE, |
| TRIM, UBOUND, UNPACK, VERIFY. |
| |
| Coarray, non standard, IEEE and ISO_C_BINDINGS intrinsic functions that can be |
| used in constant expressions have currently no folding support at all. |
| |
| ### Standard Intrinsics: EXECUTE_COMMAND_LINE |
| |
| #### Usage and Info |
| |
| - **Standard:** Fortran 2008 and later, specified in subclause 16.9.73 |
| - **Class:** Subroutine |
| - **Syntax:** `CALL EXECUTE_COMMAND_LINE(COMMAND [, WAIT, EXITSTAT, CMDSTAT, CMDMSG ])` |
| - **Arguments:** |
| |
| | Argument | Description | |
| |------------|-----------------------------------------------------------------------| |
| | `COMMAND` | Shall be a default CHARACTER scalar. | |
| | `WAIT` | (Optional) Shall be a default LOGICAL scalar. | |
| | `EXITSTAT` | (Optional) Shall be an INTEGER with kind greater than or equal to 4. | |
| | `CMDSTAT` | (Optional) Shall be an INTEGER with kind greater than or equal to 2. | |
| | `CMDMSG` | (Optional) Shall be a CHARACTER scalar of the default kind. | |
| |
| #### Implementation Specifics |
| |
| ##### `COMMAND`: |
| |
| - Must be preset. |
| |
| ##### `WAIT`: |
| |
| - If set to `false`, the command is executed asynchronously. |
| - If not preset or set to `true`, it is executed synchronously. |
| - Synchronous execution is achieved by passing the command into `std::system` on all systems. |
| - Asynchronous execution is achieved by calling `fork()` on POSIX-compatible systems or `CreateProcess()` on Windows. |
| |
| ##### `EXITSTAT`: |
| |
| - Synchronous execution: |
| - Inferred by the return value of `std::system(cmd)`. |
| - On POSIX-compatible systems: return value is first passed into `WEXITSTATUS(status)`, then assigned to `EXITSTAT`. |
| - On Windows, the value is directly assigned as the return value of `std::system()`. |
| - Asynchronous execution: |
| - Value is not modified. |
| |
| ##### `CMDSTAT`: |
| |
| - Synchronous execution: |
| - -2: `ASYNC_NO_SUPPORT_ERR` - No error condition occurs, but `WAIT` is present with the value `false`, and the processor does not support asynchronous execution. |
| - -1: `NO_SUPPORT_ERR` - The processor does not support command line execution. (system returns -1 with errno `ENOENT`) |
| - 0: `CMD_EXECUTED` - Command executed with no error. |
| - \+ (positive value): An error condition occurs. |
| - 1: `FORK_ERR` - Fork Error (occurs only on POSIX-compatible systems). |
| - 2: `EXECL_ERR` - Execution Error (system returns -1 with other errno). |
| - 3: `COMMAND_EXECUTION_ERR` - Invalid Command Error (exit code 1). |
| - 4: `COMMAND_CANNOT_EXECUTE_ERR` - Command Cannot Execute Error (Linux exit code 126). |
| - 5: `COMMAND_NOT_FOUND_ERR` - Command Not Found Error (Linux exit code 127). |
| - 6: `INVALID_CL_ERR` - Invalid Command Line Error (covers all other non-zero exit codes). |
| - 7: `SIGNAL_ERR` - Signal error (either stopped or killed by signal, occurs only on POSIX-compatible systems). |
| - Asynchronous execution: |
| - 0 will always be assigned. |
| |
| ##### `CMDMSG`: |
| |
| - Synchronous execution: |
| - If an error condition occurs, it is assigned an explanatory message; otherwise, it remains unchanged. |
| - If a condition occurs that would assign a nonzero value to `CMDSTAT` but the `CMDSTAT` variable is not present, error termination is initiated (applies to both POSIX-compatible systems and Windows). |
| - Asynchronous execution: |
| - The value is unchanged. |
| - If a condition occurs that would assign a nonzero value to `CMDSTAT` but the `CMDSTAT` variable is not present, error termination is initiated. |
| - On POSIX-compatible systems, the child process (async process) will be terminated with no effect on the parent process (continues). |
| - On Windows, error termination is not initiated. |
| |
| ### Non-Standard Intrinsics: ETIME |
| |
| #### Description |
| `ETIME(VALUES, TIME)` returns the number of seconds of runtime since the start of the process’s execution in *TIME*. *VALUES* returns the user and system components of this time in `VALUES(1)` and `VALUES(2)` respectively. *TIME* is equal to `VALUES(1) + VALUES(2)`. |
| |
| On some systems, the underlying timings are represented using types with sufficiently small limits that overflows (wrap around) are possible, such as 32-bit types. Therefore, the values returned by this intrinsic might be, or become, negative, or numerically less than previous values, during a single run of the compiled program. |
| |
| This intrinsic is provided in both subroutine and function forms; however, only one form can be used in any given program unit. |
| |
| *VALUES* and *TIME* are `INTENT(OUT)` and provide the following: |
| |
| |
| | | | |
| |---------------|-----------------------------------| |
| | `VALUES(1)` | User time in seconds. | |
| | `VALUES(2)` | System time in seconds. | |
| | `TIME` | Run time since start in seconds. | |
| |
| #### Usage and Info |
| |
| - **Standard:** GNU extension |
| - **Class:** Subroutine, function |
| - **Syntax:** `CALL ETIME(VALUES, TIME)` |
| - **Arguments:** |
| - **Return value** Elapsed time in seconds since the start of program execution. |
| |
| | Argument | Description | |
| |------------|-----------------------------------------------------------------------| |
| | `VALUES` | The type shall be REAL(4), DIMENSION(2). | |
| | `TIME` | The type shall be REAL(4). | |
| |
| #### Example |
| Here is an example usage from [Gfortran ETIME](https://gcc.gnu.org/onlinedocs/gfortran/ETIME.html) |
| ```Fortran |
| program test_etime |
| integer(8) :: i, j |
| real, dimension(2) :: tarray |
| real :: result |
| call ETIME(tarray, result) |
| print *, result |
| print *, tarray(1) |
| print *, tarray(2) |
| do i=1,100000000 ! Just a delay |
| j = i * i - i |
| end do |
| call ETIME(tarray, result) |
| print *, result |
| print *, tarray(1) |
| print *, tarray(2) |
| end program test_etime |
| ``` |
| |
| ### Non-Standard Intrinsics: GETCWD |
| |
| #### Description |
| `GETCWD(C, STATUS)` returns current working directory. |
| |
| This intrinsic is provided in both subroutine and function forms; however, only one form can be used in any given program unit. |
| |
| *C* and *STATUS* are `INTENT(OUT)` and provide the following: |
| |
| | | | |
| |------------|---------------------------------------------------------------------------------------------------| |
| | `C` | Current work directory. The type shall be `CHARACTER` and of default kind. | |
| | `STATUS` | (Optional) Status flag. Returns 0 on success, a system specific and nonzero error code otherwise. The type shall be `INTEGER` and of a kind greater or equal to 4. | |
| |
| #### Usage and Info |
| |
| - **Standard:** GNU extension |
| - **Class:** Subroutine, function |
| - **Syntax:** `CALL GETCWD(C, STATUS)`, `STATUS = GETCWD(C)` |
| |
| #### Example |
| ```Fortran |
| PROGRAM example_getcwd |
| CHARACTER(len=255) :: cwd |
| INTEGER :: status |
| CALL getcwd(cwd, status) |
| PRINT *, cwd |
| PRINT *, status |
| END PROGRAM |
| ``` |
| |
| ### Non-Standard Intrinsics: HOSTNM |
| |
| #### Description |
| `HOSTNM(C, STATUS)` returns the host name of the system. |
| |
| This intrinsic is provided in both subroutine and function forms; however, only one form can be used in any given program unit. |
| |
| *C* and *STATUS* are `INTENT(OUT)` and provide the following: |
| |
| | | | |
| |------------|---------------------------------------------------------------------------------------------------| |
| | `C` | The host name of the system. The type shall be `CHARACTER` and of default kind. | |
| | `STATUS` | (Optional) Status flag. Returns 0 on success, a system specific and nonzero error code otherwise. The type shall be `INTEGER` and of a kind greater or equal to 4. | |
| |
| #### Usage and Info |
| |
| - **Standard:** GNU extension |
| - **Class:** Subroutine, function |
| - **Syntax:** `CALL HOSTNM(C, STATUS)`, `STATUS = HOSTNM(C)` |
| |
| #### Example |
| ```Fortran |
| PROGRAM example_hostnm |
| CHARACTER(len=255) :: hnam |
| INTEGER :: status |
| CALL hostnm(hnam, status) |
| PRINT *, hnam |
| PRINT *, status |
| END PROGRAM |
| ``` |
| |
| |
| ### Non-standard Intrinsics: RENAME |
| `RENAME(OLD, NEW[, STATUS])` renames/moves a file on the filesystem. |
| |
| This intrinsic is provided in both subroutine and function form; however, only one form can be used in any given program unit. |
| |
| #### Usage and Info |
| |
| - **Standard:** GNU extension |
| - **Class:** Subroutine, function |
| - **Syntax:** `CALL RENAME(SRC, DST[, STATUS])` |
| - **Arguments:** |
| - **Return value** status code (0: success, non-zero for errors) |
| |
| | Argument | Description | |
| |----------|-----------------------------------| |
| | `SRC` | Source path | |
| | `DST` | Destination path | |
| | `STATUS` | Status code (for subroutine form) | |
| |
| The status code returned by both the subroutine and function form corresponds to the value of `errno` if the invocation of `rename(2)` was not successful. |
| |
| #### Example |
| |
| Function form: |
| ``` |
| program rename_func |
| implicit none |
| integer :: status |
| status = rename('src', 'dst') |
| print *, 'status:', status |
| status = rename('dst', 'src') |
| print *, 'status:', status |
| end program rename_func |
| ``` |
| |
| Subroutine form: |
| ``` |
| program rename_proc |
| implicit none |
| integer :: status |
| call rename('src', 'dst', status) |
| print *, 'status:', status |
| call rename('dst', 'src') |
| end program rename_proc |
| ``` |
| |
| ### Non-standard Intrinsics: SECOND |
| This intrinsic is an alias for `CPU_TIME`: supporting both a subroutine and a |
| function form. |
| |
| ### Non-standard Intrinsics: LNBLNK |
| This intrinsic is an alias for `LEN_TRIM`, without the optional KIND argument. |
| |
| #### Usage and Info |
| |
| - **Standard:** GNU extension |
| - **Class:** Subroutine, function |
| - **Syntax:** `CALL SECOND(TIME)` or `TIME = SECOND()` |
| - **Arguments:** `TIME` - a REAL value into which the elapsed CPU time in |
| seconds is written |
| - **RETURN value:** same as TIME argument |
| |
| ### Non-Standard Intrinsics: CHDIR |
| |
| #### Description |
| `CHDIR(NAME[, STATUS])` Change current working directory to a specified path. |
| |
| This intrinsic is provided in both subroutine and function forms; however, only one form can be used in any given program unit. |
| *STATUS* is `INTENT(OUT)` and provide the following: |
| |
| | | | |
| |------------|---------------------------------------------------------------------------------------------------| |
| | `NAME` | The type shall be `CHARACTER` of default kind and shall specify a valid path within the file system. | |
| | `STATUS` | (Optional) Status flag. Returns 0 on success, a system specific and nonzero error code otherwise. The type shall be `INTEGER` and of the default kind. | |
| |
| #### Usage and Info |
| |
| - **Standard:** GNU extension |
| - **Class:** Subroutine, function |
| - **Syntax:** `CALL CHDIR(NAME[, STATUS])` and `STATUS = CHDIR(NAME)` |
| |
| #### Example |
| ```Fortran |
| program chdir_func |
| character(len=) :: path |
| integer :: status |
| |
| call chdir("/tmp") |
| status = chdir("..") |
| print *, "status: ", status |
| end program chdir_func |
| ``` |
| |
| ### Non-Standard Intrinsics: IERRNO |
| |
| #### Description |
| `IERRNO()` returns the last system error number, as given by the C `errno` variable. |
| |
| #### Usage and Info |
| |
| - **Standard:** GNU extension |
| - **Class:** function |
| - **Syntax:** `RESULT = IERRNO()` |
| |
| ### Non-Standard Intrinsics: QSORT |
| |
| #### Description |
| |
| ``` |
| SUBROUTINE QSORT(ARRAY, LEN, ISIZE, COMPAR) |
| TYPE(*) :: ARRAY(*) |
| INTEGER(4) :: LEN, ISIZE |
| INTERFACE |
| INTEGER(4) FUNCTION COMPAR(A, B) |
| TYPE(*) :: A, B |
| END FUNCTION |
| END INTERFACE |
| END SUBROUTINE |
| ``` |
| |
| Sort `ARRAY` in place in ascending order given the comparison function `COMPAR`. |
| The array number of elements is given by `LEN` and the element byte size is given |
| by `ISIZE`. |
| |
| `COMPAR` function takes the addresses of element `A` and `B` and must return: |
| - a negative value if `A` < `B` |
| - zero if `A` == `B` |
| - a positive value otherwise. |
| |
| #### Usage and Info |
| |
| - **Standard:** lib3f (section 3f of old man pages). |
| - **Class:** subroutine |
| - **Syntax:** `CALL QSORT(ARRAY, LEN, ISIZE, COMPAR)` |
| |
| ### Non-Standard Intrinsics: PERROR |
| |
| #### Description |
| `PERROR(STRING)` prints (on the C stderr stream) a newline-terminated error message corresponding to the last system error. |
| This is prefixed by `STRING`, a colon and a space. |
| |
| #### Usage and Info |
| |
| - **Standard:** GNU extension |
| - **Class:** subroutine |
| - **Syntax:** `CALL PERROR(STRING)` |