-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[flang] Support FLUSH as an intrinsic subroutine #165942
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
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-flang-fir-hlfir @llvm/pr-subscribers-flang-semantics Author: Miguel Saldivar (Saldivarcher) ChangesCurrently program flush_stmt_example
implicit none
integer :: unit
! Open a file for writing
open(unit=10, file="flush_stmt.txt", status="replace", action="write")
write(10,*) "This line is written to the file."
flush(10) ! <-- flush statement, not a CALL
print *, "The file has been flushed. You can read it now before close."
close(10)
end program flush_stmt_exampleIf Fixes #119418 Full diff: https://github.com/llvm/llvm-project/pull/165942.diff 7 Files Affected:
diff --git a/flang-rt/lib/runtime/extensions.cpp b/flang-rt/lib/runtime/extensions.cpp
index 19e75143705ab..d3a618c1a39ec 100644
--- a/flang-rt/lib/runtime/extensions.cpp
+++ b/flang-rt/lib/runtime/extensions.cpp
@@ -163,6 +163,17 @@ void FORTRAN_PROCEDURE_NAME(flush)(const int &unit) {
Cookie cookie{IONAME(BeginFlush)(unit, __FILE__, __LINE__)};
IONAME(EndIoStatement)(cookie);
}
+
+void RTNAME(Flush)(int unit) {
+ // We set the `unit == -1` on the `flush()` case, so flush all units.
+ if (unit < 0) {
+ Terminator terminator{__FILE__, __LINE__};
+ IoErrorHandler handler{terminator};
+ ExternalFileUnit::FlushAll(handler);
+ return;
+ }
+ FORTRAN_PROCEDURE_NAME(flush)(unit);
+}
} // namespace io
// CALL FDATE(DATE)
diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
index 3407dd01dd504..51a3ae5af7688 100644
--- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
+++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
@@ -278,6 +278,7 @@ struct IntrinsicLibrary {
mlir::Value genExtremum(mlir::Type, llvm::ArrayRef<mlir::Value>);
void genFenceProxyAsync(llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genFloor(mlir::Type, llvm::ArrayRef<mlir::Value>);
+ void genFlush(llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genFraction(mlir::Type resultType,
mlir::ArrayRef<mlir::Value> args);
void genFree(mlir::ArrayRef<fir::ExtendedValue> args);
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h b/flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h
index 7a97172cfbb9a..5121ccce921c6 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h
@@ -51,6 +51,8 @@ mlir::Value genDsecnds(fir::FirOpBuilder &builder, mlir::Location loc,
void genEtime(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value values, mlir::Value time);
+void genFlush(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value unit);
+
void genFree(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value ptr);
mlir::Value genFseek(fir::FirOpBuilder &builder, mlir::Location loc,
diff --git a/flang/include/flang/Runtime/extensions.h b/flang/include/flang/Runtime/extensions.h
index 9fd3e118a0f22..8db68eb9c245c 100644
--- a/flang/include/flang/Runtime/extensions.h
+++ b/flang/include/flang/Runtime/extensions.h
@@ -34,6 +34,7 @@ double RTNAME(Dsecnds)(double *refTime, const char *sourceFile, int line);
// CALL FLUSH(n) antedates the Fortran 2003 FLUSH statement.
void FORTRAN_PROCEDURE_NAME(flush)(const int &unit);
+void RTNAME(Flush)(int unit);
// GNU extension subroutine FDATE
void FORTRAN_PROCEDURE_NAME(fdate)(char *string, std::int64_t length);
diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index 1de5e6b53ba71..d403afe9de307 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -1597,6 +1597,10 @@ static const IntrinsicInterface intrinsicSubroutine[]{
{"exit", {{"status", DefaultInt, Rank::scalar, Optionality::optional}}, {},
Rank::elemental, IntrinsicClass::impureSubroutine},
{"free", {{"ptr", Addressable}}, {}},
+ {"flush",
+ {{"unit", AnyInt, Rank::scalar, Optionality::optional,
+ common::Intent::In}},
+ {}, Rank::elemental, IntrinsicClass::impureSubroutine},
{"fseek",
{{"unit", AnyInt, Rank::scalar}, {"offset", AnyInt, Rank::scalar},
{"whence", AnyInt, Rank::scalar},
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 15ea84565dd75..317414ef0fec6 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -525,6 +525,10 @@ static constexpr IntrinsicHandler handlers[]{
{"back", asValue, handleDynamicOptional}}},
/*isElemental=*/false},
{"floor", &I::genFloor},
+ {"flush",
+ &I::genFlush,
+ {{{"unit", asValue, handleDynamicOptional}}},
+ /*isElemental=*/false},
{"fraction", &I::genFraction},
{"free", &I::genFree},
{"fseek",
@@ -4601,6 +4605,20 @@ mlir::Value IntrinsicLibrary::genFloor(mlir::Type resultType,
return builder.createConvert(loc, resultType, floor);
}
+// FLUSH
+void IntrinsicLibrary::genFlush(llvm::ArrayRef<fir::ExtendedValue> args) {
+ assert(args.size() == 1);
+
+ mlir::Value unit;
+ if (isStaticallyAbsent(args[0]))
+ // Give a sentinal value of `-1` on the `()` case.
+ unit = builder.createIntegerConstant(loc, builder.getI32Type(), -1);
+ else
+ unit = fir::getBase(args[0]);
+
+ fir::runtime::genFlush(builder, loc, unit);
+}
+
// FRACTION
mlir::Value IntrinsicLibrary::genFraction(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
diff --git a/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp b/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp
index 110b1b20898c7..9fa3b18a255bd 100644
--- a/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp
+++ b/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp
@@ -137,6 +137,15 @@ void fir::runtime::genEtime(fir::FirOpBuilder &builder, mlir::Location loc,
fir::CallOp::create(builder, loc, runtimeFunc, args);
}
+void fir::runtime::genFlush(fir::FirOpBuilder &builder, mlir::Location loc,
+ mlir::Value unit) {
+ auto runtimeFunc = fir::runtime::getRuntimeFunc<mkRTKey(Flush)>(loc, builder);
+ llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
+ builder, loc, runtimeFunc.getFunctionType(), unit);
+
+ fir::CallOp::create(builder, loc, runtimeFunc, args);
+}
+
void fir::runtime::genFree(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value ptr) {
auto runtimeFunc = fir::runtime::getRuntimeFunc<mkRTKey(Free)>(loc, builder);
|
9d3543e to
a40172f
Compare
FLUSH
tblah
left a comment
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 contributing this.
Please could you add tests showing the correct lowering for flush with an argument, without an argument, and with a dynamically optional argument. There are examples in flang/test/Lower/Intrinsics.
a40172f to
cecc18b
Compare
Test added, thank you! |
tblah
left a comment
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.
What about something dynamically optional like
subroutine flush_unit(unit)
integer, optional :: unit
call flush(unit)
end subroutine
|
|
gfortran doesn't support it. classic-flang (armflang 24.04) does support it. llvm-flang with your patch does not prevent the usage of a dynamically optional argument. I built your branch and tried it and it generates From this we can see that whilst the dynamic optional is handled, it defaults to 0. I think you will need -1 for how you defined flush. I don't mind if you choose to support this or not. If you do support it, you need to make sure the default value is -1 and have a test for the lowering of a dynamically optional argument. If you choose not to support this, please make it clear in the documentation and add a test to make sure that this is correctly diagnosed by the compiler (if you just remove |
cecc18b to
9deab44
Compare
Ended up adding support for it! I also added the testcase to the Thanks for the review btw, I appreciate it 🙏 |
|
I think we need add this non-standard subroutine in https://github.com/llvm/llvm-project/blob/main/flang/docs/Intrinsics.md. |
9deab44 to
a8ed9f5
Compare
Previously `FLUSH` was only recognized in statement form (e.g. `flush(unit)`); a subroutine invocation `call flush(unit)` was treated as a generic user call with no special semantics. This change teaches lowering/semantics to handle `CALL FLUSH` equivalently. Fixes llvm#119418
Done ✔️ |
🐧 Linux x64 Test Results
|
Thanks. LG |
Previously
FLUSHwas only recognized in statement form (e.g.flush(unit)); asubroutine invocation
call flush(unit)was treated as a generic user call withno special semantics. This change teaches lowering/semantics to handle
CALL FLUSHequivalently.Fixes #119418