[flang-commits] [flang] [flang] Classify intrinsic functions as SIMPLE (PR #223160)
via flang-commits
flang-commits at lists.llvm.org
Sat Sep 12 09:03:26 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-semantics
Author: Šárka Holendová (mlir-maiden)
<details>
<summary>Changes</summary>
Classify standard intrinsic functions as SIMPLE per Fortran 2023 16.1(2).
This change also:
- Classifies extensions as SIMPLE where applicable
- Documents the SIMPLE and non-SIMPLE classifications of extensions in Extensions.md
- Updates procedure-interface tests affected by the new SIMPLE classification
- Updates F202X.md to reflect the current SIMPLE implementation status
Part of the SIMPLE procedure support tracked in #<!-- -->221457.
@<!-- -->eugeneepshteyn
@<!-- -->cenewcombe
---
Full diff: https://github.com/llvm/llvm-project/pull/223160.diff
7 Files Affected:
- (modified) flang/docs/Extensions.md (+10)
- (modified) flang/docs/F202X.md (+8-2)
- (modified) flang/lib/Evaluate/intrinsics.cpp (+19-3)
- (modified) flang/test/Semantics/intrinsics03.f90 (+4-4)
- (modified) flang/test/Semantics/procinterface01.f90 (+2-2)
- (modified) flang/test/Semantics/procinterface02.f90 (+3-3)
- (added) flang/test/Semantics/simple-intrinsic-functions.f90 (+18)
``````````diff
diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md
index 0b16348074cfc..a9b1c66c6d1a3 100644
--- a/flang/docs/Extensions.md
+++ b/flang/docs/Extensions.md
@@ -570,6 +570,16 @@ end program
rather than an allocatable, it is interpreted as `ASSOCIATED(p)` with a
stern warning.
+### `SIMPLE` classification of extensions
+
+The following extensions are `SIMPLE`: `IARGC`, `INT2`, `INT8`, `INT_PTR_KIND`, `ISNAN`,
+`IZEXT`, `JZEXT`, `LNBLNK`, `LOC`, `SELECTED_UNSIGNED_KIND`, `SIZEOF`, `UINT`, `UMASKL`,
+and `UMASKR`. All specific intrinsic extensions are also `SIMPLE`.
+
+The following extensions are not classified as `SIMPLE`: `CHDIR`, `DSECNDS`, `ETIME`,
+`FSEEK`, `FTELL`, `GETCWD`, `GETGID`, `GETPID`, `GETUID`, `HOSTNM`, `IRAND`, `MALLOC`,
+`PUTENV`, `RAND`, `RENAME`, `RTC`, `SECNDS`, `SECOND`, `SYSTEM`, `TIME`, `TIMEF`, and `UNLINK`.
+
### Extensions supported when enabled by options
* C-style backslash escape sequences in quoted CHARACTER literals
diff --git a/flang/docs/F202X.md b/flang/docs/F202X.md
index 7d0cf26dbaa2c..b9ef4187518c4 100644
--- a/flang/docs/F202X.md
+++ b/flang/docs/F202X.md
@@ -175,8 +175,14 @@ This makes `SIMPLE` a lower-priority feature.
- `PURE` procedures do not satisfy `SIMPLE` requirements
- `SIMPLE`/`IMPURE` conflicts are diagnosed
- Use-associated `SIMPLE` procedures are correctly recognized
-- Additional `SIMPLE` semantic constraints remain to be implemented
-- Intrinsic procedures are not yet marked as `SIMPLE` (planned as follow-up work)
+- Additional `SIMPLE` semantic constraints remain to be implemented (see #221457)
+- F2023 16.1(2): All standard intrinsic functions are classified as `SIMPLE`
+- F2023 16.1(5): `MVBITS`, `SPLIT`, and both forms of `TOKENIZE` are classified
+ as `SIMPLE` intrinsic subroutines
+- F2023 16.1(5): Conditional `SIMPLE` classification of `MOVE_ALLOC` is not yet
+ implemented (planned as follow-up work)
+- Intrinsic module procedures are not yet classified as `SIMPLE`
+- Lowering does not yet propagate the `SIMPLE` attribute to FIR procedure attributes (see #222360)
#### Conditional expressions and actual arguments
diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index abfb48e5ad82b..7c543e6dc0309 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -19,6 +19,7 @@
#include "flang/Semantics/scope.h"
#include "flang/Semantics/tools.h"
#include "flang/Support/Fortran.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <climits>
@@ -1157,6 +1158,14 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"__builtin_numeric_storage_size", {}, DefaultInt},
};
+// Extensions that are not SIMPLE: they have side
+// effects, or their result varies with external state (clock, RNG, file,
+// process/user/group identity). See docs/Extensions.md.
+static const llvm::StringSet<> notSimpleExtensionFunctions{"chdir", "dsecnds",
+ "etime", "fseek", "ftell", "getcwd", "getgid", "getpid", "getuid", "hostnm",
+ "irand", "malloc", "putenv", "rand", "rename", "rtc", "secnds", "second",
+ "system", "time", "timef", "unlink"};
+
// TODO: Non-standard intrinsic functions
// SHIFT,
// COMPL, EQV, NEQV, INT8, JINT, JNINT, KNINT,
@@ -2889,9 +2898,14 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
name, characteristics::Procedure{std::move(dummyArgs), attrs}},
std::move(rearranged)};
} else {
- // TODO: Mark intrinsic functions that are SIMPLE per F2023
- if (intrinsicClass != IntrinsicClass::impureFunction /* RAND and IRAND */)
+ if (intrinsicClass != IntrinsicClass::impureFunction /* RAND and IRAND */) {
attrs.set(characteristics::Procedure::Attr::Pure);
+ // F2023 16.1: standard intrinsic functions are SIMPLE. The extensions in
+ // notSimpleExtensionFunctions are excluded because they are not SIMPLE.
+ if (!notSimpleExtensionFunctions.contains(name)) {
+ attrs.set(characteristics::Procedure::Attr::Simple);
+ }
+ }
characteristics::TypeAndShape typeAndShape{resultType.value(), resultRank};
characteristics::FunctionResult funcResult{std::move(typeAndShape)};
characteristics::Procedure chars{
@@ -4129,7 +4143,9 @@ IntrinsicProcTable::Implementation::IsSpecificIntrinsicFunction(
std::string{specific.dummy[j].keyword}, std::move(dummy));
}
characteristics::Procedure::Attrs attrs;
- attrs.set(characteristics::Procedure::Attr::Pure)
+ // F2023 16.1: specific intrinsic functions are SIMPLE
+ attrs.set(characteristics::Procedure::Attr::Simple)
+ .set(characteristics::Procedure::Attr::Pure)
.set(characteristics::Procedure::Attr::Elemental);
characteristics::Procedure chars{
std::move(fResult), std::move(args), attrs};
diff --git a/flang/test/Semantics/intrinsics03.f90 b/flang/test/Semantics/intrinsics03.f90
index 1a4269868a3d4..801d44a0e97ec 100644
--- a/flang/test/Semantics/intrinsics03.f90
+++ b/flang/test/Semantics/intrinsics03.f90
@@ -3,16 +3,16 @@
program test
interface
- pure integer function index1(string, substring)
+ simple integer function index1(string, substring)
character(*), intent(in) :: string, substring ! ok
end
- pure integer function index2(x1, x2)
+ simple integer function index2(x1, x2)
character(*), intent(in) :: x1, x2 ! ok
end
- pure integer function index3(string, substring)
+ simple integer function index3(string, substring)
character, intent(in) :: string, substring ! not assumed length
end
- pure integer function index4(string, substring, back)
+ simple integer function index4(string, substring, back)
character(*), intent(in) :: string, substring
logical, optional, intent(in) :: back ! not ok
end
diff --git a/flang/test/Semantics/procinterface01.f90 b/flang/test/Semantics/procinterface01.f90
index 70f4a889d6809..fecbf593ab6d8 100644
--- a/flang/test/Semantics/procinterface01.f90
+++ b/flang/test/Semantics/procinterface01.f90
@@ -48,7 +48,7 @@ end function tan
type :: derived1
!REF: /module1/abstract1
!DEF: /module1/derived1/p1 NOPASS, POINTER (Function) ProcEntity REAL(4)
- !DEF: /module1/nested1 PUBLIC, PURE (Function) Subprogram REAL(4)
+ !DEF: /module1/nested1 PUBLIC, SIMPLE (Function) Subprogram REAL(4)
procedure(abstract1), pointer, nopass :: p1 => nested1
!REF: /module1/explicit1
!DEF: /module1/derived1/p2 NOPASS, POINTER (Function) ProcEntity REAL(4)
@@ -81,7 +81,7 @@ end function tan
!REF: /module1/nested1
!DEF: /module1/nested1/x INTENT(IN) ObjectEntity REAL(4)
- pure real function nested1(x)
+ simple real function nested1(x)
!REF: /module1/nested1/x
real, intent(in) :: x
!DEF: /module1/nested1/nested1 ObjectEntity REAL(4)
diff --git a/flang/test/Semantics/procinterface02.f90 b/flang/test/Semantics/procinterface02.f90
index 6aa5dc13bd9a5..2acfb8ea8a836 100644
--- a/flang/test/Semantics/procinterface02.f90
+++ b/flang/test/Semantics/procinterface02.f90
@@ -1,10 +1,10 @@
! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic
subroutine foo(A, B, P)
interface
- real elemental function foo_elemental(x)
+ simple elemental real function foo_elemental(x)
real, intent(in) :: x
end function
- pure real function foo_pure(x)
+ simple real function foo_simple(x)
real, intent(in) :: x
end function
real function foo_nonelemental(x)
@@ -18,7 +18,7 @@ real function foo_nonelemental(x)
A = P(B)
!ERROR: Procedure pointer 'p' associated with incompatible procedure designator 'foo_elemental': incompatible procedure attributes: Elemental
P => foo_elemental
- P => foo_pure ! ok
+ P => foo_simple ! ok
!ERROR: PURE procedure pointer 'p' may not be associated with non-PURE procedure designator 'foo_nonelemental'
P => foo_nonelemental
end subroutine
diff --git a/flang/test/Semantics/simple-intrinsic-functions.f90 b/flang/test/Semantics/simple-intrinsic-functions.f90
new file mode 100644
index 0000000000000..85564501b57b9
--- /dev/null
+++ b/flang/test/Semantics/simple-intrinsic-functions.f90
@@ -0,0 +1,18 @@
+! Test that intrinsic functions are classified SIMPLE (F2023 16.1)
+! RUN: %flang_fc1 -fsyntax-only %s
+
+! An intrinsic function is SIMPLE and can target a SIMPLE procedure pointer
+module simple_intrinsic_function
+ implicit none
+ abstract interface
+ simple real function ifc(x)
+ real, intent(in) :: x
+ end function
+ end interface
+contains
+ subroutine test()
+ procedure(ifc), pointer :: sp
+ intrinsic :: sin
+ sp => sin
+ end subroutine
+end module
``````````
</details>
https://github.com/llvm/llvm-project/pull/223160
More information about the flang-commits
mailing list