Skip to content

Conversation

@JDPailleux
Copy link
Contributor

Support for multi-image features has begun to be integrated into LLVM with the MIF dialect.
In this PR, you will find lowering and operations related to the TEAM features (SYNC TEAM, GET_TEAM, FORM TEAM, CHANGE TEAM, TEAM_NUMBER).

Note regarding the operation for CHANGE TEAM : This operation is partial because it does not support the associated list of coarrays because the allocation of a coarray and the lowering of PRIF's prif_alias_{create|destroy} procedures are not yet supported in Flang. This will be integrated later.

Any feedback is welcome.

@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir labels Oct 29, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 29, 2025

@llvm/pr-subscribers-flang-fir-hlfir

Author: Jean-Didier PAILLEUX (JDPailleux)

Changes

Support for multi-image features has begun to be integrated into LLVM with the MIF dialect.
In this PR, you will find lowering and operations related to the TEAM features (SYNC TEAM, GET_TEAM, FORM TEAM, CHANGE TEAM, TEAM_NUMBER).

Note regarding the operation for CHANGE TEAM : This operation is partial because it does not support the associated list of coarrays because the allocation of a coarray and the lowering of PRIF's prif_alias_{create|destroy} procedures are not yet supported in Flang. This will be integrated later.

Any feedback is welcome.


Patch is 78.85 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/165573.diff

18 Files Affected:

  • (modified) flang/include/flang/Optimizer/Builder/IntrinsicCall.h (+3)
  • (modified) flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td (+155)
  • (modified) flang/lib/Lower/Bridge.cpp (+20-3)
  • (modified) flang/lib/Lower/Coarray.cpp (+130-6)
  • (modified) flang/lib/Lower/Runtime.cpp (+19-2)
  • (modified) flang/lib/Optimizer/Builder/IntrinsicCall.cpp (+27)
  • (modified) flang/lib/Optimizer/Dialect/MIF/MIFOps.cpp (+107)
  • (modified) flang/lib/Optimizer/Transforms/MIFOpConversion.cpp (+248-11)
  • (added) flang/test/Fir/MIF/change_team.mlir (+53)
  • (added) flang/test/Fir/MIF/form_team.mlir (+58)
  • (added) flang/test/Fir/MIF/get_team.mlir (+70)
  • (added) flang/test/Fir/MIF/sync_team.mlir (+56)
  • (added) flang/test/Fir/MIF/team_number.mlir (+29)
  • (added) flang/test/Lower/MIF/change_team.f90 (+27)
  • (added) flang/test/Lower/MIF/form_team.f90 (+29)
  • (added) flang/test/Lower/MIF/get_team.f90 (+28)
  • (added) flang/test/Lower/MIF/sync_team.f90 (+25)
  • (added) flang/test/Lower/MIF/team_number.f90 (+19)
diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
index c3cd119b96174..bec33dccedcf1 100644
--- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
+++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
@@ -292,6 +292,7 @@ struct IntrinsicLibrary {
   void genGetEnvironmentVariable(llvm::ArrayRef<fir::ExtendedValue>);
   mlir::Value genGetGID(mlir::Type resultType,
                         llvm::ArrayRef<mlir::Value> args);
+  mlir::Value genGetTeam(mlir::Type, llvm::ArrayRef<mlir::Value>);
   mlir::Value genGetUID(mlir::Type resultType,
                         llvm::ArrayRef<mlir::Value> args);
   fir::ExtendedValue genHostnm(std::optional<mlir::Type> resultType,
@@ -456,6 +457,8 @@ struct IntrinsicLibrary {
   void genSystemClock(llvm::ArrayRef<fir::ExtendedValue>);
   mlir::Value genTand(mlir::Type, llvm::ArrayRef<mlir::Value>);
   mlir::Value genTanpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genTeamNumber(mlir::Type,
+                                   llvm::ArrayRef<fir::ExtendedValue>);
   mlir::Value genTime(mlir::Type, llvm::ArrayRef<mlir::Value>);
   void genTMABulkCommitGroup(llvm::ArrayRef<fir::ExtendedValue>);
   void genTMABulkG2S(llvm::ArrayRef<fir::ExtendedValue>);
diff --git a/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td b/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td
index 52471d3702b76..32055bd4a470b 100644
--- a/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td
+++ b/flang/include/flang/Optimizer/Dialect/MIF/MIFOps.td
@@ -21,6 +21,12 @@ include "flang/Optimizer/Dialect/FIRAttr.td"
 class mif_Op<string mnemonic, list<Trait> traits>
     : Op<MIFDialect, mnemonic, traits>;
 
+class region_Op<string mnemonic, list<Trait> traits = []>
+    : mif_Op<mnemonic, !listconcat(traits, [RecursivelySpeculatable,
+                                            RecursiveMemoryEffects])> {
+  let hasCustomAssemblyFormat = 1;
+}
+
 //===----------------------------------------------------------------------===//
 // Initialization and Finalization
 //===----------------------------------------------------------------------===//
@@ -174,6 +180,18 @@ def mif_SyncMemoryOp : mif_Op<"sync_memory", [AttrSizedOperandSegments]> {
   }];
 }
 
+def mif_SyncTeamOp : mif_Op<"sync_team", [AttrSizedOperandSegments]> {
+  let summary = "Performs a synchronization of the team, identified by `team`";
+
+  let arguments = (ins AnyRefOrBoxType:$team, Optional<AnyReferenceLike>:$stat,
+      Optional<AnyRefOrBoxType>:$errmsg);
+  let assemblyFormat = [{
+    $team (`stat` $stat^ )?
+    (`errmsg` $errmsg^ )? 
+    attr-dict `:` functional-type(operands, results)
+  }];
+}
+
 //===----------------------------------------------------------------------===//
 // Collective Operations
 //===----------------------------------------------------------------------===//
@@ -265,4 +283,141 @@ def mif_CoSumOp
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// Teams
+//===----------------------------------------------------------------------===//
+
+def mif_FormTeamOp : mif_Op<"form_team", [AttrSizedOperandSegments]> {
+  let summary =
+      "Create a set of sibling teams whose parent team is the current team.";
+  let description = [{
+    Create a new team for each unique `team_number` value specified.
+    Each executing image will belong to the team whose `team_number` is equal 
+    to the value of team-number on that image, and `team_var` becomes defined
+    with a value that identifies that team.
+
+    If `new_index` is specified, the image index of the executing image will take
+    this index in its new team. Otherwise, the new image index is processor 
+    dependent.
+
+    Arguments: 
+      - `team_number`: Shall be a positive integer.
+      - `team_var` : Shall be a variable of type TEAM_TYPE from the intrinsic
+        module ISO_FORTRAN_ENV.
+      - `new_index`(optional): Shall be an integer that correspond to the index that
+        the calling image will have in the new team.
+  }];
+
+  let arguments = (ins AnyIntegerType:$team_number,
+      Arg<fir_BoxType, "", [MemWrite]>:$team_var,
+      Optional<AnyIntegerType>:$new_index,
+      Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+      Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg);
+
+  let assemblyFormat = [{
+    `team_number` $team_number `team_var` $team_var
+    (`new_index` $new_index^ )?
+    (`stat` $stat^ )?
+    (`errmsg` $errmsg^ )?
+    attr-dict `:` functional-type(operands, results)
+  }];
+}
+
+def mif_EndTeamOp : mif_Op<"end_team", [AttrSizedOperandSegments, Terminator,
+                                        ParentOneOf<["ChangeTeamOp"]>]> {
+  let summary = "Changes the current team to the parent team.";
+  let description = [{
+    The END TEAM operation completes the CHANGE TEAM construct and 
+    restores the current team to the team that was current before 
+    the CHANGE TEAM construct. 
+  }];
+
+  let arguments = (ins Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+      Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg);
+  let builders = [OpBuilder<(ins), [{ /* do nothing */ }]>];
+
+  let assemblyFormat = [{
+    (`stat` $stat^ )? (`errmsg` $errmsg^ )?
+    attr-dict `:` functional-type(operands, results)
+  }];
+}
+
+//===----------------------------------------------------------------------===//
+// NOTE: The CHANGE TEAM region will take a coarray association list in
+// argument. However, coarray management and coarray alias creation are not
+// yet supported by the dialect. The argument is therefore not yet supported by
+// this operation and will be added later.
+//===----------------------------------------------------------------------===//
+def mif_ChangeTeamOp
+    : region_Op<"change_team", [AttrSizedOperandSegments,
+                                SingleBlockImplicitTerminator<"EndTeamOp">]> {
+  let summary = "Changes the current team.";
+  let description = [{
+    The CHANGE TEAM construct changes the current team to the specified new
+    team, which must be a child team of the current team.  
+
+    ```
+      mif.change_team %team {
+        %x = fir.convert %i : (index) -> i32
+        ...
+        mif.end_team
+      }
+  }];
+
+  let arguments = (ins AnyRefOrBoxType:$team,
+      Arg<Optional<AnyReferenceLike>, "", [MemWrite]>:$stat,
+      Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg);
+  let regions = (region SizedRegion<1>:$region);
+
+  let skipDefaultBuilders = 1;
+  let builders =
+      [OpBuilder<(ins "mlir::Value":$team,
+           CArg<"bool", "true">:$ensureTerminaison,
+           CArg<"llvm::ArrayRef<mlir::NamedAttribute>", "{}">:$attributes)>,
+       OpBuilder<(ins "mlir::Value":$team, "mlir::Value":$stat,
+           "mlir::Value":$errmsg, CArg<"bool", "true">:$ensureTerminaison,
+           CArg<"llvm::ArrayRef<mlir::NamedAttribute>", "{}">:$attributes)>];
+
+  let extraClassDeclaration = [{
+    /// Get the body of the CHANGE TEAM construct 
+    mlir::Block *getBody() { return &getRegion().front(); }
+  }];
+}
+
+def mif_GetTeamOp : mif_Op<"get_team", []> {
+  let summary = "Get the team value for the current or ancestor team.";
+  let description = [{
+    This operation gets the team value for the current or an ancestor team.
+    `level`(optional): If provided, must equal one of the following constants : 
+    `INITIAL_TEAM`, `PARENT_TEAM` or `CURRENT_TEAM` from the module ISO_FORTRAN_ENV.
+    If `level` isn't present or has the value `CURRENT_TEAM` the returned
+    value is the current team.     
+  }];
+
+  let arguments = (ins Optional<AnyIntegerType>:$level);
+  let results = (outs fir_BoxType:$team);
+
+  let assemblyFormat = [{
+    (`level` $level^ )?
+    attr-dict `:` functional-type(operands, results)
+  }];
+}
+
+def mif_TeamNumberOp : mif_Op<"team_number", []> {
+  let summary = "Get the team number";
+  let description = [{
+    Argument: `team` is optional and shall be a scalar of type TEAM_TYPE from 
+    module ISO_FORTRAN_ENV and the value identifies the current or an ancestor team. 
+    If `team` is absent, the team specified is the current team.
+  }];
+
+  let arguments = (ins Optional<AnyRefOrBoxType>:$team);
+  let results = (outs I64);
+
+  let assemblyFormat = [{
+    (`team` $team^ )?
+    attr-dict `:` functional-type(operands, results)
+  }];
+}
+
 #endif // FORTRAN_DIALECT_MIF_MIF_OPS
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 6e729874eb5e6..daf8b6e6e243f 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -3950,13 +3950,30 @@ class FirConverter : public Fortran::lower::AbstractConverter {
   }
 
   void genFIR(const Fortran::parser::ChangeTeamConstruct &construct) {
-    TODO(toLocation(), "coarray: ChangeTeamConstruct");
+    Fortran::lower::StatementContext stmtCtx;
+    pushActiveConstruct(getEval(), stmtCtx);
+
+    for (Fortran::lower::pft::Evaluation &e :
+         getEval().getNestedEvaluations()) {
+      if (e.getIf<Fortran::parser::ChangeTeamStmt>()) {
+        maybeStartBlock(e.block);
+        setCurrentPosition(e.position);
+        genFIR(e);
+      } else if (e.getIf<Fortran::parser::EndChangeTeamStmt>()) {
+        maybeStartBlock(e.block);
+        setCurrentPosition(e.position);
+        genFIR(e);
+      } else {
+        genFIR(e);
+      }
+    }
+    popActiveConstruct();
   }
   void genFIR(const Fortran::parser::ChangeTeamStmt &stmt) {
-    TODO(toLocation(), "coarray: ChangeTeamStmt");
+    genChangeTeamStmt(*this, getEval(), stmt);
   }
   void genFIR(const Fortran::parser::EndChangeTeamStmt &stmt) {
-    TODO(toLocation(), "coarray: EndChangeTeamStmt");
+    genEndChangeTeamStmt(*this, getEval(), stmt);
   }
 
   void genFIR(const Fortran::parser::CriticalConstruct &criticalConstruct) {
diff --git a/flang/lib/Lower/Coarray.cpp b/flang/lib/Lower/Coarray.cpp
index a84f65a5c49e8..d0d986483ccbf 100644
--- a/flang/lib/Lower/Coarray.cpp
+++ b/flang/lib/Lower/Coarray.cpp
@@ -16,6 +16,7 @@
 #include "flang/Lower/SymbolMap.h"
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Builder/Todo.h"
+#include "flang/Optimizer/Dialect/MIF/MIFOps.h"
 #include "flang/Parser/parse-tree.h"
 #include "flang/Semantics/expression.h"
 
@@ -33,21 +34,144 @@ void Fortran::lower::genChangeTeamConstruct(
 void Fortran::lower::genChangeTeamStmt(
     Fortran::lower::AbstractConverter &converter,
     Fortran::lower::pft::Evaluation &,
-    const Fortran::parser::ChangeTeamStmt &) {
-  TODO(converter.getCurrentLocation(), "coarray: CHANGE TEAM statement");
+    const Fortran::parser::ChangeTeamStmt &stmt) {
+  mlir::Location loc = converter.getCurrentLocation();
+  converter.checkCoarrayEnabled();
+  fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+
+  mlir::Value errMsgAddr, statAddr, team;
+  // Handle STAT and ERRMSG values
+  Fortran::lower::StatementContext stmtCtx;
+  const std::list<Fortran::parser::StatOrErrmsg> &statOrErrList =
+      std::get<std::list<Fortran::parser::StatOrErrmsg>>(stmt.t);
+  for (const Fortran::parser::StatOrErrmsg &statOrErr : statOrErrList) {
+    std::visit(Fortran::common::visitors{
+                   [&](const Fortran::parser::StatVariable &statVar) {
+                     const auto *expr = Fortran::semantics::GetExpr(statVar);
+                     statAddr = fir::getBase(
+                         converter.genExprAddr(loc, *expr, stmtCtx));
+                   },
+                   [&](const Fortran::parser::MsgVariable &errMsgVar) {
+                     const auto *expr = Fortran::semantics::GetExpr(errMsgVar);
+                     errMsgAddr = fir::getBase(
+                         converter.genExprBox(loc, *expr, stmtCtx));
+                   },
+               },
+               statOrErr.u);
+  }
+
+  // TODO: Manage the list of coarrays associated in
+  // `std::list<CoarrayAssociation>`. According to the PRIF specification, it is
+  // necessary to call `prif_alias_{create|destroy}` for each coarray defined in
+  // this list. Support will be added once lowering to this procedure is
+  // possible.
+  const std::list<Fortran::parser::CoarrayAssociation> &coarrayAssocList =
+      std::get<std::list<Fortran::parser::CoarrayAssociation>>(stmt.t);
+  if (coarrayAssocList.size())
+    mlir::emitWarning(loc,
+                      "Coarrays provided in the association list are ignored.");
+
+  // Handle TEAM-VALUE
+  const auto *teamExpr =
+      Fortran::semantics::GetExpr(std::get<Fortran::parser::TeamValue>(stmt.t));
+  team = fir::getBase(converter.genExprBox(loc, *teamExpr, stmtCtx));
+
+  mif::ChangeTeamOp changeOp = mif::ChangeTeamOp::create(
+      builder, loc, team, statAddr, errMsgAddr, /*terminator*/ false);
+  builder.setInsertionPointToStart(changeOp.getBody());
 }
 
 void Fortran::lower::genEndChangeTeamStmt(
     Fortran::lower::AbstractConverter &converter,
     Fortran::lower::pft::Evaluation &,
-    const Fortran::parser::EndChangeTeamStmt &) {
-  TODO(converter.getCurrentLocation(), "coarray: END CHANGE TEAM statement");
+    const Fortran::parser::EndChangeTeamStmt &stmt) {
+  converter.checkCoarrayEnabled();
+  mlir::Location loc = converter.getCurrentLocation();
+  fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+
+  mlir::Value errMsgAddr, statAddr;
+  // Handle STAT and ERRMSG values
+  Fortran::lower::StatementContext stmtCtx;
+  const std::list<Fortran::parser::StatOrErrmsg> &statOrErrList =
+      std::get<std::list<Fortran::parser::StatOrErrmsg>>(stmt.t);
+  for (const Fortran::parser::StatOrErrmsg &statOrErr : statOrErrList) {
+    std::visit(Fortran::common::visitors{
+                   [&](const Fortran::parser::StatVariable &statVar) {
+                     const auto *expr = Fortran::semantics::GetExpr(statVar);
+                     statAddr = fir::getBase(
+                         converter.genExprAddr(loc, *expr, stmtCtx));
+                   },
+                   [&](const Fortran::parser::MsgVariable &errMsgVar) {
+                     const auto *expr = Fortran::semantics::GetExpr(errMsgVar);
+                     errMsgAddr = fir::getBase(
+                         converter.genExprBox(loc, *expr, stmtCtx));
+                   },
+               },
+               statOrErr.u);
+  }
+
+  mif::EndTeamOp endOp =
+      mif::EndTeamOp::create(builder, loc, statAddr, errMsgAddr);
+  builder.setInsertionPointAfter(endOp.getParentOp());
 }
 
 void Fortran::lower::genFormTeamStatement(
     Fortran::lower::AbstractConverter &converter,
-    Fortran::lower::pft::Evaluation &, const Fortran::parser::FormTeamStmt &) {
-  TODO(converter.getCurrentLocation(), "coarray: FORM TEAM statement");
+    Fortran::lower::pft::Evaluation &,
+    const Fortran::parser::FormTeamStmt &stmt) {
+  converter.checkCoarrayEnabled();
+  mlir::Location loc = converter.getCurrentLocation();
+  fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+
+  mlir::Value errMsgAddr, statAddr, newIndex, teamNumber, team;
+  // Handle NEW_INDEX, STAT and ERRMSG
+  std::list<Fortran::parser::StatOrErrmsg> statOrErrList{};
+  Fortran::lower::StatementContext stmtCtx;
+  const auto &formSpecList =
+      std::get<std::list<Fortran::parser::FormTeamStmt::FormTeamSpec>>(stmt.t);
+  for (const Fortran::parser::FormTeamStmt::FormTeamSpec &formSpec :
+       formSpecList) {
+    std::visit(
+        Fortran::common::visitors{
+            [&](const Fortran::parser::StatOrErrmsg &statOrErr) {
+              std::visit(
+                  Fortran::common::visitors{
+                      [&](const Fortran::parser::StatVariable &statVar) {
+                        const auto *expr = Fortran::semantics::GetExpr(statVar);
+                        statAddr = fir::getBase(
+                            converter.genExprAddr(loc, *expr, stmtCtx));
+                      },
+                      [&](const Fortran::parser::MsgVariable &errMsgVar) {
+                        const auto *expr =
+                            Fortran::semantics::GetExpr(errMsgVar);
+                        errMsgAddr = fir::getBase(
+                            converter.genExprBox(loc, *expr, stmtCtx));
+                      },
+                  },
+                  statOrErr.u);
+            },
+            [&](const Fortran::parser::ScalarIntExpr &intExpr) {
+              fir::ExtendedValue newIndexExpr = converter.genExprValue(
+                  loc, Fortran::semantics::GetExpr(intExpr), stmtCtx);
+              newIndex = fir::getBase(newIndexExpr);
+            },
+        },
+        formSpec.u);
+  }
+
+  // Handle TEAM-NUMBER
+  const auto *teamNumberExpr = Fortran::semantics::GetExpr(
+      std::get<Fortran::parser::ScalarIntExpr>(stmt.t));
+  teamNumber =
+      fir::getBase(converter.genExprValue(loc, *teamNumberExpr, stmtCtx));
+
+  // Handle TEAM-VARIABLE
+  const auto *teamExpr = Fortran::semantics::GetExpr(
+      std::get<Fortran::parser::TeamVariable>(stmt.t));
+  team = fir::getBase(converter.genExprBox(loc, *teamExpr, stmtCtx));
+
+  mif::FormTeamOp::create(builder, loc, teamNumber, team, newIndex, statAddr,
+                          errMsgAddr);
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/flang/lib/Lower/Runtime.cpp b/flang/lib/Lower/Runtime.cpp
index cb555249125f6..f8c5a72d0d66c 100644
--- a/flang/lib/Lower/Runtime.cpp
+++ b/flang/lib/Lower/Runtime.cpp
@@ -257,8 +257,25 @@ void Fortran::lower::genSyncMemoryStatement(
 
 void Fortran::lower::genSyncTeamStatement(
     Fortran::lower::AbstractConverter &converter,
-    const Fortran::parser::SyncTeamStmt &) {
-  TODO(converter.getCurrentLocation(), "coarray: SYNC TEAM runtime");
+    const Fortran::parser::SyncTeamStmt &stmt) {
+  mlir::Location loc = converter.getCurrentLocation();
+  converter.checkCoarrayEnabled();
+
+  // Handle TEAM
+  Fortran::lower::StatementContext stmtCtx;
+  const Fortran::parser::TeamValue &teamValue =
+      std::get<Fortran::parser::TeamValue>(stmt.t);
+  const SomeExpr *teamExpr = Fortran::semantics::GetExpr(teamValue);
+  mlir::Value team =
+      fir::getBase(converter.genExprBox(loc, *teamExpr, stmtCtx));
+
+  // Handle STAT and ERRMSG values
+  const std::list<Fortran::parser::StatOrErrmsg> &statOrErrList =
+      std::get<std::list<Fortran::parser::StatOrErrmsg>>(stmt.t);
+  auto [statAddr, errMsgAddr] = getStatAndErrmsg(converter, loc, statOrErrList);
+
+  fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+  mif::SyncTeamOp::create(builder, loc, team, statAddr, errMsgAddr);
 }
 
 void Fortran::lower::genPauseStatement(
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 39bac818fe5d0..391128bfc5f99 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -553,6 +553,10 @@ static constexpr IntrinsicHandler handlers[]{
        {"trim_name", asAddr, handleDynamicOptional},
        {"errmsg", asBox, handleDynamicOptional}}},
      /*isElemental=*/false},
+    {"get_team",
+     &I::genGetTeam,
+     {{{"level", asValue, handleDynamicOptional}}},
+     /*isElemental=*/false},
     {"getcwd",
      &I::genGetCwd,
      {{{"c", asBox}, {"status", asAddr, handleDynamicOptional}}},
@@ -1012,6 +1016,10 @@ static constexpr IntrinsicHandler handlers[]{
      /*isElemental=*/false},
     {"tand", &I::genTand},
     {"tanpi", &I::genTanpi},
+    {"team_number",
+     &I::genTeamNumber,
+     {{{"team", asBox, handleDynamicOptional}}},
+     /*isElemental=*/false},
     {"this_grid", &I::genThisGrid, {}, /*isElemental=*/false},
     {"this_image",
      &I::genThisImage,
@@ -4543,6 +4551,15 @@ IntrinsicLibrary::genFtell(std::optional<mlir::Type> resultType,
   }
 }
 
+// GET_TEAM
+mlir::Value IntrinsicLibrary::genGetTeam(mlir::Type resultType,
+                                         llvm::ArrayRef<mlir::Value> args) {
+  converter->checkCoarrayEnabled();
+  assert(args.size() == 1);
+  return mif::GetTeamOp::create(builder, loc, fir::BoxType::get(resultType),
+                                /*level*/ args[0]);
+}
+
 // GETCWD
 fir::ExtendedValue
 IntrinsicLibrary::genGetCwd(std::optional<mlir::Type> resultType,
@@ -8653,6 +8670,16 @@ IntrinsicLibrary::genThisImage(mlir::Type resultType,
   return builder.createConvert(loc, resultType, res);
 }
...
[truncated]

Copy link
Contributor

@bonachea bonachea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @JDPailleux for all this work, this looks like a great start on adding team features!

I've added some initial suggestions based on a quick skim of the code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the story with Fortran::lower::genChangeTeamConstruct() on line 27?

Is that just dead code that should be removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the Fortran::lower::genChangeTeamConstruct(), I think this function was added when parsing was added to Flang for the construct CHANGE TEAM. However, I don't need it at the moment, but I will probably need it later when I will add support for CoarrayAssociationList.

Copy link
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

CHANGE TEAM have a partial support for coarray associated list.
PRIF require to use prif_alias_{create|destroy} for each coarray in this
list. It will upstream later, when coarray allocation and alias procedure
will be added.
@ktras ktras requested a review from jeanPerier November 5, 2025 18:06
Copy link
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nit, LGTM otherwise, thanks!


#ifndef FORTRAN_LOWER_COARRAY_H
#define FORTRAN_LOWER_COARRAY_H
#ifndef FORTRAN_LOWER_MULTI_IMAGE_FORTRAN_H
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: The convention is FORTRAN_LOWER_MULTIIMAGEFORTRAN_H, even if that is less readable (only folders / create _.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

flang:fir-hlfir flang Flang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants