-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[flang][runtime] Implement SLEEP intrinsic #79074
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-flang-fir-hlfir @llvm/pr-subscribers-flang-semantics Author: Tom Eccles (tblah) ChangesThis intrinsic is a gnu extension. See This intrinsic is used in minighost: https://github.com/Mantevo/miniGhost/blob/c2102b521568a74862fa5abb074b1fc8041fc222/ref/MG_UTILS.F#L606 Full diff: https://github.com/llvm/llvm-project/pull/79074.diff 9 Files Affected:
diff --git a/flang/docs/Intrinsics.md b/flang/docs/Intrinsics.md
index 5ade25740329771..a3888111430a0e2 100644
--- a/flang/docs/Intrinsics.md
+++ b/flang/docs/Intrinsics.md
@@ -757,7 +757,7 @@ This phase currently supports all the intrinsic procedures listed above but the
| 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 |
-| Intrinsic subroutines |MVBITS (elemental), 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, SYSTEM_CLOCK |
+| Intrinsic subroutines |MVBITS (elemental), 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, SLEEP, SYSTEM_CLOCK |
| Atomic intrinsic subroutines | ATOMIC_ADD |
| Collective intrinsic subroutines | CO_REDUCE |
| Library subroutines | FDATE, GETLOG |
@@ -908,4 +908,3 @@ used in constant expressions have currently no folding support at all.
- 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.
-
diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
index 80f79d42fc2b75c..275878a0b2ad174 100644
--- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
+++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
@@ -339,6 +339,7 @@ struct IntrinsicLibrary {
fir::ExtendedValue genStorageSize(mlir::Type,
llvm::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genSum(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+ void genSleep(llvm::ArrayRef<fir::ExtendedValue>);
void genSystemClock(llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genTand(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genTrailz(mlir::Type, llvm::ArrayRef<mlir::Value>);
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h b/flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h
index 9a37c15e9fb4ce2..a92e03afa60d778 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h
@@ -64,6 +64,10 @@ void genTransferSize(fir::FirOpBuilder &builder, mlir::Location loc,
/// all intrinsic arguments are optional and may appear here as mlir::Value{}
void genSystemClock(fir::FirOpBuilder &, mlir::Location, mlir::Value count,
mlir::Value rate, mlir::Value max);
+
+/// generate sleep runtime call
+void genSleep(fir::FirOpBuilder &builder, mlir::Location loc,
+ mlir::Value seconds);
} // namespace runtime
} // namespace fir
diff --git a/flang/include/flang/Runtime/extensions.h b/flang/include/flang/Runtime/extensions.h
index 1ed750f3b70e0f3..515e9eb3e7b5e1d 100644
--- a/flang/include/flang/Runtime/extensions.h
+++ b/flang/include/flang/Runtime/extensions.h
@@ -12,6 +12,8 @@
#ifndef FORTRAN_RUNTIME_EXTENSIONS_H_
#define FORTRAN_RUNTIME_EXTENSIONS_H_
+#include "flang/Runtime/entry-names.h"
+
#define FORTRAN_PROCEDURE_NAME(name) name##_
#include <cstddef>
@@ -35,5 +37,8 @@ void FORTRAN_PROCEDURE_NAME(getarg)(
// GNU extension subroutine GETLOG(C).
void FORTRAN_PROCEDURE_NAME(getlog)(char *name, std::int64_t length);
+// GNU extension subroutine SLEEP(SECONDS)
+void RTNAME(Sleep)(std::int64_t seconds);
+
} // extern "C"
#endif // FORTRAN_RUNTIME_EXTENSIONS_H_
diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index da6d5970089884c..3c912b01906d7cc 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -1395,6 +1395,10 @@ static const IntrinsicInterface intrinsicSubroutine[]{
{"count_max", AnyInt, Rank::scalar, Optionality::optional,
common::Intent::Out}},
{}, Rank::elemental, IntrinsicClass::impureSubroutine},
+ {"sleep",
+ {{"seconds", AnyInt, Rank::scalar, Optionality::required,
+ common::Intent::In}},
+ {}, Rank::elemental, IntrinsicClass::impureSubroutine},
};
// TODO: Intrinsic subroutine EVENT_QUERY
@@ -1412,8 +1416,8 @@ static DynamicType GetBuiltinDerivedType(
auto iter{
builtinsScope->find(semantics::SourceName{which, std::strlen(which)})};
if (iter == builtinsScope->cend()) {
- common::die(
- "INTERNAL: The __fortran_builtins module does not define the type '%s'",
+ common::die("INTERNAL: The __fortran_builtins module does not define the "
+ "type '%s'",
which);
}
const semantics::Symbol &symbol{*iter->second};
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index ac7d4fbe23e6738..b125258fa017db7 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -556,6 +556,7 @@ static constexpr IntrinsicHandler handlers[]{
{"dim", asAddr, handleDynamicOptional},
{"kind", asValue}}},
/*isElemental=*/false},
+ {"sleep", &I::genSleep, {{{"seconds", asValue}}}, /*isElemental=*/false},
{"spacing", &I::genSpacing},
{"spread",
&I::genSpread,
@@ -5924,6 +5925,12 @@ void IntrinsicLibrary::genSystemClock(llvm::ArrayRef<fir::ExtendedValue> args) {
fir::getBase(args[1]), fir::getBase(args[2]));
}
+// SLEEP
+void IntrinsicLibrary::genSleep(llvm::ArrayRef<fir::ExtendedValue> args) {
+ assert(args.size() == 1 && "SLEEP has one compulsory argument");
+ fir::runtime::genSleep(builder, loc, fir::getBase(args[0]));
+}
+
// TRANSFER
fir::ExtendedValue
IntrinsicLibrary::genTransfer(mlir::Type resultType,
diff --git a/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp b/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp
index 63d66adf222f640..9058ff6325b1229 100644
--- a/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp
+++ b/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp
@@ -12,6 +12,7 @@
#include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
#include "flang/Parser/parse-tree.h"
+#include "flang/Runtime/extensions.h"
#include "flang/Runtime/misc-intrinsic.h"
#include "flang/Runtime/pointer.h"
#include "flang/Runtime/random.h"
@@ -235,3 +236,12 @@ void fir::runtime::genSystemClock(fir::FirOpBuilder &builder,
if (max)
makeCall(getRuntimeFunc<mkRTKey(SystemClockCountMax)>(loc, builder), max);
}
+
+void fir::runtime::genSleep(fir::FirOpBuilder &builder, mlir::Location loc,
+ mlir::Value seconds) {
+ mlir::Type int64 = builder.getIntegerType(64);
+ seconds = builder.create<fir::ConvertOp>(loc, int64, seconds);
+ mlir::func::FuncOp func{
+ fir::runtime::getRuntimeFunc<mkRTKey(Sleep)>(loc, builder)};
+ builder.create<fir::CallOp>(loc, func, seconds);
+}
\ No newline at end of file
diff --git a/flang/runtime/extensions.cpp b/flang/runtime/extensions.cpp
index 2740c854b807818..42adc13ce532e45 100644
--- a/flang/runtime/extensions.cpp
+++ b/flang/runtime/extensions.cpp
@@ -14,6 +14,7 @@
#include "tools.h"
#include "flang/Runtime/command.h"
#include "flang/Runtime/descriptor.h"
+#include "flang/Runtime/entry-names.h"
#include "flang/Runtime/io-api.h"
#include <ctime>
@@ -39,8 +40,10 @@ inline void CtimeBuffer(char *buffer, size_t bufsize, const time_t cur_time,
#endif
#if _REENTRANT || _POSIX_C_SOURCE >= 199506L
-// System is posix-compliant and has getlogin_r
+// System is posix-compliant and has getlogin_r and sleep
#include <unistd.h>
+#elif _WIN32
+#include <windows.h> // for sleep
#endif
extern "C" {
@@ -113,5 +116,15 @@ void FORTRAN_PROCEDURE_NAME(getlog)(char *arg, std::int64_t length) {
#endif
}
+// CALL SLEEP(SECONDS)
+void RTNAME(Sleep)(std::int64_t seconds) {
+ // ensure that conversion to unsigned makes sense,
+ // sleep(0) is an immidiate return anyway
+ if (seconds < 1) {
+ return;
+ }
+ sleep(static_cast<unsigned>(seconds));
+}
+
} // namespace Fortran::runtime
} // extern "C"
diff --git a/flang/test/Lower/Intrinsics/sleep.f90 b/flang/test/Lower/Intrinsics/sleep.f90
new file mode 100644
index 000000000000000..c4a7b381602cadb
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/sleep.f90
@@ -0,0 +1,27 @@
+! RUN: bbc -emit-hlfir %s -o - | FileCheck %s
+
+subroutine test_sleep()
+! CHECK-LABEL: func.func @_QPtest_sleep() {
+
+ call sleep(1_2)
+! CHECK: %[[VAL_0:.*]] = arith.constant 1 : i16
+! CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (i16) -> i64
+! CHECK: %[[VAL_2:.*]] = fir.call @_FortranASleep(%[[VAL_1]]) fastmath<contract> : (i64) -> none
+
+ call sleep(1_4)
+! CHECK: %[[VAL_3:.*]] = arith.constant 1 : i32
+! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (i32) -> i64
+! CHECK: %[[VAL_5:.*]] = fir.call @_FortranASleep(%[[VAL_4]]) fastmath<contract> : (i64) -> none
+
+ call sleep(1_8)
+! CHECK: %[[VAL_6:.*]] = arith.constant 1 : i64
+! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i64) -> i64
+! CHECK: %[[VAL_8:.*]] = fir.call @_FortranASleep(%[[VAL_7]]) fastmath<contract> : (i64) -> none
+
+ call sleep(1_16)
+! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i128
+! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (i128) -> i64
+! CHECK: %[[VAL_11:.*]] = fir.call @_FortranASleep(%[[VAL_10]]) fastmath<contract> : (i64) -> none
+end
+! CHECK: return
+! CHECK: }
|
flang/lib/Evaluate/intrinsics.cpp
Outdated
@@ -1412,8 +1416,8 @@ static DynamicType GetBuiltinDerivedType( | |||
auto iter{ | |||
builtinsScope->find(semantics::SourceName{which, std::strlen(which)})}; | |||
if (iter == builtinsScope->cend()) { | |||
common::die( | |||
"INTERNAL: The __fortran_builtins module does not define the type '%s'", | |||
common::die("INTERNAL: The __fortran_builtins module does not define the " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please consider rejoining this message string, even if it's long -- split message strings can become impossible to find in the source.
flang/runtime/extensions.cpp
Outdated
#include <unistd.h> | ||
#elif _WIN32 | ||
#include <windows.h> // for sleep |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for implementing this!
Have you considered using std::this_thread::sleep_for
to avoid the need for Windows specific header file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would that result in a call to the c++ lib?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So far as I can tell, on my system (gnu libc++) std::this_thread_sleep_for
is header-only. However, I haven't found any documentation indicating whether this is a safe assumption on other systems.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated to use std::this_thread::sleep_for for windows compatiability. Fingers crossed I didn't just add a dependency on libc++ on some obscure target.
mlir::func::FuncOp func{ | ||
fir::runtime::getRuntimeFunc<mkRTKey(Sleep)>(loc, builder)}; | ||
builder.create<fir::CallOp>(loc, func, seconds); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: new line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change broke code formatting in CI so I reverted it
✅ With the latest revision this PR passed the C/C++ code formatter. |
This intrinsic is a gnu extension. See https://gcc.gnu.org/onlinedocs/gfortran/SLEEP.html
This reverts commit 24a9e4bbf5f562e83bfe07d8b6b304c74c77626e. This caused a CI failure in code formatting
2d86560
to
5a525b5
Compare
Windows CI ran out of memory. A local build + test worked so I will merge and leave this up to the postcommit windows CI |
This intrinsic is a gnu extension. See https://gcc.gnu.org/onlinedocs/gfortran/SLEEP.html This intrinsic is used in minighost: https://github.com/Mantevo/miniGhost/blob/c2102b521568a74862fa5abb074b1fc8041fc222/ref/MG_UTILS.F#L606
This intrinsic is a gnu extension. See
https://gcc.gnu.org/onlinedocs/gfortran/SLEEP.html
This intrinsic is used in minighost: https://github.com/Mantevo/miniGhost/blob/c2102b521568a74862fa5abb074b1fc8041fc222/ref/MG_UTILS.F#L606