-
Notifications
You must be signed in to change notification settings - Fork 11.9k
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
[flang] FDATE extension implementation: get date and time in ctime format #71222
Conversation
✅ With the latest revision this PR passed the C/C++ code formatter. |
reference to gfortran fdate https://gcc.gnu.org/onlinedocs/gfortran/FDATE.html usage: CHARACTER(32) :: time CALL fdate(time) WRITE(*,*) time
@llvm/pr-subscribers-flang-runtime Author: Yi Wu (PAX-12-WU) Changesreference to gfortran fdate https://gcc.gnu.org/onlinedocs/gfortran/FDATE.html CHARACTER(32) :: time
CALL fdate(time)
WRITE(*,*) time Full diff: https://github.com/llvm/llvm-project/pull/71222.diff 6 Files Affected:
diff --git a/flang/docs/Intrinsics.md b/flang/docs/Intrinsics.md
index ab0a940e53e5538..982be8208164296 100644
--- a/flang/docs/Intrinsics.md
+++ b/flang/docs/Intrinsics.md
@@ -751,7 +751,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, 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, FDATE, GET_COMMAND, GET_COMMAND_ARGUMENT, GET_ENVIRONMENT_VARIABLE, MOVE_ALLOC, RANDOM_INIT, RANDOM_NUMBER, RANDOM_SEED, SYSTEM_CLOCK |
| Atomic intrinsic subroutines | ATOMIC_ADD |
| Collective intrinsic subroutines | CO_REDUCE |
diff --git a/flang/include/flang/Runtime/command.h b/flang/include/flang/Runtime/command.h
index ec6289390545479..07f6d8e169ead6c 100644
--- a/flang/include/flang/Runtime/command.h
+++ b/flang/include/flang/Runtime/command.h
@@ -23,6 +23,11 @@ extern "C" {
// integer kind.
std::int32_t RTNAME(ArgumentCount)();
+// Try to get the the current date (same format as CTIME: convert to a string)
+// Return a STATUS as described in the standard.
+std::int32_t RTNAME(FDate)(
+ const Descriptor *argument = nullptr, const Descriptor *errmsg = nullptr);
+
// 16.9.82 GET_COMMAND
// Try to get the value of the whole command. All of the parameters are
// optional.
diff --git a/flang/include/flang/Runtime/extensions.h b/flang/include/flang/Runtime/extensions.h
index ad592814e5acb79..92b9907860121aa 100644
--- a/flang/include/flang/Runtime/extensions.h
+++ b/flang/include/flang/Runtime/extensions.h
@@ -24,6 +24,8 @@ void FORTRAN_PROCEDURE_NAME(flush)(const int &unit);
// GNU Fortran 77 compatibility function IARGC.
std::int32_t FORTRAN_PROCEDURE_NAME(iargc)();
+void FORTRAN_PROCEDURE_NAME(fdate)(std::int8_t *string, std::int64_t length);
+
// GNU Fortran 77 compatibility subroutine GETARG(N, ARG).
void FORTRAN_PROCEDURE_NAME(getarg)(
std::int32_t &n, std::int8_t *arg, std::int64_t length);
diff --git a/flang/runtime/command.cpp b/flang/runtime/command.cpp
index b81a0791c5e571b..da0803c39f49b6d 100644
--- a/flang/runtime/command.cpp
+++ b/flang/runtime/command.cpp
@@ -14,6 +14,7 @@
#include "flang/Runtime/descriptor.h"
#include <cstdlib>
#include <limits>
+#include <time.h>
namespace Fortran::runtime {
std::int32_t RTNAME(ArgumentCount)() {
@@ -125,6 +126,33 @@ static bool FitsInDescriptor(
kind, terminator, value);
}
+void removeNewLine(char *str) {
+ char *newlinePos = strchr(str, '\n');
+ if (newlinePos != NULL) {
+ *newlinePos = '\0'; // Replace with null terminator
+ }
+}
+
+std::int32_t RTNAME(FDate)(const Descriptor *value, const Descriptor *errmsg) {
+ FillWithSpaces(*value);
+
+ time_t current_time;
+ time(¤t_time);
+
+ char *time_string = ctime(¤t_time);
+ removeNewLine(time_string);
+ std::int64_t stringLen{StringLength(time_string)};
+ if (stringLen <= 0) {
+ return ToErrmsg(errmsg, StatMissingArgument);
+ }
+
+ if (value) {
+ return CopyToDescriptor(*value, time_string, stringLen, errmsg);
+ }
+
+ return StatOk;
+}
+
std::int32_t RTNAME(GetCommandArgument)(std::int32_t n, const Descriptor *value,
const Descriptor *length, const Descriptor *errmsg, const char *sourceFile,
int line) {
diff --git a/flang/runtime/extensions.cpp b/flang/runtime/extensions.cpp
index b8e9b6eae132059..0142cac1d929d4d 100644
--- a/flang/runtime/extensions.cpp
+++ b/flang/runtime/extensions.cpp
@@ -30,6 +30,11 @@ void FORTRAN_PROCEDURE_NAME(flush)(const int &unit) {
// RESULT = IARGC()
std::int32_t FORTRAN_PROCEDURE_NAME(iargc)() { return RTNAME(ArgumentCount)(); }
+void FORTRAN_PROCEDURE_NAME(fdate)(std::int8_t *arg, std::int64_t length) {
+ Descriptor value{*Descriptor::Create(1, length, arg, 0)};
+ (void)RTNAME(FDate)(&value, nullptr);
+}
+
// CALL GETARG(N, ARG)
void FORTRAN_PROCEDURE_NAME(getarg)(
std::int32_t &n, std::int8_t *arg, std::int64_t length) {
diff --git a/flang/unittests/Runtime/CommandTest.cpp b/flang/unittests/Runtime/CommandTest.cpp
index c3571c9684e4b07..091870e4baf1730 100644
--- a/flang/unittests/Runtime/CommandTest.cpp
+++ b/flang/unittests/Runtime/CommandTest.cpp
@@ -225,6 +225,12 @@ TEST_F(ZeroArguments, GetCommandArgument) {
CheckMissingArgumentValue(1);
}
+TEST_F(ZeroArguments, FDate) {
+ CheckMissingArgumentValue(-1);
+ CheckArgumentValue(commandOnlyArgv[0], 0);
+ CheckMissingArgumentValue(1);
+}
+
TEST_F(ZeroArguments, GetCommand) { CheckCommandValue(commandOnlyArgv, 1); }
static const char *oneArgArgv[]{"aProgram", "anArgumentOfLength20"};
@@ -242,6 +248,13 @@ TEST_F(OneArgument, GetCommandArgument) {
CheckMissingArgumentValue(2);
}
+TEST_F(OneArgument, FDate) {
+ CheckMissingArgumentValue(-1);
+ CheckArgumentValue(oneArgArgv[0], 0);
+ CheckArgumentValue(oneArgArgv[1], 1);
+ CheckMissingArgumentValue(2);
+}
+
TEST_F(OneArgument, GetCommand) { CheckCommandValue(oneArgArgv, 2); }
static const char *severalArgsArgv[]{
@@ -284,6 +297,7 @@ TEST_F(SeveralArguments, ArgValueTooShort) {
ASSERT_NE(tooShort, nullptr);
EXPECT_EQ(RTNAME(GetCommandArgument)(1, tooShort.get()), -1);
CheckDescriptorEqStr(tooShort.get(), severalArgsArgv[1]);
+ EXPECT_EQ(RTNAME(FDate)(tooShort.get()), -1);
OwningPtr<Descriptor> length{EmptyIntDescriptor()};
ASSERT_NE(length, nullptr);
|
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.
Thanks for the patch; everything looks good (modulo my small comments) other than the thread safety issue. I'd prefer if we could make this thread safe but I'm not sure exactly how to approach that
ctime_s is defined in MS, ctime_r is defined in linux/macos
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.
Thanks, this is looking good, I just have a couple more small comments
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.
LGTM, maybe wait for @jeanPerier to check as well though. Thanks!
update based on:
character(20) :: string
call fdate(string)
write(*, *) string, "X" $ ../build-release/bin/flang-new test.f90
$ ./a.out
X If length if larger than it requires(24), fill the rest of buffer space. character(30) :: string
call fdate(string)
write(*, *) string, "X" $ ../build-release/bin/flang-new test.f90
$ ./a.out
Wed Nov 15 16:59:13 2023 X The length value is hardcoded, because: // Day Mon dd hh:mm:ss yyyy\n\0 is 26 characters, e.g.
// Tue May 26 21:51:03 2015\n\0 |
If the length is too short to fit completely, blank return. If length if larger than it requires(24), fill the rest of buffer space. hange the return type of `ctime_alloc` from char * to void, because we don't need the return value.
6fee4b1
to
c759cf9
Compare
Take copyBufferAndPad out of anonymous namespace and declear in 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.
Thanks, please add the POSIX macros to use ctime_r, and looks great otherwise.
… use CopyAndPad from character.h instead This reverts commit 344cbdc.
Hi @klausler , any thought of this patch? Thank in advance! |
Hi @jeanPerier I have made some changes, mainly on test cases and use |
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.
LGTM
…rmat (llvm#71222) reference to gfortran fdate https://gcc.gnu.org/onlinedocs/gfortran/FDATE.html usage: ```fortran CHARACTER(32) :: time CALL fdate(time) WRITE(*,*) time ``` fdate is used in the ECP proxy application https://proxyapps.exascaleproject.org/app/minismac2d/ https://github.com/Mantevo/miniSMAC/blob/f90446714226eeef650b78bce06ca4967792e74d/ref/smac2d.f#L1570 `fdate` now produce the same result on flang, compare to gfortran, where If the length is too short to fit completely, blank return. ```fortran character(20) :: string call fdate(string) write(*, *) string, "X" ``` ```bash $ ../build-release/bin/flang-new test.f90 $ ./a.out X ``` If length if larger than it requires(24), fill the rest of buffer space. ```fortran character(30) :: string call fdate(string) write(*, *) string, "X" ``` ```bash $ ../build-release/bin/flang-new test.f90 $ ./a.out Wed Nov 15 16:59:13 2023 X ``` The length value is hardcoded, because: ```c++ // Day Mon dd hh:mm:ss yyyy\n\0 is 26 characters, e.g. // Tue May 26 21:51:03 2015\n\0 ``` --------- Co-authored-by: Yi Wu <yiwu02@wdev-yiwu02.arm.com>
reference to gfortran fdate https://gcc.gnu.org/onlinedocs/gfortran/FDATE.html
usage:
fdate is used in the ECP proxy application https://proxyapps.exascaleproject.org/app/minismac2d/
https://github.com/Mantevo/miniSMAC/blob/f90446714226eeef650b78bce06ca4967792e74d/ref/smac2d.f#L1570