-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[flang][Multi-Image] Moving Mutli-image lowering to PRIF into the MIF dialect #161179
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-driver Author: Jean-Didier PAILLEUX (JDPailleux) ChangesSupport for multi-image features has begun to be integrated into LLVM. A new dialect which simplifies lowering to PRIF wil be proposed in this PR. Features like TEAMs and the use of coarrays will follow later in other PRs. Patch is 231.27 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/161179.diff 59 Files Affected:
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Coarray.h b/flang/include/flang/Optimizer/Builder/Runtime/Coarray.h
deleted file mode 100644
index 20bfb7c124af2..0000000000000
--- a/flang/include/flang/Optimizer/Builder/Runtime/Coarray.h
+++ /dev/null
@@ -1,85 +0,0 @@
-//===-- Coarray.h -- generate Coarray intrinsics runtime calls --*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef FORTRAN_OPTIMIZER_BUILDER_RUNTIME_COARRAY_H
-#define FORTRAN_OPTIMIZER_BUILDER_RUNTIME_COARRAY_H
-
-#include "flang/Lower/AbstractConverter.h"
-#include "flang/Optimizer/Support/InternalNames.h"
-#include "mlir/Dialect/Func/IR/FuncOps.h"
-
-namespace fir {
-class ExtendedValue;
-class FirOpBuilder;
-} // namespace fir
-
-namespace fir::runtime {
-
-// Get the function type for a prif subroutine with a variable number of
-// arguments
-#define PRIF_FUNCTYPE(...) \
- mlir::FunctionType::get(builder.getContext(), /*inputs*/ {__VA_ARGS__}, \
- /*result*/ {})
-
-// Default prefix for subroutines of PRIF compiled with LLVM
-#define PRIFNAME_SUB(fmt) \
- []() { \
- std::ostringstream oss; \
- oss << "prif_" << fmt; \
- 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);
-
-/// Generate Call to runtime prif_num_images
-mlir::Value getNumImages(fir::FirOpBuilder &builder, mlir::Location loc);
-
-/// Generate Call to runtime prif_num_images_with_team or
-/// prif_num_images_with_team_number
-mlir::Value getNumImagesWithTeam(fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::Value team);
-
-/// Generate Call to runtime prif_this_image_no_coarray
-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);
-
-/// Generate call to runtime subroutine prif_sync_all
-void genSyncAllStatement(fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::Value stat, mlir::Value errmsg);
-/// Generate call to runtime subroutine prif_sync_memory
-void genSyncMemoryStatement(fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::Value stat, mlir::Value errmsg);
-/// Generate call to runtime subroutine prif_sync_images
-void genSyncImagesStatement(fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::Value imageSet, mlir::Value stat,
- mlir::Value errmsg);
-} // namespace fir::runtime
-#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_COARRAY_H
diff --git a/flang/include/flang/Optimizer/Dialect/CMakeLists.txt b/flang/include/flang/Optimizer/Dialect/CMakeLists.txt
index adefcfea0b5dc..7b1a12932276a 100644
--- a/flang/include/flang/Optimizer/Dialect/CMakeLists.txt
+++ b/flang/include/flang/Optimizer/Dialect/CMakeLists.txt
@@ -1,5 +1,6 @@
add_subdirectory(CUF)
add_subdirectory(FIRCG)
+add_subdirectory(MIF)
# This replicates part of the add_mlir_dialect cmake function from MLIR that
# cannot be used her because it expects to be run inside MLIR directory which
diff --git a/flang/include/flang/Optimizer/Dialect/MIF/CMakeLists.txt b/flang/include/flang/Optimizer/Dialect/MIF/CMakeLists.txt
new file mode 100644
index 0000000000000..27ba3889c8045
--- /dev/null
+++ b/flang/include/flang/Optimizer/Dialect/MIF/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(LLVM_TARGET_DEFINITIONS MIFDialect.td)
+mlir_tablegen(MIFDialect.h.inc -gen-dialect-decls -dialect=mif)
+mlir_tablegen(MIFDialect.cpp.inc -gen-dialect-defs -dialect=mif)
+
+# Add Multi Image Fortran operations
+set(LLVM_TARGET_DEFINITIONS MIFOps.td)
+mlir_tablegen(MIFOps.h.inc -gen-op-decls)
+mlir_tablegen(MIFOps.cpp.inc -gen-op-defs)
+add_public_tablegen_target(MIFOpsIncGen)
diff --git a/flang/include/flang/Optimizer/Dialect/MIF/MIFDialect.h b/flang/include/flang/Optimizer/Dialect/MIF/MIFDialect.h
new file mode 100644
index 0000000000000..f862d9175a6ae
--- /dev/null
+++ b/flang/include/flang/Optimizer/Dialect/MIF/MIFDialect.h
@@ -0,0 +1,31 @@
+//===- MIF.h - MIF dialect --------------------------------*- C++-*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_OPTIMIZER_DIALECT_MIF_MIF_H
+#define FORTRAN_OPTIMIZER_DIALECT_MIF_MIF_H
+
+#include "mlir/Bytecode/BytecodeOpInterface.h"
+#include "mlir/IR/Dialect.h"
+#include "mlir/IR/OpDefinition.h"
+#include "mlir/IR/OpImplementation.h"
+#include "mlir/IR/SymbolTable.h"
+#include "mlir/Interfaces/CallInterfaces.h"
+#include "mlir/Interfaces/InferTypeOpInterface.h"
+#include "mlir/Interfaces/SideEffectInterfaces.h"
+#include "mlir/Interfaces/VectorInterfaces.h"
+
+// #include "flang/Optimizer/Dialect/FIRAttr.h"
+// #include "flang/Optimizer/Dialect/FIRType.h"
+
+//===----------------------------------------------------------------------===//
+// MIFDialect
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Dialect/MIF/MIFDialect.h.inc"
+
+#endif // FORTRAN_OPTIMIZER_DIALECT_MIF_MIF_H
diff --git a/flang/include/flang/Optimizer/Dialect/MIF/MIFDialect.td b/flang/include/flang/Optimizer/Dialect/MIF/MIFDialect.td
new file mode 100644
index 0000000000000..f8be6a86a79fe
--- /dev/null
+++ b/flang/include/flang/Optimizer/Dialect/MIF/MIFDialect.td
@@ -0,0 +1,38 @@
+//===-- MIFDialect.td - MIF dialect base definitions - tablegen ---------*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Definition of the Multi-Image Fortran (MIF) dialect
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_DIALECT_MIF_MIFDIALECT
+#define FORTRAN_DIALECT_MIF_MIFDIALECT
+
+include "mlir/IR/AttrTypeBase.td"
+include "mlir/IR/EnumAttr.td"
+include "mlir/IR/OpBase.td"
+
+def MIFDialect : Dialect {
+ let name = "mif";
+
+ let summary = "Multi-Image Fortran dialect";
+
+ let description = [{
+ The "MIF" dialect is designed to contain the basic coarray operations
+ in Fortran and all multi image operations as descibed in the standard.
+ This includes synchronization operations, atomic operations,
+ image queries, teams, criticals, etc. The MIF dialect operations use
+ the FIR types and are tightly coupled with FIR and HLFIR.
+ }];
+
+ let cppNamespace = "::mif";
+ let dependentDialects = ["fir::FIROpsDialect"];
+}
+
+#endif // FORTRAN_DIALECT_MIF_MIFDIALECT
diff --git a/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.h b/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.h
new file mode 100644
index 0000000000000..a9e53c21171c4
--- /dev/null
+++ b/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.h
@@ -0,0 +1,20 @@
+//===-- Optimizer/Dialect/MIF/MIFOps.h - MIF operations ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_OPTIMIZER_DIALECT_MIF_MIFOPS_H
+#define FORTRAN_OPTIMIZER_DIALECT_MIF_MIFOPS_H
+
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/MIF/MIFDialect.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/IR/OpDefinition.h"
+
+#define GET_OP_CLASSES
+#include "flang/Optimizer/Dialect/MIF/MIFOps.h.inc"
+
+#endif // FORTRAN_OPTIMIZER_DIALECT_MIF_MIFOPS_H
diff --git a/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td b/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td
new file mode 100644
index 0000000000000..115ef0c65a76f
--- /dev/null
+++ b/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td
@@ -0,0 +1,274 @@
+//===-- MIFOps.td - MIF operation definitions ------*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Definition of the MIF dialect operations
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_DIALECT_MIF_MIF_OPS
+#define FORTRAN_DIALECT_MIF_MIF_OPS
+
+include "flang/Optimizer/Dialect/MIF/MIFDialect.td"
+include "flang/Optimizer/Dialect/FIRTypes.td"
+include "flang/Optimizer/Dialect/FIRAttr.td"
+include "mlir/Dialect/LLVMIR/LLVMAttrDefs.td"
+include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
+include "mlir/Interfaces/LoopLikeInterface.td"
+include "mlir/IR/BuiltinAttributes.td"
+
+class mif_Op<string mnemonic, list<Trait> traits>
+ : Op<MIFDialect, mnemonic, traits>;
+
+//===----------------------------------------------------------------------===//
+// Initialization and Finalization
+//===----------------------------------------------------------------------===//
+
+def mif_InitOp : mif_Op<"init", []> {
+ let summary = "Initialize the parallel environment";
+ let description = [{This operation will initialize the parallel environment}];
+
+ let results = (outs I32:$stat);
+ let assemblyFormat = "`->` type($stat) attr-dict";
+}
+
+//===----------------------------------------------------------------------===//
+// Image Queries
+//===----------------------------------------------------------------------===//
+
+def mif_NumImagesOp
+ : mif_Op<"num_images", [NoMemoryEffect, AttrSizedOperandSegments]> {
+ let summary = "Query the number of images in the specified or current team";
+ let description = [{
+ This operation query the number of images in the specified or current
+ team and can be called with 3 differents way :
+ - `num_images()`
+ - `num_images(team)`
+ - `num_images(team_number)`
+
+ Arguments:
+ - `team` : Shall be a scalar of type `team_type` from the `ISO_FORTRAN_ENV`
+ module with a value that identifies the current or ancestor team.
+ - `team_number` : Shall be an integer scalar. It shall identify the
+ initial team or a sibling team of the current team.
+
+ Result Value: The number of images in the specified team, or in the current
+ team if no team is specified.
+ }];
+
+ let arguments = (ins Optional<AnyInteger>:$team_number,
+ Optional<AnyRefOrBoxType>:$team);
+ let results = (outs I32:$res);
+
+ let builders = [OpBuilder<(ins CArg<"mlir::Value", "{}">:$teamArg)>];
+
+ let hasVerifier = 1;
+ let assemblyFormat = [{
+ ( `team_number` `(` $team_number^ `:` type($team_number) `)` )?
+ ( `team` `(` $team^ `:` type($team) `)` )?
+ attr-dict `->` type($res)
+ }];
+}
+
+def mif_ThisImageOp
+ : mif_Op<"this_image", [NoMemoryEffect, AttrSizedOperandSegments]> {
+ let summary = "Determine the image index of the current image";
+ let description = [{
+ Arguments:
+ - `coarray` : Shall be a coarray of any type.
+ - `dim` : Shall be an integer scalar. Its value shall be in the range of
+ 1 <= DIM <= N, where N is the corank of the coarray.
+ - `team`(optional) : Shall be a scalar of type `team_type` from
+ ISO_FORTRAN_ENV. If the `coarray` is present, it shall be
+ established in that team.
+
+ Results:
+ - Case(1) : The result of `this_image([team])` is a scalar with a value
+ equal to the index of the image in the current or specified team.
+ - Case(2) : The result of `this_image(coarray [,team])` is the sequence of
+ cosubscript values for `coarray`.
+ - Case(3) : The result of `this_image(coarray, dim [,team])` is the value of
+ cosubscript `dim` in the sequence of cosubscript values for `coarray`.
+
+ Example:
+ ```fortran
+ REAL :: A[10, 0:9, 0:*]
+ ```
+ If we take a look on the example and we are on image 5, `this_image` has the
+ value 5, `this_image(A)` has the value [5, 0, 0].
+ }];
+
+ let arguments = (ins Optional<fir_BoxType>:$coarray,
+ Optional<AnyInteger>:$dim, Optional<fir_BoxType>:$team);
+ let results = (outs I32:$res);
+
+ let builders = [OpBuilder<(ins "mlir::Value":$coarray, "mlir::Value":$team)>,
+ OpBuilder<(ins "mlir::Value":$team)>];
+
+ let hasVerifier = 1;
+ let assemblyFormat = [{
+ ( `coarray` `(` $coarray^ `:` type($coarray) `)` )?
+ ( `team` `(` $team^ `:` type($team) `)` )?
+ ( `dim` `(` $dim^ `:` type($dim) `)` )?
+ attr-dict `->` type($res)
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// Synchronization
+//===----------------------------------------------------------------------===//
+
+def mif_SyncAllOp : mif_Op<"sync_all", [AttrSizedOperandSegments,
+ MemoryEffects<[MemWrite]>]> {
+ let summary =
+ "Performs a collective synchronization of all images in the current team";
+
+ let arguments = (ins Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+ Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg);
+ let assemblyFormat = [{
+ (`stat` `(` $stat^ `:` type($stat) `)` )?
+ (`errmsg` `(` $errmsg^ `:` type($errmsg) `)` )?
+ attr-dict
+ }];
+}
+
+def mif_SyncImagesOp : mif_Op<"sync_images", [AttrSizedOperandSegments,
+ MemoryEffects<[MemWrite]>]> {
+ let summary = "Performs a synchronization of image with each of the other "
+ "images in the `image_set`";
+ let description = [{
+ This operation can take an optional argument `image_set`, wich must be an integer expression
+ and must be scalar or rank one. If `image_set` is omitted from the call, this operation will
+ adopt the behavior of the Fortran statement `SYNC IMAGES(*)`.
+ }];
+
+ let arguments = (ins Optional<AnyRefOrBoxType>:$image_set,
+ Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+ Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg);
+ let hasVerifier = 1;
+ let assemblyFormat = [{
+ (`image_set` `(` $image_set^ `:` type($image_set) `)` )?
+ (`stat` `(` $stat^ `:` type($stat) `)` )?
+ (`errmsg` `(` $errmsg^ `:` type($errmsg) `)` )?
+ attr-dict
+ }];
+}
+
+def mif_SyncMemoryOp : mif_Op<"sync_memory", [AttrSizedOperandSegments,
+ MemoryEffects<[MemWrite]>]> {
+ let summary = "Operation that ends one segment and begins another.";
+ let description = [{
+ Operation that ends one segment and begins another; Those two segments can
+ be ordered by user-defined way with respect to segments on other images.
+ }];
+
+ let arguments = (ins Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+ Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg);
+ let assemblyFormat = [{
+ (`stat` `(` $stat^ `:` type($stat) `)` )?
+ (`errmsg` `(` $errmsg^ `:` type($errmsg) `)` )?
+ attr-dict
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// Collective Operations
+//===----------------------------------------------------------------------===//
+
+def mif_CoBroadcastOp : mif_Op<"co_broadcast", [AttrSizedOperandSegments,
+ MemoryEffects<[MemWrite]>]> {
+ let summary = "Broadcast value to images.";
+ let description = [{
+ The co_broadcast operation performs the computation of the sum
+ across images.
+ }];
+
+ let arguments = (ins fir_BoxType:$a,
+ AnyIntegerType:$source_image,
+ Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+ Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg);
+
+ let assemblyFormat = [{
+ $a `:` qualified(type($a))
+ `source` `(` $source_image `:` type($source_image) `)`
+ (`stat` `(` $stat^ `:` type($stat) `)` )?
+ (`errmsg` `(` $errmsg^ `:` type($errmsg) `)` )?
+ attr-dict
+ }];
+}
+
+def mif_CoMaxOp
+ : mif_Op<"co_max", [AttrSizedOperandSegments, MemoryEffects<[MemWrite]>]> {
+ let summary = "Compute maximum value across images.";
+ let description = [{
+ The co_max operation performs the computation of the maximum
+ across images.
+ }];
+
+ let arguments = (ins fir_BoxType:$a,
+ Optional<AnyIntegerType>:$result_image,
+ Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+ Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg);
+
+ let hasVerifier = 1;
+ let assemblyFormat = [{
+ $a `:` qualified(type($a))
+ (`result` `(` $result_image^ `:` type($result_image) `)` )?
+ (`stat` `(` $stat^ `:` type($stat) `)` )?
+ (`errmsg` `(` $errmsg^ `:` type($errmsg) `)` )?
+ attr-dict
+ }];
+}
+
+def mif_CoMinOp
+ : mif_Op<"co_min", [AttrSizedOperandSegments, MemoryEffects<[MemWrite]>]> {
+ let summary = "Compute minimum value across images.";
+ let description = [{
+ The co_min operation performs the computation of the minimum
+ across images.
+ }];
+
+ let arguments = (ins fir_BoxType:$a,
+ Optional<AnyIntegerType>:$result_image,
+ Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+ Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg);
+
+ let hasVerifier = 1;
+ let assemblyFormat = [{
+ $a `:` qualified(type($a))
+ (`result` `(` $result_image^ `:` type($result_image) `)` )?
+ (`stat` `(` $stat^ `:` type($stat) `)` )?
+ (`errmsg` `(` $errmsg^ `:` type($errmsg) `)` )?
+ attr-dict
+ }];
+}
+
+def mif_CoSumOp
+ : mif_Op<"co_sum", [AttrSizedOperandSegments, MemoryEffects<[MemWrite]>]> {
+ let summary = "Compute sum across images.";
+ let description = [{
+ The co_sum operation performs the computation of the sum
+ across images.
+ }];
+
+ let arguments = (ins fir_BoxType:$a,
+ Optional<AnyIntegerType>:$result_image,
+ Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+ Arg<Optional<Any...
[truncated]
|
@llvm/pr-subscribers-flang-fir-hlfir Author: Jean-Didier PAILLEUX (JDPailleux) ChangesSupport for multi-image features has begun to be integrated into LLVM. A new dialect which simplifies lowering to PRIF wil be proposed in this PR. Features like TEAMs and the use of coarrays will follow later in other PRs. Patch is 231.27 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/161179.diff 59 Files Affected:
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Coarray.h b/flang/include/flang/Optimizer/Builder/Runtime/Coarray.h
deleted file mode 100644
index 20bfb7c124af2..0000000000000
--- a/flang/include/flang/Optimizer/Builder/Runtime/Coarray.h
+++ /dev/null
@@ -1,85 +0,0 @@
-//===-- Coarray.h -- generate Coarray intrinsics runtime calls --*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef FORTRAN_OPTIMIZER_BUILDER_RUNTIME_COARRAY_H
-#define FORTRAN_OPTIMIZER_BUILDER_RUNTIME_COARRAY_H
-
-#include "flang/Lower/AbstractConverter.h"
-#include "flang/Optimizer/Support/InternalNames.h"
-#include "mlir/Dialect/Func/IR/FuncOps.h"
-
-namespace fir {
-class ExtendedValue;
-class FirOpBuilder;
-} // namespace fir
-
-namespace fir::runtime {
-
-// Get the function type for a prif subroutine with a variable number of
-// arguments
-#define PRIF_FUNCTYPE(...) \
- mlir::FunctionType::get(builder.getContext(), /*inputs*/ {__VA_ARGS__}, \
- /*result*/ {})
-
-// Default prefix for subroutines of PRIF compiled with LLVM
-#define PRIFNAME_SUB(fmt) \
- []() { \
- std::ostringstream oss; \
- oss << "prif_" << fmt; \
- 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);
-
-/// Generate Call to runtime prif_num_images
-mlir::Value getNumImages(fir::FirOpBuilder &builder, mlir::Location loc);
-
-/// Generate Call to runtime prif_num_images_with_team or
-/// prif_num_images_with_team_number
-mlir::Value getNumImagesWithTeam(fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::Value team);
-
-/// Generate Call to runtime prif_this_image_no_coarray
-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);
-
-/// Generate call to runtime subroutine prif_sync_all
-void genSyncAllStatement(fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::Value stat, mlir::Value errmsg);
-/// Generate call to runtime subroutine prif_sync_memory
-void genSyncMemoryStatement(fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::Value stat, mlir::Value errmsg);
-/// Generate call to runtime subroutine prif_sync_images
-void genSyncImagesStatement(fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::Value imageSet, mlir::Value stat,
- mlir::Value errmsg);
-} // namespace fir::runtime
-#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_COARRAY_H
diff --git a/flang/include/flang/Optimizer/Dialect/CMakeLists.txt b/flang/include/flang/Optimizer/Dialect/CMakeLists.txt
index adefcfea0b5dc..7b1a12932276a 100644
--- a/flang/include/flang/Optimizer/Dialect/CMakeLists.txt
+++ b/flang/include/flang/Optimizer/Dialect/CMakeLists.txt
@@ -1,5 +1,6 @@
add_subdirectory(CUF)
add_subdirectory(FIRCG)
+add_subdirectory(MIF)
# This replicates part of the add_mlir_dialect cmake function from MLIR that
# cannot be used her because it expects to be run inside MLIR directory which
diff --git a/flang/include/flang/Optimizer/Dialect/MIF/CMakeLists.txt b/flang/include/flang/Optimizer/Dialect/MIF/CMakeLists.txt
new file mode 100644
index 0000000000000..27ba3889c8045
--- /dev/null
+++ b/flang/include/flang/Optimizer/Dialect/MIF/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(LLVM_TARGET_DEFINITIONS MIFDialect.td)
+mlir_tablegen(MIFDialect.h.inc -gen-dialect-decls -dialect=mif)
+mlir_tablegen(MIFDialect.cpp.inc -gen-dialect-defs -dialect=mif)
+
+# Add Multi Image Fortran operations
+set(LLVM_TARGET_DEFINITIONS MIFOps.td)
+mlir_tablegen(MIFOps.h.inc -gen-op-decls)
+mlir_tablegen(MIFOps.cpp.inc -gen-op-defs)
+add_public_tablegen_target(MIFOpsIncGen)
diff --git a/flang/include/flang/Optimizer/Dialect/MIF/MIFDialect.h b/flang/include/flang/Optimizer/Dialect/MIF/MIFDialect.h
new file mode 100644
index 0000000000000..f862d9175a6ae
--- /dev/null
+++ b/flang/include/flang/Optimizer/Dialect/MIF/MIFDialect.h
@@ -0,0 +1,31 @@
+//===- MIF.h - MIF dialect --------------------------------*- C++-*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_OPTIMIZER_DIALECT_MIF_MIF_H
+#define FORTRAN_OPTIMIZER_DIALECT_MIF_MIF_H
+
+#include "mlir/Bytecode/BytecodeOpInterface.h"
+#include "mlir/IR/Dialect.h"
+#include "mlir/IR/OpDefinition.h"
+#include "mlir/IR/OpImplementation.h"
+#include "mlir/IR/SymbolTable.h"
+#include "mlir/Interfaces/CallInterfaces.h"
+#include "mlir/Interfaces/InferTypeOpInterface.h"
+#include "mlir/Interfaces/SideEffectInterfaces.h"
+#include "mlir/Interfaces/VectorInterfaces.h"
+
+// #include "flang/Optimizer/Dialect/FIRAttr.h"
+// #include "flang/Optimizer/Dialect/FIRType.h"
+
+//===----------------------------------------------------------------------===//
+// MIFDialect
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Dialect/MIF/MIFDialect.h.inc"
+
+#endif // FORTRAN_OPTIMIZER_DIALECT_MIF_MIF_H
diff --git a/flang/include/flang/Optimizer/Dialect/MIF/MIFDialect.td b/flang/include/flang/Optimizer/Dialect/MIF/MIFDialect.td
new file mode 100644
index 0000000000000..f8be6a86a79fe
--- /dev/null
+++ b/flang/include/flang/Optimizer/Dialect/MIF/MIFDialect.td
@@ -0,0 +1,38 @@
+//===-- MIFDialect.td - MIF dialect base definitions - tablegen ---------*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Definition of the Multi-Image Fortran (MIF) dialect
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_DIALECT_MIF_MIFDIALECT
+#define FORTRAN_DIALECT_MIF_MIFDIALECT
+
+include "mlir/IR/AttrTypeBase.td"
+include "mlir/IR/EnumAttr.td"
+include "mlir/IR/OpBase.td"
+
+def MIFDialect : Dialect {
+ let name = "mif";
+
+ let summary = "Multi-Image Fortran dialect";
+
+ let description = [{
+ The "MIF" dialect is designed to contain the basic coarray operations
+ in Fortran and all multi image operations as descibed in the standard.
+ This includes synchronization operations, atomic operations,
+ image queries, teams, criticals, etc. The MIF dialect operations use
+ the FIR types and are tightly coupled with FIR and HLFIR.
+ }];
+
+ let cppNamespace = "::mif";
+ let dependentDialects = ["fir::FIROpsDialect"];
+}
+
+#endif // FORTRAN_DIALECT_MIF_MIFDIALECT
diff --git a/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.h b/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.h
new file mode 100644
index 0000000000000..a9e53c21171c4
--- /dev/null
+++ b/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.h
@@ -0,0 +1,20 @@
+//===-- Optimizer/Dialect/MIF/MIFOps.h - MIF operations ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_OPTIMIZER_DIALECT_MIF_MIFOPS_H
+#define FORTRAN_OPTIMIZER_DIALECT_MIF_MIFOPS_H
+
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/MIF/MIFDialect.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/IR/OpDefinition.h"
+
+#define GET_OP_CLASSES
+#include "flang/Optimizer/Dialect/MIF/MIFOps.h.inc"
+
+#endif // FORTRAN_OPTIMIZER_DIALECT_MIF_MIFOPS_H
diff --git a/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td b/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td
new file mode 100644
index 0000000000000..115ef0c65a76f
--- /dev/null
+++ b/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td
@@ -0,0 +1,274 @@
+//===-- MIFOps.td - MIF operation definitions ------*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Definition of the MIF dialect operations
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_DIALECT_MIF_MIF_OPS
+#define FORTRAN_DIALECT_MIF_MIF_OPS
+
+include "flang/Optimizer/Dialect/MIF/MIFDialect.td"
+include "flang/Optimizer/Dialect/FIRTypes.td"
+include "flang/Optimizer/Dialect/FIRAttr.td"
+include "mlir/Dialect/LLVMIR/LLVMAttrDefs.td"
+include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
+include "mlir/Interfaces/LoopLikeInterface.td"
+include "mlir/IR/BuiltinAttributes.td"
+
+class mif_Op<string mnemonic, list<Trait> traits>
+ : Op<MIFDialect, mnemonic, traits>;
+
+//===----------------------------------------------------------------------===//
+// Initialization and Finalization
+//===----------------------------------------------------------------------===//
+
+def mif_InitOp : mif_Op<"init", []> {
+ let summary = "Initialize the parallel environment";
+ let description = [{This operation will initialize the parallel environment}];
+
+ let results = (outs I32:$stat);
+ let assemblyFormat = "`->` type($stat) attr-dict";
+}
+
+//===----------------------------------------------------------------------===//
+// Image Queries
+//===----------------------------------------------------------------------===//
+
+def mif_NumImagesOp
+ : mif_Op<"num_images", [NoMemoryEffect, AttrSizedOperandSegments]> {
+ let summary = "Query the number of images in the specified or current team";
+ let description = [{
+ This operation query the number of images in the specified or current
+ team and can be called with 3 differents way :
+ - `num_images()`
+ - `num_images(team)`
+ - `num_images(team_number)`
+
+ Arguments:
+ - `team` : Shall be a scalar of type `team_type` from the `ISO_FORTRAN_ENV`
+ module with a value that identifies the current or ancestor team.
+ - `team_number` : Shall be an integer scalar. It shall identify the
+ initial team or a sibling team of the current team.
+
+ Result Value: The number of images in the specified team, or in the current
+ team if no team is specified.
+ }];
+
+ let arguments = (ins Optional<AnyInteger>:$team_number,
+ Optional<AnyRefOrBoxType>:$team);
+ let results = (outs I32:$res);
+
+ let builders = [OpBuilder<(ins CArg<"mlir::Value", "{}">:$teamArg)>];
+
+ let hasVerifier = 1;
+ let assemblyFormat = [{
+ ( `team_number` `(` $team_number^ `:` type($team_number) `)` )?
+ ( `team` `(` $team^ `:` type($team) `)` )?
+ attr-dict `->` type($res)
+ }];
+}
+
+def mif_ThisImageOp
+ : mif_Op<"this_image", [NoMemoryEffect, AttrSizedOperandSegments]> {
+ let summary = "Determine the image index of the current image";
+ let description = [{
+ Arguments:
+ - `coarray` : Shall be a coarray of any type.
+ - `dim` : Shall be an integer scalar. Its value shall be in the range of
+ 1 <= DIM <= N, where N is the corank of the coarray.
+ - `team`(optional) : Shall be a scalar of type `team_type` from
+ ISO_FORTRAN_ENV. If the `coarray` is present, it shall be
+ established in that team.
+
+ Results:
+ - Case(1) : The result of `this_image([team])` is a scalar with a value
+ equal to the index of the image in the current or specified team.
+ - Case(2) : The result of `this_image(coarray [,team])` is the sequence of
+ cosubscript values for `coarray`.
+ - Case(3) : The result of `this_image(coarray, dim [,team])` is the value of
+ cosubscript `dim` in the sequence of cosubscript values for `coarray`.
+
+ Example:
+ ```fortran
+ REAL :: A[10, 0:9, 0:*]
+ ```
+ If we take a look on the example and we are on image 5, `this_image` has the
+ value 5, `this_image(A)` has the value [5, 0, 0].
+ }];
+
+ let arguments = (ins Optional<fir_BoxType>:$coarray,
+ Optional<AnyInteger>:$dim, Optional<fir_BoxType>:$team);
+ let results = (outs I32:$res);
+
+ let builders = [OpBuilder<(ins "mlir::Value":$coarray, "mlir::Value":$team)>,
+ OpBuilder<(ins "mlir::Value":$team)>];
+
+ let hasVerifier = 1;
+ let assemblyFormat = [{
+ ( `coarray` `(` $coarray^ `:` type($coarray) `)` )?
+ ( `team` `(` $team^ `:` type($team) `)` )?
+ ( `dim` `(` $dim^ `:` type($dim) `)` )?
+ attr-dict `->` type($res)
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// Synchronization
+//===----------------------------------------------------------------------===//
+
+def mif_SyncAllOp : mif_Op<"sync_all", [AttrSizedOperandSegments,
+ MemoryEffects<[MemWrite]>]> {
+ let summary =
+ "Performs a collective synchronization of all images in the current team";
+
+ let arguments = (ins Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+ Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg);
+ let assemblyFormat = [{
+ (`stat` `(` $stat^ `:` type($stat) `)` )?
+ (`errmsg` `(` $errmsg^ `:` type($errmsg) `)` )?
+ attr-dict
+ }];
+}
+
+def mif_SyncImagesOp : mif_Op<"sync_images", [AttrSizedOperandSegments,
+ MemoryEffects<[MemWrite]>]> {
+ let summary = "Performs a synchronization of image with each of the other "
+ "images in the `image_set`";
+ let description = [{
+ This operation can take an optional argument `image_set`, wich must be an integer expression
+ and must be scalar or rank one. If `image_set` is omitted from the call, this operation will
+ adopt the behavior of the Fortran statement `SYNC IMAGES(*)`.
+ }];
+
+ let arguments = (ins Optional<AnyRefOrBoxType>:$image_set,
+ Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+ Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg);
+ let hasVerifier = 1;
+ let assemblyFormat = [{
+ (`image_set` `(` $image_set^ `:` type($image_set) `)` )?
+ (`stat` `(` $stat^ `:` type($stat) `)` )?
+ (`errmsg` `(` $errmsg^ `:` type($errmsg) `)` )?
+ attr-dict
+ }];
+}
+
+def mif_SyncMemoryOp : mif_Op<"sync_memory", [AttrSizedOperandSegments,
+ MemoryEffects<[MemWrite]>]> {
+ let summary = "Operation that ends one segment and begins another.";
+ let description = [{
+ Operation that ends one segment and begins another; Those two segments can
+ be ordered by user-defined way with respect to segments on other images.
+ }];
+
+ let arguments = (ins Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+ Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg);
+ let assemblyFormat = [{
+ (`stat` `(` $stat^ `:` type($stat) `)` )?
+ (`errmsg` `(` $errmsg^ `:` type($errmsg) `)` )?
+ attr-dict
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// Collective Operations
+//===----------------------------------------------------------------------===//
+
+def mif_CoBroadcastOp : mif_Op<"co_broadcast", [AttrSizedOperandSegments,
+ MemoryEffects<[MemWrite]>]> {
+ let summary = "Broadcast value to images.";
+ let description = [{
+ The co_broadcast operation performs the computation of the sum
+ across images.
+ }];
+
+ let arguments = (ins fir_BoxType:$a,
+ AnyIntegerType:$source_image,
+ Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+ Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg);
+
+ let assemblyFormat = [{
+ $a `:` qualified(type($a))
+ `source` `(` $source_image `:` type($source_image) `)`
+ (`stat` `(` $stat^ `:` type($stat) `)` )?
+ (`errmsg` `(` $errmsg^ `:` type($errmsg) `)` )?
+ attr-dict
+ }];
+}
+
+def mif_CoMaxOp
+ : mif_Op<"co_max", [AttrSizedOperandSegments, MemoryEffects<[MemWrite]>]> {
+ let summary = "Compute maximum value across images.";
+ let description = [{
+ The co_max operation performs the computation of the maximum
+ across images.
+ }];
+
+ let arguments = (ins fir_BoxType:$a,
+ Optional<AnyIntegerType>:$result_image,
+ Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+ Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg);
+
+ let hasVerifier = 1;
+ let assemblyFormat = [{
+ $a `:` qualified(type($a))
+ (`result` `(` $result_image^ `:` type($result_image) `)` )?
+ (`stat` `(` $stat^ `:` type($stat) `)` )?
+ (`errmsg` `(` $errmsg^ `:` type($errmsg) `)` )?
+ attr-dict
+ }];
+}
+
+def mif_CoMinOp
+ : mif_Op<"co_min", [AttrSizedOperandSegments, MemoryEffects<[MemWrite]>]> {
+ let summary = "Compute minimum value across images.";
+ let description = [{
+ The co_min operation performs the computation of the minimum
+ across images.
+ }];
+
+ let arguments = (ins fir_BoxType:$a,
+ Optional<AnyIntegerType>:$result_image,
+ Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+ Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg);
+
+ let hasVerifier = 1;
+ let assemblyFormat = [{
+ $a `:` qualified(type($a))
+ (`result` `(` $result_image^ `:` type($result_image) `)` )?
+ (`stat` `(` $stat^ `:` type($stat) `)` )?
+ (`errmsg` `(` $errmsg^ `:` type($errmsg) `)` )?
+ attr-dict
+ }];
+}
+
+def mif_CoSumOp
+ : mif_Op<"co_sum", [AttrSizedOperandSegments, MemoryEffects<[MemWrite]>]> {
+ let summary = "Compute sum across images.";
+ let description = [{
+ The co_sum operation performs the computation of the sum
+ across images.
+ }];
+
+ let arguments = (ins fir_BoxType:$a,
+ Optional<AnyIntegerType>:$result_image,
+ Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+ Arg<Optional<Any...
[truncated]
|
Thanks @JDPailleux for the progress with the Multi Image Dialect. Does this currently cover only the intrinsics? If you could write a high level description of the MIF dialect as a PR to flang/docs or write a summary in discourse (https://discourse.llvm.org/c/subprojects/flang/33) that will make it easier for others to follow and help review. Alternatively you could consider presenting at the Flang community call next Wednesday. Are there any general principles that you are following. Like all co-array or multi-image intrinsics will be represented as an operation. Are there any new FIR/MLIR types to represent coarrays/multi-images? Is the dialect only for ease of lowering or will it include some transformations as well? What kind of transformations do you plan to have in the dialect? |
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 @JDPailleux for adding a dialect for multi image Fortran!
It is nice to centralize the interface with PRIF in an MLIR pass and to have operations for MIF/Coarrays that will make experimenting easier.
I added comments inline, overall this looks great to me.
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.
@JDPailleux Thanks for all the great work on this new MIF dialect!
I don't follow all the LLVM details in this PR, but I've added some questions/comments on parts I think I understand.
I see that you have some slides in https://flang-compiler.slack.com/archives/C06QTP07SCU/p1758900973869609. This addresses my points above. Thanks. |
Hello @kiranchandramohan, currently in this PR, the dialect will cover the intrinsics/statements that are already upstreamed in LLVM. But later we will add statements/intrinsics, coarray allocation and deallocation, and coarray memory access operations, ... Of course, I will write something on the discourse. About your question about the representation of a coarray in that, I haven't fully thought about it yet. But there are some ideas in the slides pointed on slack. Unfortunately, I won't be available next Wednesday, but I'll be available for a next Flang community call. |
Co-authored-by: Dan Bonachea <dobonachea@lbl.gov>
Co-authored-by: Dan Bonachea <dobonachea@lbl.gov>
Co-authored-by: Dan Bonachea <dobonachea@lbl.gov>
- Add decoration MemWrite and MemRead - Remote useless --split-file flag - Remote useless Start/End/Main in the conversion tests - Replace PRIF macro type by static functions - Remove unecessary things
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.
@JDPailleux Thanks for all the improvements!
I'm very excited to see this effort progressing.
Co-authored-by: Valentin Clement (バレンタイン クレメン) <clementval@gmail.com>
Co-authored-by: Valentin Clement (バレンタイン クレメン) <clementval@gmail.com>
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 take care of the missing side effect, LGTM otherwise. Thanks for adding this dialect!
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.
All the recent improvements look great!
I added a few more observations to consider as possible improvements.
//===----------------------------------------------------------------------===// | ||
|
||
def mif_SyncAllOp : mif_Op<"sync_all", [AttrSizedOperandSegments, | ||
MemoryEffects<[MemWrite]>]> { |
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.
All three SYNC operations in this section (sync_all
, sync_images
and sync_memory
) are Fortran "image control statements" (see F23 11.7.1). This means they end a Fortran "segment" and start another (see F23 11.7.2), which affects the memory consistency semantics of the multi-image execution.
One practical impact of this is to restrict the types of optimizations that can safely be performed on surrounding operations that might access memory reachable from a coarray (which generally includes any variable directly in a coarray or any variable with a TARGET attribute). So for example in the absence of very sophisticated analysis, the LLVM optimizer should not be permitted to effectively hoist any access operations touching such locations across an image control statement like sync all
.
The parallel runtime library will only ensure the image synchronization semantics of the operation and inhibit hardware-level reordering. It's the compiler's responsibility to ensure that optimizations don't move surrounding memory access operations across the image control statement in ways that could break the Fortran memory model. Such violations probably wouldn't affect visible behavior today, but could become a visible problem once we add coindexed access.
I found only limited documentation on mlir::MemoryEffects
, so I'm not sure if the dialect is a sufficient and proper place to represent this category of constraint, or if it belongs elsewhere. However one conservative way to enforce the required constraint might be to set the MemoryEffects
of dialect operations corresponding to image control statements such that compiler analysis assumes the operation effectively has a side-effect of reading and writing all memory locations (not just those directly referenced by the arguments).
@jeanPerier Can this be expressed by setting attributes like MemoryEffects<[MemRead,MemWrite]>
on dialect operations corresponding to image control statements? Or do we need something even more aggressive like MemoryEffects<[MemRead<DefaultResource, 0, FullEffect>,MemWrite<DefaultResource, 1, FullEffect>]>
, or something else entirely?
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.
It is a good point that a sync operation will not only write but also read something from the runtime state.
FullEffect
seems to imply all the memory resource is being read/written. It is not the case here, and if anything, I would imagine this is an indication that allows doing more optimizations (like deleting the first write in write after write). It is not used on any of the FIR operations.
The safest approach is to not implement the side effect interface at all, this will prevent any dialect independent optimizations involving memory. My understanding is that this is semantically equivalent to specifying MemoryEffects<[MemRead,MemWrite,MemAlloc,MemFree]>
, with the exception that the latter imply that the operation has no memory conflict with an operation that would have MemoryEffects on something else than the DefaultRessource.
For now I would advise starting by not implementing the side effect interface at all without some deeper design and testing phase.
I checked the MPI dialect and it does not implement side effect interfaces outside of few invariant operations that they consider Pure.
Later, there is maybe a case from ensuring some optimizations like load to store forwarding of local scalars that are not involved in any multi image statements is still possible (my understanding is that an operation that either does not implement the side effect interface or has generic write effect will prevent such optimization if it is between the load and store, even if the operation does not take the address, or an alias of the address as an argument). We should likely have a discussion with the MPI dialect contributors when trying to specify side effects in a finer way.
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.
FullEffect
seems to imply all the memory resource is being read/written. It is not the case here, and if anything, I would imagine this is an indication that allows doing more optimizations (like deleting the first write in write after write).
The idea was that by including MemRead<DefaultResource, 0, FullEffect>
then analysis must assume this operation starts by reading every single memory location, and then writes it MemWrite<DefaultResource, 1, FullEffect>]>
. I suspect that first step automatically avoids the WAW hazard you mention by ensuring this operation starts by effectively reading all of memory. It's not literally how a sync all
behaves, but we're looking for an annotation that inhibits all motion of memory access across this segment boundary. Conservatively saying that it consumes all of memory and then writes all of memory is more than necessary but should be sufficient.
All that being said, I yield to @jeanPerier 's expertise regarding the safest near-term approach being to remove the side effect interface from sync {all,images,memory}
, which hopefully has the same fencing effect on problematic optimization across segment boundaries.
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.
That's definitely a good point! Perhaps later on, a specific memory effect will need to be added for this type of operation, if I understand correctly, because there isn't really one for this type of use ?
The current proposal to remove the memory effect isn't a right solution. Because if we omit passing errmsg
and stat
, after optimization, the operation is removed. As specified by @jeanPerier , should we use full effect in this case?
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.
The current proposal to remove the memory effect isn't a right solution. Because if we omit passing errmsg and stat, after optimization, the operation is removed.
Are you sure you removed all the memory effect specifications from the operation, including the ones on the operands ([MemWrite]>:$stat
and [MemWrite]>:$errmsg
)?
Specifying memory effects on the operands gives the MemoryEffectsOpInterface to the operation and implies that there are no other memory being read/written to than the operands, which is not what we want here.
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.
My bad, sorry, when I tested it, I forgot to remove one of the arguments!
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.
a specific memory effect will need to be added for this type of operation, if I understand correctly, because there isn't really one for this type of use ?
No, it is likely a matter of expressing it with what exists. What I am saying is that there is no point adding memory effects to say that it can read/write to any memory. That is already implied by not implementing the interface (interfaces are here to enable optimizations in a controlled fashion which by default are disabled). I think the key will likely be to define some CoarrayMemoryRessource, and have the MIF operations do read/write to that resource. This is similar to how we ensure that VOLATILE load/stores are not re-ordered without impacting the load/stores of non VOLATILE memory around that.
The point is: only implement MemoryEffectsOpInterface
if is obvious for the operation, or, for operation like here, if you have a clear design and related tests to verify that memory related optimizations will only kick in when allowed.
Sorry for my absence during the last Flang community call, but as mentioned at the beginning of the PR, I couldn't attend this call. However, I will be present at the next one on Octobre 22. |
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.
Made one minor cosmetic request, otherwise LGTM!
//===----------------------------------------------------------------------===// | ||
// Synchronization | ||
//===----------------------------------------------------------------------===// | ||
|
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.
Given the subtlety and importance to correctness, I'd like to request that we record the conclusion of our conversation in this PR as a comment. This will hopefully ensure the design choice is explicitly/visibly documented, as opposed to potentially looking like we simply forgot to implement MemoryEffects
for these operations.
Perhaps something like:
// NOTE: Every operation in this section corresponds to a Fortran | |
// "image control statement" (F23 11.7.1). This means they end a Fortran | |
// "segment" and start another (F23 11.7.2), which affects the memory | |
// consistency semantics of surrounding accesses in the multi-image execution. | |
// For now we've modeled this by *deliberately* omitting mlir::MemoryEffects | |
// on these operations, to ensure analysis treats these ops conservatively. | |
//===----------------------------------------------------------------------===// | |
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 have verified through testing with Caffeine that this PR doesn't contain any regressions for the features switched from the experimental support to support using the new MIF dialect.
Support for multi-image features has begun to be integrated into LLVM. A new dialect which simplifies lowering to PRIF wil be proposed in this PR.
The initial definition of this dialect (MIF) is based only on operations already upstreamed in LLVM and the current lowering will be moved to this dialect.
Features like TEAMs and the use of coarrays will follow later in other PRs.
Any feedback regarding what is proposed is welcome.