[flang-commits] [flang] [flang][Lower] Add Lowering for CO_{BROADCAST, MAX, MIN, MAX} to PRIF (PR #154770)
via flang-commits
flang-commits at lists.llvm.org
Thu Aug 21 07:12:15 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-fir-hlfir
Author: Jean-Didier PAILLEUX (JDPailleux)
<details>
<summary>Changes</summary>
In relation to the approval and merge of the https://github.com/llvm/llvm-project/pull/76088 specification about multi-image features in Flang.
Here is a PR on adding support of the collectives CO_BROADCAST, CO_SUM, CO_MIN and CO_MAX in conformance with the PRIF specification.
---
Patch is 46.15 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/154770.diff
8 Files Affected:
- (modified) flang/include/flang/Optimizer/Builder/IntrinsicCall.h (+4)
- (modified) flang/include/flang/Optimizer/Builder/Runtime/Coarray.h (+22)
- (modified) flang/lib/Optimizer/Builder/IntrinsicCall.cpp (+108)
- (modified) flang/lib/Optimizer/Builder/Runtime/Coarray.cpp (+81)
- (added) flang/test/Lower/Coarray/co_broadcast.f90 (+92)
- (added) flang/test/Lower/Coarray/co_max.f90 (+112)
- (added) flang/test/Lower/Coarray/co_min.f90 (+112)
- (added) flang/test/Lower/Coarray/co_sum.f90 (+122)
``````````diff
diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
index 88c3ada3ff64f..84ed16c088e00 100644
--- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
+++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
@@ -225,6 +225,10 @@ struct IntrinsicLibrary {
fir::ExtendedValue genCharacterCompare(mlir::Type,
llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genCmplx(mlir::Type, llvm::ArrayRef<mlir::Value>);
+ void genCoBroadcast(llvm::ArrayRef<fir::ExtendedValue>);
+ void genCoMax(llvm::ArrayRef<fir::ExtendedValue>);
+ void genCoMin(llvm::ArrayRef<fir::ExtendedValue>);
+ void genCoSum(llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genConjg(mlir::Type, llvm::ArrayRef<mlir::Value>);
fir::ExtendedValue genCount(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
void genCpuTime(llvm::ArrayRef<fir::ExtendedValue>);
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Coarray.h b/flang/include/flang/Optimizer/Builder/Runtime/Coarray.h
index 23bb378c30838..10ed503a485a3 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/Coarray.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/Coarray.h
@@ -34,6 +34,11 @@ namespace fir::runtime {
return fir::NameUniquer::doProcedure({"prif"}, {}, oss.str()); \
}()
+#define PRIF_STAT_TYPE builder.getRefType(builder.getI32Type())
+#define PRIF_ERRMSG_TYPE \
+ fir::BoxType::get(fir::CharacterType::get(builder.getContext(), 1, \
+ fir::CharacterType::unknownLen()))
+
/// Generate Call to runtime prif_init
mlir::Value genInitCoarray(fir::FirOpBuilder &builder, mlir::Location loc);
@@ -49,5 +54,22 @@ mlir::Value getNumImagesWithTeam(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value getThisImage(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value team = {});
+/// Generate call to runtime subroutine prif_co_broadcast
+void genCoBroadcast(fir::FirOpBuilder &builder, mlir::Location loc,
+ mlir::Value A, mlir::Value sourceImage, mlir::Value stat,
+ mlir::Value errmsg);
+
+/// Generate call to runtime subroutine prif_co_max and prif_co_max_character
+void genCoMax(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value A,
+ mlir::Value resultImage, mlir::Value stat, mlir::Value errmsg);
+
+/// Generate call to runtime subroutine prif_co_min or prif_co_min_character
+void genCoMin(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value A,
+ mlir::Value resultImage, mlir::Value stat, mlir::Value errmsg);
+
+/// Generate call to runtime subroutine prif_co_sum
+void genCoSum(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value A,
+ mlir::Value resultImage, mlir::Value stat, mlir::Value errmsg);
+
} // namespace fir::runtime
#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_COARRAY_H
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 8aacdb1815e3b..d5b4b77f8cb98 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -397,6 +397,34 @@ static constexpr IntrinsicHandler handlers[]{
{"cmplx",
&I::genCmplx,
{{{"x", asValue}, {"y", asValue, handleDynamicOptional}}}},
+ {"co_broadcast",
+ &I::genCoBroadcast,
+ {{{"a", asBox},
+ {"source_image", asAddr, handleDynamicOptional},
+ {"stat", asAddr, handleDynamicOptional},
+ {"errmsg", asBox, handleDynamicOptional}}},
+ /*isElemental*/ false},
+ {"co_max",
+ &I::genCoMax,
+ {{{"a", asBox},
+ {"result_image", asAddr, handleDynamicOptional},
+ {"stat", asAddr, handleDynamicOptional},
+ {"errmsg", asBox, handleDynamicOptional}}},
+ /*isElemental*/ false},
+ {"co_min",
+ &I::genCoMin,
+ {{{"a", asBox},
+ {"result_image", asAddr, handleDynamicOptional},
+ {"stat", asAddr, handleDynamicOptional},
+ {"errmsg", asBox, handleDynamicOptional}}},
+ /*isElemental*/ false},
+ {"co_sum",
+ &I::genCoSum,
+ {{{"a", asBox},
+ {"result_image", asAddr, handleDynamicOptional},
+ {"stat", asAddr, handleDynamicOptional},
+ {"errmsg", asBox, handleDynamicOptional}}},
+ /*isElemental*/ false},
{"command_argument_count", &I::genCommandArgumentCount},
{"conjg", &I::genConjg},
{"cosd", &I::genCosd},
@@ -3649,6 +3677,86 @@ mlir::Value IntrinsicLibrary::genCmplx(mlir::Type resultType,
imag);
}
+// CO_BROADCAST
+void IntrinsicLibrary::genCoBroadcast(llvm::ArrayRef<fir::ExtendedValue> args) {
+ checkCoarrayEnabled();
+ assert(args.size() == 4);
+ mlir::Value refNone =
+ builder
+ .create<fir::AbsentOp>(loc, builder.getRefType(builder.getI32Type()))
+ .getResult();
+ mlir::Value sourceImage =
+ isStaticallyAbsent(args[1]) ? refNone : fir::getBase(args[1]);
+ mlir::Value status =
+ isStaticallyAbsent(args[2]) ? refNone : fir::getBase(args[2]);
+ mlir::Value errmsg =
+ isStaticallyAbsent(args[3])
+ ? builder.create<fir::AbsentOp>(loc, PRIF_ERRMSG_TYPE).getResult()
+ : fir::getBase(args[3]);
+ fir::runtime::genCoBroadcast(builder, loc, fir::getBase(args[0]), sourceImage,
+ status, errmsg);
+}
+
+// CO_MAX
+void IntrinsicLibrary::genCoMax(llvm::ArrayRef<fir::ExtendedValue> args) {
+ checkCoarrayEnabled();
+ assert(args.size() == 4);
+ mlir::Value refNone =
+ builder
+ .create<fir::AbsentOp>(loc, builder.getRefType(builder.getI32Type()))
+ .getResult();
+ mlir::Value remoteImage =
+ isStaticallyAbsent(args[1]) ? refNone : fir::getBase(args[1]);
+ mlir::Value status =
+ isStaticallyAbsent(args[2]) ? refNone : fir::getBase(args[2]);
+ mlir::Value errmsg =
+ isStaticallyAbsent(args[3])
+ ? builder.create<fir::AbsentOp>(loc, PRIF_ERRMSG_TYPE).getResult()
+ : fir::getBase(args[3]);
+ fir::runtime::genCoMax(builder, loc, fir::getBase(args[0]), remoteImage,
+ status, errmsg);
+}
+
+// CO_MIN
+void IntrinsicLibrary::genCoMin(llvm::ArrayRef<fir::ExtendedValue> args) {
+ checkCoarrayEnabled();
+ assert(args.size() == 4);
+ mlir::Value refNone =
+ builder
+ .create<fir::AbsentOp>(loc, builder.getRefType(builder.getI32Type()))
+ .getResult();
+ mlir::Value remoteImage =
+ isStaticallyAbsent(args[1]) ? refNone : fir::getBase(args[1]);
+ mlir::Value status =
+ isStaticallyAbsent(args[2]) ? refNone : fir::getBase(args[2]);
+ mlir::Value errmsg =
+ isStaticallyAbsent(args[3])
+ ? builder.create<fir::AbsentOp>(loc, PRIF_ERRMSG_TYPE).getResult()
+ : fir::getBase(args[3]);
+ fir::runtime::genCoMin(builder, loc, fir::getBase(args[0]), remoteImage,
+ status, errmsg);
+}
+
+// CO_SUM
+void IntrinsicLibrary::genCoSum(llvm::ArrayRef<fir::ExtendedValue> args) {
+ checkCoarrayEnabled();
+ assert(args.size() == 4);
+ mlir::Value absentInt =
+ builder
+ .create<fir::AbsentOp>(loc, builder.getRefType(builder.getI32Type()))
+ .getResult();
+ mlir::Value remoteImage =
+ isStaticallyAbsent(args[1]) ? absentInt : fir::getBase(args[1]);
+ mlir::Value status =
+ isStaticallyAbsent(args[2]) ? absentInt : fir::getBase(args[2]);
+ mlir::Value errmsg =
+ isStaticallyAbsent(args[3])
+ ? builder.create<fir::AbsentOp>(loc, PRIF_ERRMSG_TYPE).getResult()
+ : fir::getBase(args[3]);
+ fir::runtime::genCoSum(builder, loc, fir::getBase(args[0]), remoteImage,
+ status, errmsg);
+}
+
// COMMAND_ARGUMENT_COUNT
fir::ExtendedValue IntrinsicLibrary::genCommandArgumentCount(
mlir::Type resultType, llvm::ArrayRef<fir::ExtendedValue> args) {
diff --git a/flang/lib/Optimizer/Builder/Runtime/Coarray.cpp b/flang/lib/Optimizer/Builder/Runtime/Coarray.cpp
index fb72fc2089e23..ca3052d9206a5 100644
--- a/flang/lib/Optimizer/Builder/Runtime/Coarray.cpp
+++ b/flang/lib/Optimizer/Builder/Runtime/Coarray.cpp
@@ -14,6 +14,24 @@
using namespace Fortran::runtime;
using namespace Fortran::semantics;
+// Most PRIF functions take `errmsg` and `errmsg_alloc` as two optional
+// arguments of intent (out). One is allocatable, the other is not.
+// It is the responsibility of the compiler to ensure that the appropriate
+// optional argument is passed, and at most one must be provided in a given
+// call.
+// Depending on the type of `errmsg`, this function will return the pair
+// corresponding to (`errmsg`, `errmsg_alloc`).
+static std::pair<mlir::Value, mlir::Value>
+genErrmsgPRIF(fir::FirOpBuilder &builder, mlir::Location loc,
+ mlir::Value errmsg) {
+ bool isAllocatableErrmsg = fir::isAllocatableType(errmsg.getType());
+
+ mlir::Value absent = builder.create<fir::AbsentOp>(loc, PRIF_ERRMSG_TYPE);
+ mlir::Value errMsg = isAllocatableErrmsg ? absent : errmsg;
+ mlir::Value errMsgAlloc = isAllocatableErrmsg ? errmsg : absent;
+ return {errMsg, errMsgAlloc};
+}
+
/// Generate Call to runtime prif_init
mlir::Value fir::runtime::genInitCoarray(fir::FirOpBuilder &builder,
mlir::Location loc) {
@@ -84,3 +102,66 @@ mlir::Value fir::runtime::getThisImage(fir::FirOpBuilder &builder,
builder.create<fir::CallOp>(loc, funcOp, args);
return builder.create<fir::LoadOp>(loc, result);
}
+
+/// Generate call to collective subroutines except co_reduce
+/// A must be lowered as a box
+void genCollectiveSubroutine(fir::FirOpBuilder &builder, mlir::Location loc,
+ mlir::Value A, mlir::Value sourceImage,
+ mlir::Value stat, mlir::Value errmsg,
+ std::string coName) {
+ mlir::Type boxTy = fir::BoxType::get(builder.getNoneType());
+ mlir::FunctionType ftype =
+ PRIF_FUNCTYPE(boxTy, builder.getRefType(builder.getI32Type()),
+ PRIF_STAT_TYPE, PRIF_ERRMSG_TYPE, PRIF_ERRMSG_TYPE);
+ mlir::func::FuncOp funcOp = builder.createFunction(loc, coName, ftype);
+
+ auto [errmsgArg, errmsgAllocArg] = genErrmsgPRIF(builder, loc, errmsg);
+ llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
+ builder, loc, ftype, A, sourceImage, stat, errmsgArg, errmsgAllocArg);
+ builder.create<fir::CallOp>(loc, funcOp, args);
+}
+
+/// Generate call to runtime subroutine prif_co_broadcast
+void fir::runtime::genCoBroadcast(fir::FirOpBuilder &builder,
+ mlir::Location loc, mlir::Value A,
+ mlir::Value sourceImage, mlir::Value stat,
+ mlir::Value errmsg) {
+ genCollectiveSubroutine(builder, loc, A, sourceImage, stat, errmsg,
+ PRIFNAME_SUB("co_broadcast"));
+}
+
+/// Generate call to runtime subroutine prif_co_max or prif_co_max_character
+void fir::runtime::genCoMax(fir::FirOpBuilder &builder, mlir::Location loc,
+ mlir::Value A, mlir::Value resultImage,
+ mlir::Value stat, mlir::Value errmsg) {
+ mlir::Type argTy =
+ fir::unwrapSequenceType(fir::unwrapPassByRefType(A.getType()));
+ if (mlir::isa<fir::CharacterType>(argTy))
+ genCollectiveSubroutine(builder, loc, A, resultImage, stat, errmsg,
+ PRIFNAME_SUB("co_max_character"));
+ else
+ genCollectiveSubroutine(builder, loc, A, resultImage, stat, errmsg,
+ PRIFNAME_SUB("co_max"));
+}
+
+/// Generate call to runtime subroutine prif_co_min or prif_co_min_character
+void fir::runtime::genCoMin(fir::FirOpBuilder &builder, mlir::Location loc,
+ mlir::Value A, mlir::Value resultImage,
+ mlir::Value stat, mlir::Value errmsg) {
+ mlir::Type argTy =
+ fir::unwrapSequenceType(fir::unwrapPassByRefType(A.getType()));
+ if (mlir::isa<fir::CharacterType>(argTy))
+ genCollectiveSubroutine(builder, loc, A, resultImage, stat, errmsg,
+ PRIFNAME_SUB("co_min_character"));
+ else
+ genCollectiveSubroutine(builder, loc, A, resultImage, stat, errmsg,
+ PRIFNAME_SUB("co_min"));
+}
+
+/// Generate call to runtime subroutine prif_co_sum
+void fir::runtime::genCoSum(fir::FirOpBuilder &builder, mlir::Location loc,
+ mlir::Value A, mlir::Value resultImage,
+ mlir::Value stat, mlir::Value errmsg) {
+ genCollectiveSubroutine(builder, loc, A, resultImage, stat, errmsg,
+ PRIFNAME_SUB("co_sum"));
+}
diff --git a/flang/test/Lower/Coarray/co_broadcast.f90 b/flang/test/Lower/Coarray/co_broadcast.f90
new file mode 100644
index 0000000000000..be7fdcb99252c
--- /dev/null
+++ b/flang/test/Lower/Coarray/co_broadcast.f90
@@ -0,0 +1,92 @@
+! RUN: %flang_fc1 -emit-hlfir -fcoarray %s -o - | FileCheck %s
+
+program test_co_broadcast
+ integer :: i, array_i(2), status
+ real :: r, array_r(2)
+ double precision :: d, array_d(2)
+ complex :: c, array_c(2)
+ character(len=1) :: message
+
+ ! CHECK: %[[C1_i32:.*]] = arith.constant 1 : i32
+ ! CHECK: %[[V1:.*]] = fir.embox %[[VAR_I:.*]]#0 : (!fir.ref<i32>) -> !fir.box<i32>
+ ! CHECK: fir.store %[[C1_i32]] to %[[IMAGE_RESULT:.*]] : !fir.ref<i32>
+ ! CHECK: %[[V2:.*]] = fir.absent !fir.ref<i32>
+ ! CHECK: %[[V3:.*]] = fir.absent !fir.box<!fir.char<1,?>>
+ ! CHECK: %[[V4:.*]] = fir.absent !fir.box<!fir.char<1,?>>
+ ! CHECK: %[[V5:.*]] = fir.convert %[[V1]] : (!fir.box<i32>) -> !fir.box<none>
+ ! CHECK: fir.call @_QMprifPprif_co_broadcast(%[[V5]], %[[IMAGE_RESULT]], %[[V2]], %[[V3]], %[[V4]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i32>, !fir.ref<i32>, !fir.box<!fir.char<1,?>>, !fir.box<!fir.char<1,?>>) -> ()
+ call co_broadcast(i, source_image=1)
+
+ ! CHECK: %[[C1_i32:.*]] = arith.constant 1 : i32
+ ! CHECK: %[[V1:.*]] = fir.embox %[[VAR_C:.*]]#0 : (!fir.ref<complex<f32>>) -> !fir.box<complex<f32>>
+ ! CHECK: fir.store %[[C1_i32]] to %[[IMAGE_RESULT:.*]] : !fir.ref<i32>
+ ! CHECK: %[[V2:.*]] = fir.absent !fir.box<!fir.char<1,?>>
+ ! CHECK: %[[V3:.*]] = fir.absent !fir.box<!fir.char<1,?>>
+ ! CHECK: %[[V4:.*]] = fir.convert %[[V1]] : (!fir.box<complex<f32>>) -> !fir.box<none>
+ ! CHECK: fir.call @_QMprifPprif_co_broadcast(%[[V4]], %[[IMAGE_RESULT]], %[[STATUS:.*]], %[[V2]], %[[V3]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i32>, !fir.ref<i32>, !fir.box<!fir.char<1,?>>, !fir.box<!fir.char<1,?>>) -> ()
+ call co_broadcast(c, source_image=1, stat=status)
+
+ ! CHECK: %[[C1_i32:.*]] = arith.constant 1 : i32
+ ! CHECK: %[[V1:.*]] = fir.embox %[[VAR_D:.*]]#0 : (!fir.ref<f64>) -> !fir.box<f64>
+ ! CHECK: fir.store %[[C1_i32]] to %[[IMAGE_RESULT:.*]] : !fir.ref<i32>
+ ! CHECK: %[[V2:.*]] = fir.embox %[[MESSAGE:.*]]#0 : (!fir.ref<!fir.char<1>>) -> !fir.box<!fir.char<1>>
+ ! CHECK: %[[V3:.*]] = fir.absent !fir.box<!fir.char<1,?>>
+ ! CHECK: %[[V4:.*]] = fir.convert %[[V1]] : (!fir.box<f64>) -> !fir.box<none>
+ ! CHECK: %[[V5:.*]] = fir.convert %[[V2]] : (!fir.box<!fir.char<1>>) -> !fir.box<!fir.char<1,?>>
+ ! CHECK: fir.call @_QMprifPprif_co_broadcast(%[[V4]], %[[IMAGE_RESULT]], %[[STATUS]], %[[V5]], %[[V3]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i32>, !fir.ref<i32>, !fir.box<!fir.char<1,?>>, !fir.box<!fir.char<1,?>>) -> ()
+ call co_broadcast(d, source_image=1, stat=status, errmsg=message)
+
+ ! CHECK: %[[C1_i32:.*]] = arith.constant 1 : i32
+ ! CHECK: %[[V1:.*]] = fir.embox %[[VAR_R:.*]]#0 : (!fir.ref<f32>) -> !fir.box<f32>
+ ! CHECK: fir.store %[[C1_i32]] to %[[IMAGE_RESULT:.*]] : !fir.ref<i32>
+ ! CHECK: %[[V2:.*]] = fir.embox %[[MESSAGE]]#0 : (!fir.ref<!fir.char<1>>) -> !fir.box<!fir.char<1>>
+ ! CHECK: %[[V3:.*]] = fir.absent !fir.box<!fir.char<1,?>>
+ ! CHECK: %[[V4:.*]] = fir.convert %[[V1]] : (!fir.box<f32>) -> !fir.box<none>
+ ! CHECK: %[[V5:.*]] = fir.convert %[[V2]] : (!fir.box<!fir.char<1>>) -> !fir.box<!fir.char<1,?>>
+ ! CHECK: fir.call @_QMprifPprif_co_broadcast(%[[V4]], %[[IMAGE_RESULT]], %[[STATUS]], %[[V5]], %[[V3]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i32>, !fir.ref<i32>, !fir.box<!fir.char<1,?>>, !fir.box<!fir.char<1,?>>) -> ()
+ call co_broadcast(r, source_image=1, stat=status, errmsg=message)
+
+ ! CHECK: %[[C1_i32:.*]] = arith.constant 1 : i32
+ ! CHECK: %[[SHAPE_2:.*]] = fir.shape %[[C2_2:.*]] : (index) -> !fir.shape<1>
+ ! CHECK: %[[V1:.*]] = fir.embox %[[ARRAY_I:.*]]#0(%[[SHAPE_2]]) : (!fir.ref<!fir.array<2xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<2xi32>>
+ ! CHECK: fir.store %[[C1_i32]] to %[[IMAGE_RESULT:.*]] : !fir.ref<i32>
+ ! CHECK: %[[V2:.*]] = fir.absent !fir.ref<i32>
+ ! CHECK: %[[V3:.*]] = fir.absent !fir.box<!fir.char<1,?>>
+ ! CHECK: %[[V4:.*]] = fir.absent !fir.box<!fir.char<1,?>>
+ ! CHECK: %[[V5:.*]] = fir.convert %[[V1]] : (!fir.box<!fir.array<2xi32>>) -> !fir.box<none>
+ ! CHECK: fir.call @_QMprifPprif_co_broadcast(%[[V5]], %[[IMAGE_RESULT]], %[[V2]], %[[V3]], %[[V4]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i32>, !fir.ref<i32>, !fir.box<!fir.char<1,?>>, !fir.box<!fir.char<1,?>>) -> ()
+ call co_broadcast(array_i, source_image=1)
+
+ ! CHECK: %[[C1_i32:.*]] = arith.constant 1 : i32
+ ! CHECK: %[[SHAPE_2:.*]] = fir.shape %[[C2_2:.*]] : (index) -> !fir.shape<1>
+ ! CHECK: %[[V1:.*]] = fir.embox %[[ARRAY_C:.*]]#0(%[[SHAPE_2]]) : (!fir.ref<!fir.array<2xcomplex<f32>>>, !fir.shape<1>) -> !fir.box<!fir.array<2xcomplex<f32>>>
+ ! CHECK: fir.store %[[C1_i32]] to %[[IMAGE_RESULT:.*]] : !fir.ref<i32>
+ ! CHECK: %[[V2:.*]] = fir.absent !fir.ref<i32>
+ ! CHECK: %[[V3:.*]] = fir.absent !fir.box<!fir.char<1,?>>
+ ! CHECK: %[[V4:.*]] = fir.absent !fir.box<!fir.char<1,?>>
+ ! CHECK: %[[V5:.*]] = fir.convert %[[V1]] : (!fir.box<!fir.array<2xcomplex<f32>>>) -> !fir.box<none>
+ ! CHECK: fir.call @_QMprifPprif_co_broadcast(%[[V5]], %[[IMAGE_RESULT]], %[[V2]], %[[V3]], %[[V4]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i32>, !fir.ref<i32>, !fir.box<!fir.char<1,?>>, !fir.box<!fir.char<1,?>>) -> ()
+ call co_broadcast(array_c, source_image=1)
+
+ ! CHECK: %[[C1_i32:.*]] = arith.constant 1 : i32
+ ! CHECK: %[[SHAPE_2:.*]] = fir.shape %[[C2_2:.*]] : (index) -> !fir.shape<1>
+ ! CHECK: %[[V1:.*]] = fir.embox %[[ARRAY_D:.*]]#0(%[[SHAPE_2]]) : (!fir.ref<!fir.array<2xf64>>, !fir.shape<1>) -> !fir.box<!fir.array<2xf64>>
+ ! CHECK: fir.store %[[C1_i32]] to %[[IMAGE_RESULT:.*]] : !fir.ref<i32>
+ ! CHECK: %[[V2:.*]] = fir.absent !fir.box<!fir.char<1,?>>
+ ! CHECK: %[[V3:.*]] = fir.absent !fir.box<!fir.char<1,?>>
+ ! CHECK: %[[V4:.*]] = fir.convert %[[V1]] : (!fir.box<!fir.array<2xf64>>) -> !fir.box<none>
+ ! CHECK: fir.call @_QMprifPprif_co_broadcast(%[[V4]], %[[IMAGE_RESULT]], %[[STATUS]], %[[V2]], %[[V3]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i32>, !fir.ref<i32>, !fir.box<!fir.char<1,?>>, !fir.box<!fir.char<1,?>>) -> ()
+ call co_broadcast(array_d, source_image=1, stat=status)
+
+ ! CHECK: %[[C1_i32:.*]] = arith.constant 1 : i32
+ ! CHECK: %[[SHAPE_2:.*]] = fir.shape %[[C2_2:.*]] : (index) -> !fir.shape<1>
+ ! CHECK: %[[V1:.*]] = fir.embox %[[ARRAY_C:.*]]#0(%[[SHAPE_2]]) : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<2xf32>>
+ ! CHECK: fir.store %[[C1_i32]] to %[[IMAGE_RESULT:.*]] : !fir.ref<i32>
+ ! CHECK: %[[V2:.*]] = fir.embox %[[MESSAGE]]#0 : (!fir.ref<!fir.char<1>>) -> !fir.box<!fir.char<1>>
+ ! CHECK: %[[V3:.*]] = fir.absent !fir.box<!fir.char<1,?>>
+ ! CHECK: %[[V4:.*]] = fir.convert %[[V1]] : (!fir.box<!fir.array<2xf32>>) -> !fir.box<none>
+ ! CHECK: %[[V5:.*]] = fir.convert %[[V2]] : (!fir.box<!fir.char<1>>) -> !fir.box<!fir.char<1,?>>
+ ! CHECK: fir.call @_QMprifPprif_co_broadcast(%[[V4]], %[[IMAGE_RESULT]], %[[STATUS]], %[[V5]], %[[V3]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i32>, !fir.ref<i32>, !fir.box<!fir.char<1,?>>, !fir.box<!fir.char<1,?>>) -> ()
+ call co_broadcast(array_r, source_image=1, stat= status, errmsg=message)
+
+end program
diff --git a/flang/test/Lower/Coarray/co_max.f90 b/flang/test/Lower/Coarray/co_max.f90
new file mode 100644
index 0000000000000..56d863389d02b
--- /dev/null...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/154770
More information about the flang-commits
mailing list