Skip to content

Commit 8c5fdb0

Browse files
JDPailleuxktras
authored andcommitted
Automerge: [flang][Lower] Add lowering to SYNC ALL, SYNC MEMORY and SYNC IMAGES to PRIF (#154166)
In relation to the approval and merge of the llvm/llvm-project#76088 specification about multi-image features in Flang. Here is a PR on adding support for SYNC ALL, SYNC MEMORY and SYNC IMAGES in conformance with the PRIF specification. --------- Co-authored-by: Katherine Rasmussen <[email protected]>
2 parents 3d577f8 + 5149e51 commit 8c5fdb0

File tree

10 files changed

+317
-21
lines changed

10 files changed

+317
-21
lines changed

flang/include/flang/Lower/AbstractConverter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,9 @@ class AbstractConverter {
271271
virtual const Fortran::lower::pft::FunctionLikeUnit *
272272
getCurrentFunctionUnit() const = 0;
273273

274+
/// Check support of Multi-image features if -fcoarray is provided
275+
virtual void checkCoarrayEnabled() = 0;
276+
274277
//===--------------------------------------------------------------------===//
275278
// Types
276279
//===--------------------------------------------------------------------===//

flang/include/flang/Optimizer/Builder/IntrinsicCall.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -573,15 +573,6 @@ struct IntrinsicLibrary {
573573

574574
void setResultMustBeFreed() { resultMustBeFreed = true; }
575575

576-
// Check support of coarray features
577-
void checkCoarrayEnabled() {
578-
if (converter &&
579-
!converter->getFoldingContext().languageFeatures().IsEnabled(
580-
Fortran::common::LanguageFeature::Coarray))
581-
fir::emitFatalError(loc, "Coarrays disabled, use '-fcoarray' to enable.",
582-
false);
583-
}
584-
585576
fir::FirOpBuilder &builder;
586577
mlir::Location loc;
587578
bool resultMustBeFreed = false;

flang/include/flang/Optimizer/Builder/Runtime/Coarray.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,15 @@ void genCoMin(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value A,
7171
void genCoSum(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value A,
7272
mlir::Value resultImage, mlir::Value stat, mlir::Value errmsg);
7373

74+
/// Generate call to runtime subroutine prif_sync_all
75+
void genSyncAllStatement(fir::FirOpBuilder &builder, mlir::Location loc,
76+
mlir::Value stat, mlir::Value errmsg);
77+
/// Generate call to runtime subroutine prif_sync_memory
78+
void genSyncMemoryStatement(fir::FirOpBuilder &builder, mlir::Location loc,
79+
mlir::Value stat, mlir::Value errmsg);
80+
/// Generate call to runtime subroutine prif_sync_images
81+
void genSyncImagesStatement(fir::FirOpBuilder &builder, mlir::Location loc,
82+
mlir::Value imageSet, mlir::Value stat,
83+
mlir::Value errmsg);
7484
} // namespace fir::runtime
7585
#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_COARRAY_H

flang/lib/Lower/Bridge.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,16 @@ class FirConverter : public Fortran::lower::AbstractConverter {
11311131
return currentFunctionUnit;
11321132
}
11331133

1134+
void checkCoarrayEnabled() override final {
1135+
if (!getFoldingContext().languageFeatures().IsEnabled(
1136+
Fortran::common::LanguageFeature::Coarray))
1137+
fir::emitFatalError(
1138+
getCurrentLocation(),
1139+
"Not yet implemented: Multi-image features are experimental and are "
1140+
"disabled by default, use '-fcoarray' to enable.",
1141+
false);
1142+
}
1143+
11341144
void registerTypeInfo(mlir::Location loc,
11351145
Fortran::lower::SymbolRef typeInfoSym,
11361146
const Fortran::semantics::DerivedTypeSpec &typeSpec,

flang/lib/Lower/Runtime.cpp

Lines changed: 91 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "flang/Lower/OpenMP.h"
1313
#include "flang/Lower/StatementContext.h"
1414
#include "flang/Optimizer/Builder/FIRBuilder.h"
15+
#include "flang/Optimizer/Builder/Runtime/Coarray.h"
1516
#include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
1617
#include "flang/Optimizer/Builder/Todo.h"
1718
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
@@ -47,6 +48,42 @@ static void genUnreachable(fir::FirOpBuilder &builder, mlir::Location loc) {
4748
builder.setInsertionPointToStart(newBlock);
4849
}
4950

51+
/// Initializes values for STAT and ERRMSG
52+
static std::pair<mlir::Value, mlir::Value> getStatAndErrmsg(
53+
Fortran::lower::AbstractConverter &converter, mlir::Location loc,
54+
const std::list<Fortran::parser::StatOrErrmsg> &statOrErrList) {
55+
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
56+
Fortran::lower::StatementContext stmtCtx;
57+
58+
mlir::Value errMsgExpr, statExpr;
59+
for (const Fortran::parser::StatOrErrmsg &statOrErr : statOrErrList) {
60+
std::visit(Fortran::common::visitors{
61+
[&](const Fortran::parser::StatVariable &statVar) {
62+
statExpr = fir::getBase(converter.genExprAddr(
63+
loc, Fortran::semantics::GetExpr(statVar), stmtCtx));
64+
},
65+
[&](const Fortran::parser::MsgVariable &errMsgVar) {
66+
const Fortran::semantics::SomeExpr *expr =
67+
Fortran::semantics::GetExpr(errMsgVar);
68+
errMsgExpr = fir::getBase(
69+
converter.genExprBox(loc, *expr, stmtCtx));
70+
}},
71+
statOrErr.u);
72+
}
73+
74+
if (!statExpr) {
75+
statExpr = fir::AbsentOp::create(builder, loc,
76+
builder.getRefType(builder.getI32Type()));
77+
}
78+
if (!errMsgExpr) {
79+
errMsgExpr = fir::AbsentOp::create(
80+
builder, loc,
81+
fir::BoxType::get(fir::CharacterType::get(
82+
builder.getContext(), 1, fir::CharacterType::unknownLen())));
83+
}
84+
return {statExpr, errMsgExpr};
85+
}
86+
5087
//===----------------------------------------------------------------------===//
5188
// Misc. Fortran statements that lower to runtime calls
5289
//===----------------------------------------------------------------------===//
@@ -169,20 +206,68 @@ void Fortran::lower::genUnlockStatement(
169206

170207
void Fortran::lower::genSyncAllStatement(
171208
Fortran::lower::AbstractConverter &converter,
172-
const Fortran::parser::SyncAllStmt &) {
173-
TODO(converter.getCurrentLocation(), "coarray: SYNC ALL runtime");
209+
const Fortran::parser::SyncAllStmt &stmt) {
210+
mlir::Location loc = converter.getCurrentLocation();
211+
converter.checkCoarrayEnabled();
212+
213+
// Handle STAT and ERRMSG values
214+
const std::list<Fortran::parser::StatOrErrmsg> &statOrErrList = stmt.v;
215+
auto [statAddr, errMsgAddr] = getStatAndErrmsg(converter, loc, statOrErrList);
216+
217+
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
218+
fir::runtime::genSyncAllStatement(builder, loc, statAddr, errMsgAddr);
174219
}
175220

176221
void Fortran::lower::genSyncImagesStatement(
177222
Fortran::lower::AbstractConverter &converter,
178-
const Fortran::parser::SyncImagesStmt &) {
179-
TODO(converter.getCurrentLocation(), "coarray: SYNC IMAGES runtime");
223+
const Fortran::parser::SyncImagesStmt &stmt) {
224+
mlir::Location loc = converter.getCurrentLocation();
225+
converter.checkCoarrayEnabled();
226+
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
227+
228+
// Handle STAT and ERRMSG values
229+
const std::list<Fortran::parser::StatOrErrmsg> &statOrErrList =
230+
std::get<std::list<Fortran::parser::StatOrErrmsg>>(stmt.t);
231+
auto [statAddr, errMsgAddr] = getStatAndErrmsg(converter, loc, statOrErrList);
232+
233+
// SYNC_IMAGES(*) is passed as count == -1 while SYNC IMAGES([]) has count
234+
// == 0. Note further that SYNC IMAGES(*) is not semantically equivalent to
235+
// SYNC ALL.
236+
Fortran::lower::StatementContext stmtCtx;
237+
mlir::Value imageSet;
238+
const Fortran::parser::SyncImagesStmt::ImageSet &imgSet =
239+
std::get<Fortran::parser::SyncImagesStmt::ImageSet>(stmt.t);
240+
std::visit(Fortran::common::visitors{
241+
[&](const Fortran::parser::IntExpr &intExpr) {
242+
const SomeExpr *expr = Fortran::semantics::GetExpr(intExpr);
243+
imageSet =
244+
fir::getBase(converter.genExprBox(loc, *expr, stmtCtx));
245+
},
246+
[&](const Fortran::parser::Star &) {
247+
imageSet = fir::AbsentOp::create(
248+
builder, loc,
249+
fir::BoxType::get(fir::SequenceType::get(
250+
{fir::SequenceType::getUnknownExtent()},
251+
builder.getI32Type())));
252+
}},
253+
imgSet.u);
254+
255+
fir::runtime::genSyncImagesStatement(builder, loc, imageSet, statAddr,
256+
errMsgAddr);
180257
}
181258

182259
void Fortran::lower::genSyncMemoryStatement(
183260
Fortran::lower::AbstractConverter &converter,
184-
const Fortran::parser::SyncMemoryStmt &) {
185-
TODO(converter.getCurrentLocation(), "coarray: SYNC MEMORY runtime");
261+
const Fortran::parser::SyncMemoryStmt &stmt) {
262+
mlir::Location loc = converter.getCurrentLocation();
263+
converter.checkCoarrayEnabled();
264+
265+
// Handle STAT and ERRMSG values
266+
const std::list<Fortran::parser::StatOrErrmsg> &statOrErrList = stmt.v;
267+
auto [statAddr, errMsgAddr] = getStatAndErrmsg(converter, loc, statOrErrList);
268+
269+
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
270+
fir::runtime::genSyncMemoryStatement(builder, loc, statAddr, errMsgAddr);
186271
}
187272

188273
void Fortran::lower::genSyncTeamStatement(

flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3716,7 +3716,7 @@ mlir::Value IntrinsicLibrary::genCmplx(mlir::Type resultType,
37163716

37173717
// CO_BROADCAST
37183718
void IntrinsicLibrary::genCoBroadcast(llvm::ArrayRef<fir::ExtendedValue> args) {
3719-
checkCoarrayEnabled();
3719+
converter->checkCoarrayEnabled();
37203720
assert(args.size() == 4);
37213721
mlir::Value sourceImage = fir::getBase(args[1]);
37223722
mlir::Value status =
@@ -3735,7 +3735,7 @@ void IntrinsicLibrary::genCoBroadcast(llvm::ArrayRef<fir::ExtendedValue> args) {
37353735

37363736
// CO_MAX
37373737
void IntrinsicLibrary::genCoMax(llvm::ArrayRef<fir::ExtendedValue> args) {
3738-
checkCoarrayEnabled();
3738+
converter->checkCoarrayEnabled();
37393739
assert(args.size() == 4);
37403740
mlir::Value refNone =
37413741
fir::AbsentOp::create(builder, loc,
@@ -3755,7 +3755,7 @@ void IntrinsicLibrary::genCoMax(llvm::ArrayRef<fir::ExtendedValue> args) {
37553755

37563756
// CO_MIN
37573757
void IntrinsicLibrary::genCoMin(llvm::ArrayRef<fir::ExtendedValue> args) {
3758-
checkCoarrayEnabled();
3758+
converter->checkCoarrayEnabled();
37593759
assert(args.size() == 4);
37603760
mlir::Value refNone =
37613761
fir::AbsentOp::create(builder, loc,
@@ -3775,7 +3775,7 @@ void IntrinsicLibrary::genCoMin(llvm::ArrayRef<fir::ExtendedValue> args) {
37753775

37763776
// CO_SUM
37773777
void IntrinsicLibrary::genCoSum(llvm::ArrayRef<fir::ExtendedValue> args) {
3778-
checkCoarrayEnabled();
3778+
converter->checkCoarrayEnabled();
37793779
assert(args.size() == 4);
37803780
mlir::Value absentInt =
37813781
fir::AbsentOp::create(builder, loc,
@@ -7438,7 +7438,7 @@ IntrinsicLibrary::genNull(mlir::Type, llvm::ArrayRef<fir::ExtendedValue> args) {
74387438
fir::ExtendedValue
74397439
IntrinsicLibrary::genNumImages(mlir::Type resultType,
74407440
llvm::ArrayRef<fir::ExtendedValue> args) {
7441-
checkCoarrayEnabled();
7441+
converter->checkCoarrayEnabled();
74427442
assert(args.size() == 0 || args.size() == 1);
74437443

74447444
if (args.size())
@@ -8519,7 +8519,7 @@ mlir::Value IntrinsicLibrary::genThisGrid(mlir::Type resultType,
85198519
fir::ExtendedValue
85208520
IntrinsicLibrary::genThisImage(mlir::Type resultType,
85218521
llvm::ArrayRef<fir::ExtendedValue> args) {
8522-
checkCoarrayEnabled();
8522+
converter->checkCoarrayEnabled();
85238523
assert(args.size() >= 1 && args.size() <= 3);
85248524
const bool coarrayIsAbsent = args.size() == 1;
85258525
mlir::Value team =

flang/lib/Optimizer/Builder/Runtime/Coarray.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,64 @@ void fir::runtime::genCoSum(fir::FirOpBuilder &builder, mlir::Location loc,
165165
genCollectiveSubroutine(builder, loc, A, resultImage, stat, errmsg,
166166
PRIFNAME_SUB("co_sum"));
167167
}
168+
169+
/// Generate call to runtime subroutine prif_sync_all
170+
void fir::runtime::genSyncAllStatement(fir::FirOpBuilder &builder,
171+
mlir::Location loc, mlir::Value stat,
172+
mlir::Value errmsg) {
173+
mlir::FunctionType ftype =
174+
PRIF_FUNCTYPE(PRIF_STAT_TYPE, PRIF_ERRMSG_TYPE, PRIF_ERRMSG_TYPE);
175+
mlir::func::FuncOp funcOp =
176+
builder.createFunction(loc, PRIFNAME_SUB("sync_all"), ftype);
177+
178+
auto [errmsgArg, errmsgAllocArg] = genErrmsgPRIF(builder, loc, errmsg);
179+
llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
180+
builder, loc, ftype, stat, errmsgArg, errmsgAllocArg);
181+
fir::CallOp::create(builder, loc, funcOp, args);
182+
}
183+
184+
/// Generate call to runtime subroutine prif_sync_memory
185+
void fir::runtime::genSyncMemoryStatement(fir::FirOpBuilder &builder,
186+
mlir::Location loc, mlir::Value stat,
187+
mlir::Value errmsg) {
188+
mlir::FunctionType ftype =
189+
PRIF_FUNCTYPE(PRIF_STAT_TYPE, PRIF_ERRMSG_TYPE, PRIF_ERRMSG_TYPE);
190+
mlir::func::FuncOp funcOp =
191+
builder.createFunction(loc, PRIFNAME_SUB("sync_memory"), ftype);
192+
193+
auto [errmsgArg, errmsgAllocArg] = genErrmsgPRIF(builder, loc, errmsg);
194+
llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
195+
builder, loc, ftype, stat, errmsgArg, errmsgAllocArg);
196+
fir::CallOp::create(builder, loc, funcOp, args);
197+
}
198+
199+
/// Generate call to runtime subroutine prif_sync_images
200+
void fir::runtime::genSyncImagesStatement(fir::FirOpBuilder &builder,
201+
mlir::Location loc,
202+
mlir::Value imageSet,
203+
mlir::Value stat,
204+
mlir::Value errmsg) {
205+
mlir::Type imgSetTy = fir::BoxType::get(fir::SequenceType::get(
206+
{fir::SequenceType::getUnknownExtent()}, builder.getI32Type()));
207+
mlir::FunctionType ftype = PRIF_FUNCTYPE(imgSetTy, PRIF_STAT_TYPE,
208+
PRIF_ERRMSG_TYPE, PRIF_ERRMSG_TYPE);
209+
mlir::func::FuncOp funcOp =
210+
builder.createFunction(loc, PRIFNAME_SUB("sync_images"), ftype);
211+
212+
// If imageSet is scalar, PRIF require to pass an array of size 1.
213+
if (auto boxTy = mlir::dyn_cast<fir::BoxType>(imageSet.getType())) {
214+
if (!mlir::isa<fir::SequenceType>(boxTy.getEleTy())) {
215+
mlir::Value one =
216+
builder.createIntegerConstant(loc, builder.getI32Type(), 1);
217+
mlir::Value shape = fir::ShapeOp::create(builder, loc, one);
218+
imageSet = fir::ReboxOp::create(
219+
builder, loc,
220+
fir::BoxType::get(fir::SequenceType::get({1}, builder.getI32Type())),
221+
imageSet, shape, mlir::Value{});
222+
}
223+
}
224+
auto [errmsgArg, errmsgAllocArg] = genErrmsgPRIF(builder, loc, errmsg);
225+
llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
226+
builder, loc, ftype, imageSet, stat, errmsgArg, errmsgAllocArg);
227+
fir::CallOp::create(builder, loc, funcOp, args);
228+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
! RUN: %flang_fc1 -emit-hlfir -fcoarray %s -o - | FileCheck %s --check-prefixes=COARRAY
2+
! RUN: not %flang_fc1 -emit-hlfir %s 2>&1 | FileCheck %s --check-prefixes=NOCOARRAY
3+
4+
program test_sync_all
5+
implicit none
6+
! NOCOARRAY: Not yet implemented: Multi-image features are experimental and are disabled by default, use '-fcoarray' to enable.
7+
8+
! COARRAY: %[[ERRMSG:.*]]:2 = hlfir.declare %[[VAL_1:.*]] typeparams %[[C_128:.*]] {uniq_name = "_QFEerror_message"} : (!fir.ref<!fir.char<1,128>>, index) -> (!fir.ref<!fir.char<1,128>>, !fir.ref<!fir.char<1,128>>)
9+
! COARRAY: %[[STAT:.*]]:2 = hlfir.declare %[[VAL_2:.*]] {uniq_name = "_QFEsync_status"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
10+
integer sync_status
11+
character(len=128) :: error_message
12+
13+
! COARRAY: %[[VAL_3:.*]] = fir.absent !fir.ref<i32>
14+
! COARRAY: %[[VAL_4:.*]] = fir.absent !fir.box<!fir.char<1,?>>
15+
! COARRAY: %[[VAL_5:.*]] = fir.absent !fir.box<!fir.char<1,?>>
16+
! COARRAY: fir.call @_QMprifPprif_sync_all(%[[VAL_3]], %[[VAL_4]], %[[VAL_5]]) fastmath<contract> : (!fir.ref<i32>, !fir.box<!fir.char<1,?>>, !fir.box<!fir.char<1,?>>) -> ()
17+
sync all
18+
19+
! COARRAY: %[[VAL_6:.*]] = fir.absent !fir.box<!fir.char<1,?>>
20+
! COARRAY: %[[VAL_7:.*]] = fir.absent !fir.box<!fir.char<1,?>>
21+
! COARRAY: fir.call @_QMprifPprif_sync_all(%[[STAT]]#0, %[[VAL_6]], %[[VAL_7]]) fastmath<contract> : (!fir.ref<i32>, !fir.box<!fir.char<1,?>>, !fir.box<!fir.char<1,?>>) -> ()
22+
sync all(stat=sync_status)
23+
24+
! COARRAY: %[[VAL_8:.*]] = fir.embox %[[ERRMSG]]#0 : (!fir.ref<!fir.char<1,128>>) -> !fir.box<!fir.char<1,128>>
25+
! COARRAY: %[[VAL_9:.*]] = fir.absent !fir.ref<i32>
26+
! COARRAY: %[[VAL_10:.*]] = fir.absent !fir.box<!fir.char<1,?>>
27+
! COARRAY: %[[VAL_11:.*]] = fir.convert %[[VAL_8]] : (!fir.box<!fir.char<1,128>>) -> !fir.box<!fir.char<1,?>>
28+
! COARRAY: fir.call @_QMprifPprif_sync_all(%[[VAL_9]], %[[VAL_11]], %[[VAL_10]]) fastmath<contract> : (!fir.ref<i32>, !fir.box<!fir.char<1,?>>, !fir.box<!fir.char<1,?>>) -> ()
29+
sync all( errmsg=error_message)
30+
31+
! COARRAY: %[[VAL_12:.*]] = fir.embox %[[ERRMSG]]#0 : (!fir.ref<!fir.char<1,128>>) -> !fir.box<!fir.char<1,128>>
32+
! COARRAY: %[[VAL_13:.*]] = fir.absent !fir.box<!fir.char<1,?>>
33+
! COARRAY: %[[VAL_14:.*]] = fir.convert %[[VAL_12]] : (!fir.box<!fir.char<1,128>>) -> !fir.box<!fir.char<1,?>>
34+
! COARRAY: fir.call @_QMprifPprif_sync_all(%[[STAT]]#0, %[[VAL_14]], %[[VAL_13]]) fastmath<contract> : (!fir.ref<i32>, !fir.box<!fir.char<1,?>>, !fir.box<!fir.char<1,?>>) -> ()
35+
sync all(stat=sync_status, errmsg=error_message)
36+
37+
end program test_sync_all

0 commit comments

Comments
 (0)