[Mlir-commits] [flang] [mlir] [OpenMP][mlir] Add DynGroupPrivateClause in omp dialect (PR #153562)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Wed Jan 28 01:15:14 PST 2026


https://github.com/skc7 updated https://github.com/llvm/llvm-project/pull/153562

>From ec8a7b90bca211244f89e9b44a90a5b08071344d Mon Sep 17 00:00:00 2001
From: skc7 <Krishna.Sankisa at amd.com>
Date: Thu, 14 Aug 2025 09:46:31 +0530
Subject: [PATCH 1/4] [OpenMP][mlir] Add DynGroupPrivateClause in omp dialect

---
 .../mlir/Dialect/OpenMP/OpenMPClauses.td      |  43 ++++
 .../mlir/Dialect/OpenMP/OpenMPEnums.td        |  21 ++
 mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td |   5 +-
 mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp  | 187 ++++++++++++++++++
 .../OpenMP/OpenMPToLLVMIRTranslation.cpp      |   7 +
 mlir/test/Dialect/OpenMP/invalid.mlir         |  40 +++-
 mlir/test/Dialect/OpenMP/ops.mlir             |  34 +++-
 7 files changed, 330 insertions(+), 7 deletions(-)

diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
index 9114d9c1f0ac1..571abad1bfc74 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
@@ -1692,4 +1692,47 @@ class OpenMP_UniformClauseSkip<
 
 def OpenMP_UniformClause : OpenMP_UniformClauseSkip<>;
 
+//===----------------------------------------------------------------------===//
+// V6.1 `dyn_groupprivate` clause
+//===----------------------------------------------------------------------===//
+
+class OpenMP_DynGroupprivateClauseSkip<
+    bit traits = false, bit arguments = false, bit assemblyFormat = false,
+    bit description = false, bit extraClassDeclaration = false
+  > : OpenMP_Clause<traits, arguments, assemblyFormat, description,
+                    extraClassDeclaration> {
+
+  let arguments = (ins
+    OptionalAttr<DynGroupprivateModifierAttr>:$modifier_first,
+    OptionalAttr<DynGroupprivateModifierAttr>:$modifier_second,
+    Optional<AnyInteger>:$dyn_groupprivate_size
+  );
+
+  let description = [{
+    The `dyn_groupprivate` clause allows you to dynamically allocate group-private
+    memory in OpenMP parallel regions, specifically for `target` and `teams` directives.
+    This clause enables runtime-sized private memory allocation and applicable to
+    target and teams ops.
+
+    Syntax:
+    ```
+    dyn_groupprivate(modifier_first ,modifier_second : dyn_groupprivate_size)
+    ```
+
+    Example:
+    ```
+    omp.target dyn_groupprivate(strict, cgroup : %dyn_groupprivate_size : i32)
+    ```
+  }];
+
+  let optAssemblyFormat = [{
+    `dyn_groupprivate` `(`
+      custom<DynGroupprivateClause>($modifier_first, $modifier_second, 
+      $dyn_groupprivate_size, type($dyn_groupprivate_size))
+    `)`
+  }];
+}
+
+def OpenMP_DynGroupprivateClause : OpenMP_DynGroupprivateClauseSkip<>;
+
 #endif // OPENMP_CLAUSES
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td
index 707850cbb47b7..57021dfc0daad 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td
@@ -331,4 +331,25 @@ def VariableCaptureKindAttr : OpenMP_EnumAttr<VariableCaptureKind,
   let assemblyFormat = "`(` $value `)`";
 }
 
+//===----------------------------------------------------------------------===//
+// dyn_groupprivate enum.
+//===----------------------------------------------------------------------===//
+
+def DynGroupprivateCGroup : I32EnumAttrCase<"cgroup", 0>;
+def DynGroupprivateStrict : I32EnumAttrCase<"strict", 1>;
+def DynGroupprivateFallback : I32EnumAttrCase<"fallback", 2>;
+
+def DynGroupprivateModifier : OpenMP_I32EnumAttr<
+    "DynGroupprivateModifier",
+    "dyn_groupprivate modifier", [
+      DynGroupprivateCGroup,
+      DynGroupprivateStrict,
+      DynGroupprivateFallback
+    ]>;
+
+def DynGroupprivateModifierAttr : OpenMP_EnumAttr<DynGroupprivateModifier,
+                                            "dyn_groupprivate_modifier"> {
+  let assemblyFormat = "`(` $value `)`";
+}
+
 #endif // OPENMP_ENUMS
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
index dfec6609e1161..8dab65670fa54 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
@@ -241,7 +241,8 @@ def TeamsOp : OpenMP_Op<"teams", traits = [
     AttrSizedOperandSegments, RecursiveMemoryEffects, OutlineableOpenMPOpInterface
   ], clauses = [
     OpenMP_AllocateClause, OpenMP_IfClause, OpenMP_NumTeamsClause,
-    OpenMP_PrivateClause, OpenMP_ReductionClause, OpenMP_ThreadLimitClause
+    OpenMP_PrivateClause, OpenMP_ReductionClause, OpenMP_ThreadLimitClause,
+    OpenMP_DynGroupprivateClause
   ], singleRegion = true> {
   let summary = "teams construct";
   let description = [{
@@ -1457,7 +1458,7 @@ def TargetOp : OpenMP_Op<"target", traits = [
     OpenMP_DeviceClause, OpenMP_HasDeviceAddrClause, OpenMP_HostEvalClause,
     OpenMP_IfClause, OpenMP_InReductionClause, OpenMP_IsDevicePtrClause,
     OpenMP_MapClauseSkip<assemblyFormat = true>, OpenMP_NowaitClause,
-    OpenMP_PrivateClause, OpenMP_ThreadLimitClause
+    OpenMP_PrivateClause, OpenMP_ThreadLimitClause, OpenMP_DynGroupprivateClause
   ], singleRegion = true> {
   let summary = "target construct";
   let description = [{
diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
index c3916219d1c93..fbf3ab31ccb22 100644
--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
@@ -798,6 +798,167 @@ static void printNumTasksClause(OpAsmPrinter &p, Operation *op,
       p, op, numTasksMod, numTasks, numTasksType, &stringifyClauseNumTasksType);
 }
 
+//===----------------------------------------------------------------------===//
+// Parser, printer and verify for dyn_groupprivate Clause
+//===----------------------------------------------------------------------===//
+
+static LogicalResult verifyDynGroupprivateClause(
+    Operation *op, DynGroupprivateModifierAttr modifierFirst,
+    DynGroupprivateModifierAttr modifierSecond, Value dynGroupprivateSize) {
+
+  // Helper to get modifier name as string
+  auto getModifierName = [](DynGroupprivateModifier mod) -> StringRef {
+    switch (mod) {
+    case DynGroupprivateModifier::strict:
+      return "strict";
+    case DynGroupprivateModifier::cgroup:
+      return "cgroup";
+    case DynGroupprivateModifier::fallback:
+      return "fallback";
+    }
+    return "unknown";
+  };
+
+  // Check for duplicate modifiers
+  if (modifierFirst && modifierSecond &&
+      modifierFirst.getValue() == modifierSecond.getValue()) {
+    return op->emitOpError("duplicate dyn_groupprivate modifier '")
+           << getModifierName(modifierFirst.getValue()) << "'";
+  }
+
+  // Check for incompatible modifier combinations
+  if (modifierFirst && modifierSecond) {
+    auto m1 = modifierFirst.getValue();
+    auto m2 = modifierSecond.getValue();
+
+    // strict and fallback are incompatible
+    if ((m1 == DynGroupprivateModifier::strict &&
+         m2 == DynGroupprivateModifier::fallback) ||
+        (m1 == DynGroupprivateModifier::fallback &&
+         m2 == DynGroupprivateModifier::strict)) {
+      return op->emitOpError("incompatible dyn_groupprivate modifiers: '")
+             << getModifierName(m1) << "' and '" << getModifierName(m2)
+             << "' cannot be used together";
+    }
+  }
+
+  // Verify the size
+  if (dynGroupprivateSize) {
+    Type size_type = dynGroupprivateSize.getType();
+    // Check if the size type is an integer type
+    if (!size_type.isIntOrIndex()) {
+      return op->emitOpError(
+                 "dyn_groupprivate size must be an integer type, got ")
+             << size_type;
+    }
+  }
+
+  return success();
+}
+
+static ParseResult parseDynGroupprivateClause(
+    OpAsmParser &parser, DynGroupprivateModifierAttr &modifierFirst,
+    DynGroupprivateModifierAttr &modifierSecond,
+    std::optional<OpAsmParser::UnresolvedOperand> &dynGroupprivateSize,
+    Type &size_type) {
+
+  bool hasModifiers = false;
+
+  // Parse first modifier if present
+  if (succeeded(parser.parseOptionalKeyword("strict"))) {
+    modifierFirst = DynGroupprivateModifierAttr::get(
+        parser.getContext(), DynGroupprivateModifier::strict);
+    hasModifiers = true;
+  } else if (succeeded(parser.parseOptionalKeyword("cgroup"))) {
+    modifierFirst = DynGroupprivateModifierAttr::get(
+        parser.getContext(), DynGroupprivateModifier::cgroup);
+    hasModifiers = true;
+  } else if (succeeded(parser.parseOptionalKeyword("fallback"))) {
+    modifierFirst = DynGroupprivateModifierAttr::get(
+        parser.getContext(), DynGroupprivateModifier::fallback);
+    hasModifiers = true;
+  }
+
+  // If first modifier found, check for comma and second modifier
+  if (hasModifiers && succeeded(parser.parseOptionalComma())) {
+    if (succeeded(parser.parseOptionalKeyword("strict"))) {
+      modifierSecond = DynGroupprivateModifierAttr::get(
+          parser.getContext(), DynGroupprivateModifier::strict);
+    } else if (succeeded(parser.parseOptionalKeyword("cgroup"))) {
+      modifierSecond = DynGroupprivateModifierAttr::get(
+          parser.getContext(), DynGroupprivateModifier::cgroup);
+    } else if (succeeded(parser.parseOptionalKeyword("fallback"))) {
+      modifierSecond = DynGroupprivateModifierAttr::get(
+          parser.getContext(), DynGroupprivateModifier::fallback);
+    } else {
+      return parser.emitError(parser.getCurrentLocation(),
+                              "expected modifier after comma");
+    }
+  }
+
+  // Parse colon and size if modifiers were present, or just try to parse
+  // operand
+  if (hasModifiers) {
+    // Modifiers present, expect colon
+    if (failed(parser.parseColon())) {
+      return parser.emitError(parser.getCurrentLocation(),
+                              "expected ':' after modifiers");
+    }
+
+    // Parse operand and type
+    OpAsmParser::UnresolvedOperand operand;
+    if (succeeded(parser.parseOperand(operand))) {
+      dynGroupprivateSize = operand;
+      if (failed(parser.parseColon()) || failed(parser.parseType(size_type))) {
+        return parser.emitError(parser.getCurrentLocation(),
+                                "expected ':' and type after size operand");
+      }
+    }
+  } else {
+    // No modifiers, try to parse operand directly
+    OpAsmParser::UnresolvedOperand operand;
+    if (succeeded(parser.parseOperand(operand))) {
+      dynGroupprivateSize = operand;
+      if (failed(parser.parseColon()) || failed(parser.parseType(size_type))) {
+        return parser.emitError(parser.getCurrentLocation(),
+                                "expected ':' and type after size operand");
+      }
+    } else {
+      return parser.emitError(parser.getCurrentLocation(),
+                              "expected dyn_groupprivate_size operand");
+    }
+  }
+
+  return success();
+}
+
+static void
+printDynGroupprivateClause(OpAsmPrinter &printer, Operation *op,
+                           DynGroupprivateModifierAttr modifierFirst,
+                           DynGroupprivateModifierAttr modifierSecond,
+                           Value dynGroupprivateSize, Type size_type) {
+
+  bool needsComma = false;
+
+  if (modifierFirst) {
+    printer << modifierFirst.getValue();
+    needsComma = true;
+  }
+
+  if (modifierSecond) {
+    if (needsComma)
+      printer << ", ";
+    printer << modifierSecond.getValue();
+    needsComma = true;
+  }
+
+  if (dynGroupprivateSize) {
+    if (needsComma)
+      printer << " : ";
+    printer << dynGroupprivateSize << " : " << size_type;
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // Parsers for operations including clauses that define entry block arguments.
 //===----------------------------------------------------------------------===//
@@ -2211,6 +2372,8 @@ void TargetOp::build(OpBuilder &builder, OperationState &state,
                   clauses.mapVars, clauses.nowait, clauses.privateVars,
                   makeArrayAttr(ctx, clauses.privateSyms),
                   clauses.privateNeedsBarrier, clauses.threadLimitVars,
+                  clauses.modifierFirst, clauses.modifierSecond,
+                  clauses.dynGroupprivateSize,
                   /*private_maps=*/nullptr);
 }
 
@@ -2225,6 +2388,12 @@ LogicalResult TargetOp::verify() {
   if (failed(verifyMapClause(*this, getMapVars())))
     return failure();
 
+  // check dyn_groupprivate clause restrictions
+  if (failed(verifyDynGroupprivateClause(*this, getModifierFirstAttr(),
+                                         getModifierSecondAttr(),
+                                         getDynGroupprivateSize())))
+    return failure();
+
   return verifyPrivateVarsMapping(*this);
 }
 
@@ -2625,6 +2794,7 @@ void TeamsOp::build(OpBuilder &builder, OperationState &state,
                     const TeamsOperands &clauses) {
   MLIRContext *ctx = builder.getContext();
   // TODO Store clauses in op: privateVars, privateSyms, privateNeedsBarrier
+<<<<<<< HEAD
   TeamsOp::build(
       builder, state, clauses.allocateVars, clauses.allocatorVars,
       clauses.ifExpr, clauses.numTeamsLower, clauses.numTeamsUpperVars,
@@ -2651,6 +2821,17 @@ static LogicalResult verifyNumTeamsClause(Operation *op, Value numTeamsLower,
   }
 
   return success();
+=======
+  TeamsOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
+                 clauses.ifExpr, clauses.numTeamsLower, clauses.numTeamsUpper,
+                 /*private_vars=*/{}, /*private_syms=*/nullptr,
+                 /*private_needs_barrier=*/nullptr, clauses.reductionMod,
+                 clauses.reductionVars,
+                 makeDenseBoolArrayAttr(ctx, clauses.reductionByref),
+                 makeArrayAttr(ctx, clauses.reductionSyms), clauses.threadLimit,
+                 clauses.modifierFirst, clauses.modifierSecond,
+                 clauses.dynGroupprivateSize);
+>>>>>>> [OpenMP][mlir] Add DynGroupPrivateClause in omp dialect
 }
 
 LogicalResult TeamsOp::verify() {
@@ -2675,6 +2856,12 @@ LogicalResult TeamsOp::verify() {
     return emitError(
         "expected equal sizes for allocate and allocator variables");
 
+  // check dyn_groupprivate clause restrictions
+  if (failed(verifyDynGroupprivateClause(op, getModifierFirstAttr(),
+                                         getModifierSecondAttr(),
+                                         getDynGroupprivateSize())))
+    return failure();
+
   return verifyReductionVarList(*this, getReductionSyms(), getReductionVars(),
                                 getReductionByref());
 }
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 022322502a755..2ccac5b020e93 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -390,6 +390,11 @@ static LogicalResult checkImplementationStatus(Operation &op) {
       result = todo("thread_limit with multi-dimensional values");
   };
 
+  auto checkDynGroupprivate = [&todo](auto op, LogicalResult &result) {
+    if (op.getDynGroupprivateSize())
+      result = todo("dyn_groupprivate");
+  };
+
   LogicalResult result = success();
   llvm::TypeSwitch<Operation &>(op)
       .Case([&](omp::DistributeOp op) {
@@ -415,6 +420,7 @@ static LogicalResult checkImplementationStatus(Operation &op) {
         checkPrivate(op, result);
         checkNumTeams(op, result);
         checkThreadLimit(op, result);
+        checkDynGroupprivate(op, result);
       })
       .Case([&](omp::TaskOp op) {
         checkAllocate(op, result);
@@ -454,6 +460,7 @@ static LogicalResult checkImplementationStatus(Operation &op) {
         checkBare(op, result);
         checkInReduction(op, result);
         checkThreadLimit(op, result);
+        checkDynGroupprivate(op, result);
       })
       .Default([](Operation &) {
         // Assume all clauses for an operation can be translated unless they are
diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir
index 4ee9b2c58a5ef..87252419e5dbe 100644
--- a/mlir/test/Dialect/OpenMP/invalid.mlir
+++ b/mlir/test/Dialect/OpenMP/invalid.mlir
@@ -1438,7 +1438,7 @@ func.func @omp_teams_allocate(%data_var : memref<i32>) {
     // expected-error @below {{expected equal sizes for allocate and allocator variables}}
     "omp.teams" (%data_var) ({
       omp.terminator
-    }) {operandSegmentSizes = array<i32: 1,0,0,0,0,0,0,0>} : (memref<i32>) -> ()
+    }) {operandSegmentSizes = array<i32: 1,0,0,0,0,0,0,0,0>} : (memref<i32>) -> ()
     omp.terminator
   }
   return
@@ -1451,7 +1451,7 @@ func.func @omp_teams_num_teams1(%lb : i32) {
     // expected-error @below {{expected exactly one num_teams upper bound when lower bound is specified}}
     "omp.teams" (%lb) ({
       omp.terminator
-    }) {operandSegmentSizes = array<i32: 0,0,0,1,0,0,0,0>} : (i32) -> ()
+    }) {operandSegmentSizes = array<i32: 0,0,0,1,0,0,0,0,0>} : (i32) -> ()
     omp.terminator
   }
   return
@@ -1489,6 +1489,26 @@ func.func @omp_teams_num_teams2(%lb : i32, %ub : i16) {
 
 // -----
 
+func.func @test_teams_dyn_groupprivate_errors_1(%dyn_size: i32) {
+  // expected-error @below {{duplicate dyn_groupprivate modifier 'strict'}}
+  omp.teams dyn_groupprivate(strict, strict : %dyn_size : i32) {
+    omp.terminator
+  }
+  return
+}
+
+// -----
+
+func.func @test_teams_dyn_groupprivate_errors_2(%dyn_size: i32) {
+  // expected-error @below {{incompatible dyn_groupprivate modifiers: 'strict' and 'fallback' cannot be used together}}
+  omp.teams dyn_groupprivate(strict, fallback : %dyn_size : i32) {
+    omp.terminator
+  }
+  return
+}
+
+// -----
+
 func.func @omp_sections(%data_var : memref<i32>) -> () {
   // expected-error @below {{expected equal sizes for allocate and allocator variables}}
   "omp.sections" (%data_var) ({
@@ -2475,12 +2495,26 @@ func.func @omp_target_depend(%data_var: memref<i32>) {
   // expected-error @below {{op expected as many depend values as depend variables}}
     "omp.target"(%data_var) ({
       "omp.terminator"() : () -> ()
-    }) {depend_kinds = [], operandSegmentSizes = array<i32: 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0>} : (memref<i32>) -> ()
+    }) {depend_kinds = [], operandSegmentSizes = array<i32: 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>} : (memref<i32>) -> ()
    "func.return"() : () -> ()
 }
 
 // -----
 
+func.func @test_target_dyn_groupprivate_errors(%dyn_size: i32) {
+  // expected-error @below {{duplicate dyn_groupprivate modifier 'strict'}}
+  omp.target dyn_groupprivate(strict, strict : %dyn_size : i32) {
+    omp.terminator
+  }
+  // expected-error @below {{incompatible dyn_groupprivate modifiers: 'strict' and 'fallback' cannot be used together}}
+  omp.target dyn_groupprivate(strict, fallback : %dyn_size : i32) {
+    omp.terminator
+  }
+  return
+}
+
+// -----
+
 func.func @omp_distribute_schedule(%chunk_size : i32, %lb : i32, %ub : i32, %step : i32) -> () {
   // expected-error @below {{op chunk size set without dist_schedule_static being present}}
   "omp.distribute"(%chunk_size) <{operandSegmentSizes = array<i32: 0, 0, 1, 0>}> ({
diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir
index 1e8c9bdeb33ae..a6fde0e66515d 100644
--- a/mlir/test/Dialect/OpenMP/ops.mlir
+++ b/mlir/test/Dialect/OpenMP/ops.mlir
@@ -836,7 +836,7 @@ func.func @omp_target(%if_cond : i1, %device : si32,  %num_threads : i32, %devic
     "omp.target"(%device, %if_cond, %num_threads) ({
        // CHECK: omp.terminator
        omp.terminator
-    }) {nowait, operandSegmentSizes = array<i32: 0,0,0,1,0,0,1,0,0,0,0,1>} : ( si32, i1, i32 ) -> ()
+    }) {nowait, operandSegmentSizes = array<i32: 0,0,0,1,0,0,1,0,0,0,0,1,0>} : ( si32, i1, i32 ) -> ()
 
     // Test with optional map clause.
     // CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[VAL_1:.*]] : memref<?xi32>, tensor<?xi32>)   map_clauses(always, to) capture(ByRef) -> memref<?xi32> {name = ""}
@@ -1089,7 +1089,8 @@ func.func @parallel_wsloop_reduction(%lb : index, %ub : index, %step : index) {
 
 // CHECK-LABEL: omp_teams
 func.func @omp_teams(%lb : i32, %ub : i32, %if_cond : i1, %num_threads : i32,
-                     %data_var : memref<i32>, %ub64 : i64, %ub16 : i16) -> () {
+                     %data_var : memref<i32>, %ub64 : i64, %ub16 : i16,
+                     %dyn_size : i32,) -> () {
   // Test nesting inside of omp.target
   omp.target {
     // CHECK: omp.teams
@@ -1185,6 +1186,13 @@ func.func @omp_teams(%lb : i32, %ub : i32, %if_cond : i1, %num_threads : i32,
     // CHECK: omp.terminator
     omp.terminator
   }
+  
+  // Test dyn_groupprivate
+  // CHECK: omp.teams dyn_groupprivate(cgroup, strict : %{{.+}} : i32)
+  omp.teams dyn_groupprivate(cgroup, strict : %dyn_size : i32) {
+    // CHECK: omp.terminator
+    omp.terminator
+  }
 
   return
 }
@@ -2246,6 +2254,28 @@ func.func @omp_target_depend(%arg0: memref<i32>, %arg1: memref<i32>) {
   return
 }
 
+// CHECK-LABEL: @omp_target_dyn_groupprivate
+func.func @omp_target_dyn_groupprivate(%dyn_size: i32, %large_size: i64) {
+  // CHECK: omp.target dyn_groupprivate(strict, cgroup : %{{.*}} : i32)
+  omp.target dyn_groupprivate(strict, cgroup : %dyn_size : i32) {
+    // CHECK: omp.terminator
+    omp.terminator
+  }
+  // CHECK: omp.target dyn_groupprivate(cgroup : %{{.*}} : i64)
+  omp.target dyn_groupprivate(cgroup : %large_size : i64) {
+    omp.terminator
+  }
+  // CHECK: omp.target dyn_groupprivate(fallback, cgroup : %{{.*}} : i32)
+  omp.target dyn_groupprivate(fallback, cgroup : %dyn_size : i32) {
+    omp.terminator
+  }
+  // CHECK: omp.target dyn_groupprivate(%{{.*}} : i64)
+  omp.target dyn_groupprivate(%large_size : i64) {
+    omp.terminator
+  }
+  return
+}
+
 func.func @omp_threadprivate() {
   %0 = arith.constant 1 : i32
   %1 = arith.constant 2 : i32

>From ec63a14f47b441fdd85eeefa109374fe64a7b9a2 Mon Sep 17 00:00:00 2001
From: skc7 <Krishna.Sankisa at amd.com>
Date: Mon, 27 Oct 2025 18:04:20 +0530
Subject: [PATCH 2/4] Update to use fallback modifiers

---
 .../Optimizer/OpenMP/LowerWorkdistribute.cpp  |  10 +-
 .../mlir/Dialect/OpenMP/OpenMPClauses.td      |  10 +-
 .../mlir/Dialect/OpenMP/OpenMPEnums.td        |  37 ++--
 mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp  | 203 +++++++-----------
 mlir/test/Dialect/OpenMP/invalid.mlir         |  54 +++--
 mlir/test/Dialect/OpenMP/ops.mlir             |  22 +-
 6 files changed, 166 insertions(+), 170 deletions(-)

diff --git a/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp b/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp
index 2c7980064500f..62cbe805fbb89 100644
--- a/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp
+++ b/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp
@@ -766,7 +766,9 @@ FailureOr<omp::TargetOp> splitTargetData(omp::TargetOp targetOp,
       targetOp.getInReductionSymsAttr(), targetOp.getIsDevicePtrVars(),
       innerMapInfos, targetOp.getNowaitAttr(), targetOp.getPrivateVars(),
       targetOp.getPrivateSymsAttr(), targetOp.getPrivateNeedsBarrierAttr(),
-      targetOp.getThreadLimitVars(), targetOp.getPrivateMapsAttr());
+      targetOp.getThreadLimitVars(), targetOp.getAccessGroupAttr(),
+      targetOp.getFallbackAttr(), targetOp.getDynGroupprivateSize(),
+      targetOp.getPrivateMapsAttr());
   rewriter.inlineRegionBefore(targetOp.getRegion(), newTargetOp.getRegion(),
                               newTargetOp.getRegion().begin());
   rewriter.replaceOp(targetOp, targetDataOp);
@@ -1486,6 +1488,8 @@ genPreTargetOp(omp::TargetOp targetOp, SmallVector<Value> &preMapOperands,
       targetOp.getIsDevicePtrVars(), preMapOperands, targetOp.getNowaitAttr(),
       targetOp.getPrivateVars(), targetOp.getPrivateSymsAttr(),
       targetOp.getPrivateNeedsBarrierAttr(), targetOp.getThreadLimitVars(),
+      targetOp.getAccessGroupAttr(), targetOp.getFallbackAttr(),
+      targetOp.getDynGroupprivateSize(),
       targetOp.getPrivateMapsAttr());
   auto *preTargetBlock = rewriter.createBlock(
       &preTargetOp.getRegion(), preTargetOp.getRegion().begin(), {}, {});
@@ -1576,6 +1580,8 @@ genIsolatedTargetOp(omp::TargetOp targetOp, SmallVector<Value> &postMapOperands,
       targetOp.getIsDevicePtrVars(), postMapOperands, targetOp.getNowaitAttr(),
       targetOp.getPrivateVars(), targetOp.getPrivateSymsAttr(),
       targetOp.getPrivateNeedsBarrierAttr(), targetOp.getThreadLimitVars(),
+      targetOp.getAccessGroupAttr(), targetOp.getFallbackAttr(),
+      targetOp.getDynGroupprivateSize(),
       targetOp.getPrivateMapsAttr());
   auto *isolatedTargetBlock =
       rewriter.createBlock(&isolatedTargetOp.getRegion(),
@@ -1656,6 +1662,8 @@ static omp::TargetOp genPostTargetOp(omp::TargetOp targetOp,
       targetOp.getIsDevicePtrVars(), postMapOperands, targetOp.getNowaitAttr(),
       targetOp.getPrivateVars(), targetOp.getPrivateSymsAttr(),
       targetOp.getPrivateNeedsBarrierAttr(), targetOp.getThreadLimitVars(),
+      targetOp.getAccessGroupAttr(), targetOp.getFallbackAttr(),
+      targetOp.getDynGroupprivateSize(),
       targetOp.getPrivateMapsAttr());
   // Create the block for postTargetOp
   auto *postTargetBlock = rewriter.createBlock(
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
index 571abad1bfc74..5f07f1115f2e9 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
@@ -1703,8 +1703,8 @@ class OpenMP_DynGroupprivateClauseSkip<
                     extraClassDeclaration> {
 
   let arguments = (ins
-    OptionalAttr<DynGroupprivateModifierAttr>:$modifier_first,
-    OptionalAttr<DynGroupprivateModifierAttr>:$modifier_second,
+    OptionalAttr<AccessGroupModifierAttr>:$accessGroup,
+    OptionalAttr<FallbackModifierAttr>:$fallback,
     Optional<AnyInteger>:$dyn_groupprivate_size
   );
 
@@ -1716,18 +1716,18 @@ class OpenMP_DynGroupprivateClauseSkip<
 
     Syntax:
     ```
-    dyn_groupprivate(modifier_first ,modifier_second : dyn_groupprivate_size)
+    dyn_groupprivate(cgroup, fallback(abort), %size)
     ```
 
     Example:
     ```
-    omp.target dyn_groupprivate(strict, cgroup : %dyn_groupprivate_size : i32)
+    omp.target dyn_groupprivate(cgroup, fallback(default_mem), %size : i32)
     ```
   }];
 
   let optAssemblyFormat = [{
     `dyn_groupprivate` `(`
-      custom<DynGroupprivateClause>($modifier_first, $modifier_second, 
+      custom<DynGroupprivateClause>($accessGroup, $fallback, 
       $dyn_groupprivate_size, type($dyn_groupprivate_size))
     `)`
   }];
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td
index 57021dfc0daad..7fb501a15761c 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td
@@ -332,23 +332,36 @@ def VariableCaptureKindAttr : OpenMP_EnumAttr<VariableCaptureKind,
 }
 
 //===----------------------------------------------------------------------===//
-// dyn_groupprivate enum.
+// dyn_groupprivate enums.
 //===----------------------------------------------------------------------===//
 
-def DynGroupprivateCGroup : I32EnumAttrCase<"cgroup", 0>;
-def DynGroupprivateStrict : I32EnumAttrCase<"strict", 1>;
-def DynGroupprivateFallback : I32EnumAttrCase<"fallback", 2>;
+def AccessGroupCGroup : I32EnumAttrCase<"cgroup", 0>;
 
-def DynGroupprivateModifier : OpenMP_I32EnumAttr<
-    "DynGroupprivateModifier",
-    "dyn_groupprivate modifier", [
-      DynGroupprivateCGroup,
-      DynGroupprivateStrict,
-      DynGroupprivateFallback
+def AccessGroupModifier : OpenMP_I32EnumAttr<
+    "AccessGroupModifier",
+    "access group modifier", [
+      AccessGroupCGroup
     ]>;
 
-def DynGroupprivateModifierAttr : OpenMP_EnumAttr<DynGroupprivateModifier,
-                                            "dyn_groupprivate_modifier"> {
+def AccessGroupModifierAttr : OpenMP_EnumAttr<AccessGroupModifier,
+                                            "access_group_modifier"> {
+  let assemblyFormat = "`(` $value `)`";
+}
+
+def FallbackAbort : I32EnumAttrCase<"abort", 0>;
+def FallbackNull : I32EnumAttrCase<"null", 1>;
+def FallbackDefaultMem : I32EnumAttrCase<"default_mem", 2>;
+
+def FallbackModifier : OpenMP_I32EnumAttr<
+    "FallbackModifier",
+    "fallback modifier", [
+      FallbackAbort,
+      FallbackNull,
+      FallbackDefaultMem
+    ]>;
+
+def FallbackModifierAttr : OpenMP_EnumAttr<FallbackModifier,
+                                            "fallback_modifier"> {
   let assemblyFormat = "`(` $value `)`";
 }
 
diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
index fbf3ab31ccb22..64d4c9a347c0a 100644
--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
@@ -803,44 +803,8 @@ static void printNumTasksClause(OpAsmPrinter &p, Operation *op,
 //===----------------------------------------------------------------------===//
 
 static LogicalResult verifyDynGroupprivateClause(
-    Operation *op, DynGroupprivateModifierAttr modifierFirst,
-    DynGroupprivateModifierAttr modifierSecond, Value dynGroupprivateSize) {
-
-  // Helper to get modifier name as string
-  auto getModifierName = [](DynGroupprivateModifier mod) -> StringRef {
-    switch (mod) {
-    case DynGroupprivateModifier::strict:
-      return "strict";
-    case DynGroupprivateModifier::cgroup:
-      return "cgroup";
-    case DynGroupprivateModifier::fallback:
-      return "fallback";
-    }
-    return "unknown";
-  };
-
-  // Check for duplicate modifiers
-  if (modifierFirst && modifierSecond &&
-      modifierFirst.getValue() == modifierSecond.getValue()) {
-    return op->emitOpError("duplicate dyn_groupprivate modifier '")
-           << getModifierName(modifierFirst.getValue()) << "'";
-  }
-
-  // Check for incompatible modifier combinations
-  if (modifierFirst && modifierSecond) {
-    auto m1 = modifierFirst.getValue();
-    auto m2 = modifierSecond.getValue();
-
-    // strict and fallback are incompatible
-    if ((m1 == DynGroupprivateModifier::strict &&
-         m2 == DynGroupprivateModifier::fallback) ||
-        (m1 == DynGroupprivateModifier::fallback &&
-         m2 == DynGroupprivateModifier::strict)) {
-      return op->emitOpError("incompatible dyn_groupprivate modifiers: '")
-             << getModifierName(m1) << "' and '" << getModifierName(m2)
-             << "' cannot be used together";
-    }
-  }
+    Operation *op, AccessGroupModifierAttr modifierFirst,
+    FallbackModifierAttr modifierSecond, Value dynGroupprivateSize) {
 
   // Verify the size
   if (dynGroupprivateSize) {
@@ -857,86 +821,83 @@ static LogicalResult verifyDynGroupprivateClause(
 }
 
 static ParseResult parseDynGroupprivateClause(
-    OpAsmParser &parser, DynGroupprivateModifierAttr &modifierFirst,
-    DynGroupprivateModifierAttr &modifierSecond,
+    OpAsmParser &parser, AccessGroupModifierAttr &accessGroupAttr,
+    FallbackModifierAttr &fallbackAttr,
     std::optional<OpAsmParser::UnresolvedOperand> &dynGroupprivateSize,
-    Type &size_type) {
-
-  bool hasModifiers = false;
-
-  // Parse first modifier if present
-  if (succeeded(parser.parseOptionalKeyword("strict"))) {
-    modifierFirst = DynGroupprivateModifierAttr::get(
-        parser.getContext(), DynGroupprivateModifier::strict);
-    hasModifiers = true;
-  } else if (succeeded(parser.parseOptionalKeyword("cgroup"))) {
-    modifierFirst = DynGroupprivateModifierAttr::get(
-        parser.getContext(), DynGroupprivateModifier::cgroup);
-    hasModifiers = true;
-  } else if (succeeded(parser.parseOptionalKeyword("fallback"))) {
-    modifierFirst = DynGroupprivateModifierAttr::get(
-        parser.getContext(), DynGroupprivateModifier::fallback);
-    hasModifiers = true;
-  }
+    Type &sizeType) {
 
-  // If first modifier found, check for comma and second modifier
-  if (hasModifiers && succeeded(parser.parseOptionalComma())) {
-    if (succeeded(parser.parseOptionalKeyword("strict"))) {
-      modifierSecond = DynGroupprivateModifierAttr::get(
-          parser.getContext(), DynGroupprivateModifier::strict);
-    } else if (succeeded(parser.parseOptionalKeyword("cgroup"))) {
-      modifierSecond = DynGroupprivateModifierAttr::get(
-          parser.getContext(), DynGroupprivateModifier::cgroup);
-    } else if (succeeded(parser.parseOptionalKeyword("fallback"))) {
-      modifierSecond = DynGroupprivateModifierAttr::get(
-          parser.getContext(), DynGroupprivateModifier::fallback);
-    } else {
-      return parser.emitError(parser.getCurrentLocation(),
-                              "expected modifier after comma");
-    }
-  }
+  bool parsedAccessGroup = false;
+  bool parsedFallback = false;
 
-  // Parse colon and size if modifiers were present, or just try to parse
-  // operand
-  if (hasModifiers) {
-    // Modifiers present, expect colon
-    if (failed(parser.parseColon())) {
-      return parser.emitError(parser.getCurrentLocation(),
-                              "expected ':' after modifiers");
-    }
-
-    // Parse operand and type
-    OpAsmParser::UnresolvedOperand operand;
-    if (succeeded(parser.parseOperand(operand))) {
-      dynGroupprivateSize = operand;
-      if (failed(parser.parseColon()) || failed(parser.parseType(size_type))) {
+  // Parse modifiers separated by commas
+  while (true) {
+    // parse AccessGroupModifier
+    if (succeeded(parser.parseOptionalKeyword("cgroup"))) {
+      if (parsedAccessGroup)
         return parser.emitError(parser.getCurrentLocation(),
-                                "expected ':' and type after size operand");
-      }
+                                "duplicate access group modifier");
+      accessGroupAttr = AccessGroupModifierAttr::get(
+          parser.getContext(), AccessGroupModifier::cgroup);
+      parsedAccessGroup = true;
     }
-  } else {
-    // No modifiers, try to parse operand directly
-    OpAsmParser::UnresolvedOperand operand;
-    if (succeeded(parser.parseOperand(operand))) {
-      dynGroupprivateSize = operand;
-      if (failed(parser.parseColon()) || failed(parser.parseType(size_type))) {
+    // parse FallbackModifier
+    else if (succeeded(parser.parseOptionalKeyword("fallback"))) {
+      if (parsedFallback)
         return parser.emitError(parser.getCurrentLocation(),
-                                "expected ':' and type after size operand");
-      }
-    } else {
+                                "duplicate fallback modifier");
+      if (parser.parseLParen())
+        return parser.emitError(parser.getCurrentLocation(),
+                                "expected '(' after 'fallback'");
+      llvm::StringRef fbKind;
+      if (parser.parseKeyword(&fbKind))
+        return parser.emitError(
+            parser.getCurrentLocation(),
+            "expected fallback modifier (abort/null/default_mem)");
+      std::optional<FallbackModifier> fbEnum;
+      if (fbKind == "abort")
+        fbEnum = FallbackModifier::abort;
+      else if (fbKind == "null")
+        fbEnum = FallbackModifier::null;
+      else if (fbKind == "default_mem")
+        fbEnum = FallbackModifier::default_mem;
+      else
+        return parser.emitError(parser.getCurrentLocation(),
+                                "invalid fallback modifier '" + fbKind + "'");
+      fallbackAttr = FallbackModifierAttr::get(parser.getContext(), *fbEnum);
+      if (parser.parseRParen())
+        return parser.emitError(parser.getCurrentLocation(),
+                                "expected ')' after fallback modifier");
+      parsedFallback = true;
+    } else
+      break;
+
+    // Consume optional comma between modifiers
+    (void)parser.parseOptionalComma();
+  }
+
+  // Consume comma after modifiers, if both modifiers are present
+  (void)parser.parseOptionalComma();
+
+  OpAsmParser::UnresolvedOperand operand;
+  if (succeeded(parser.parseOperand(operand))) {
+    dynGroupprivateSize = operand;
+    if (failed(parser.parseColon()) || failed(parser.parseType(sizeType))) {
       return parser.emitError(parser.getCurrentLocation(),
-                              "expected dyn_groupprivate_size operand");
+                              "expected ':' and type after size operand");
     }
+  } else {
+    return parser.emitError(parser.getCurrentLocation(),
+                            "expected dyn_groupprivate_size operand");
   }
 
   return success();
 }
 
-static void
-printDynGroupprivateClause(OpAsmPrinter &printer, Operation *op,
-                           DynGroupprivateModifierAttr modifierFirst,
-                           DynGroupprivateModifierAttr modifierSecond,
-                           Value dynGroupprivateSize, Type size_type) {
+static void printDynGroupprivateClause(OpAsmPrinter &printer, Operation *op,
+                                       AccessGroupModifierAttr modifierFirst,
+                                       FallbackModifierAttr modifierSecond,
+                                       Value dynGroupprivateSize,
+                                       Type sizeType) {
 
   bool needsComma = false;
 
@@ -948,14 +909,16 @@ printDynGroupprivateClause(OpAsmPrinter &printer, Operation *op,
   if (modifierSecond) {
     if (needsComma)
       printer << ", ";
+    printer << "fallback(";
     printer << modifierSecond.getValue();
+    printer << ")";
     needsComma = true;
   }
 
   if (dynGroupprivateSize) {
     if (needsComma)
-      printer << " : ";
-    printer << dynGroupprivateSize << " : " << size_type;
+      printer << ", ";
+    printer << dynGroupprivateSize << " : " << sizeType;
   }
 }
 
@@ -2372,7 +2335,7 @@ void TargetOp::build(OpBuilder &builder, OperationState &state,
                   clauses.mapVars, clauses.nowait, clauses.privateVars,
                   makeArrayAttr(ctx, clauses.privateSyms),
                   clauses.privateNeedsBarrier, clauses.threadLimitVars,
-                  clauses.modifierFirst, clauses.modifierSecond,
+                  clauses.accessGroup, clauses.fallback,
                   clauses.dynGroupprivateSize,
                   /*private_maps=*/nullptr);
 }
@@ -2389,8 +2352,8 @@ LogicalResult TargetOp::verify() {
     return failure();
 
   // check dyn_groupprivate clause restrictions
-  if (failed(verifyDynGroupprivateClause(*this, getModifierFirstAttr(),
-                                         getModifierSecondAttr(),
+  if (failed(verifyDynGroupprivateClause(*this, getAccessGroupAttr(),
+                                         getFallbackAttr(),
                                          getDynGroupprivateSize())))
     return failure();
 
@@ -2794,7 +2757,6 @@ void TeamsOp::build(OpBuilder &builder, OperationState &state,
                     const TeamsOperands &clauses) {
   MLIRContext *ctx = builder.getContext();
   // TODO Store clauses in op: privateVars, privateSyms, privateNeedsBarrier
-<<<<<<< HEAD
   TeamsOp::build(
       builder, state, clauses.allocateVars, clauses.allocatorVars,
       clauses.ifExpr, clauses.numTeamsLower, clauses.numTeamsUpperVars,
@@ -2802,7 +2764,9 @@ void TeamsOp::build(OpBuilder &builder, OperationState &state,
       /*private_needs_barrier=*/nullptr, clauses.reductionMod,
       clauses.reductionVars,
       makeDenseBoolArrayAttr(ctx, clauses.reductionByref),
-      makeArrayAttr(ctx, clauses.reductionSyms), clauses.threadLimitVars);
+      makeArrayAttr(ctx, clauses.reductionSyms), clauses.threadLimitVars,
+      clauses.accessGroup, clauses.fallback,
+      clauses.dynGroupprivateSize);
 }
 
 // Verify num_teams clause
@@ -2821,17 +2785,6 @@ static LogicalResult verifyNumTeamsClause(Operation *op, Value numTeamsLower,
   }
 
   return success();
-=======
-  TeamsOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
-                 clauses.ifExpr, clauses.numTeamsLower, clauses.numTeamsUpper,
-                 /*private_vars=*/{}, /*private_syms=*/nullptr,
-                 /*private_needs_barrier=*/nullptr, clauses.reductionMod,
-                 clauses.reductionVars,
-                 makeDenseBoolArrayAttr(ctx, clauses.reductionByref),
-                 makeArrayAttr(ctx, clauses.reductionSyms), clauses.threadLimit,
-                 clauses.modifierFirst, clauses.modifierSecond,
-                 clauses.dynGroupprivateSize);
->>>>>>> [OpenMP][mlir] Add DynGroupPrivateClause in omp dialect
 }
 
 LogicalResult TeamsOp::verify() {
@@ -2857,8 +2810,8 @@ LogicalResult TeamsOp::verify() {
         "expected equal sizes for allocate and allocator variables");
 
   // check dyn_groupprivate clause restrictions
-  if (failed(verifyDynGroupprivateClause(op, getModifierFirstAttr(),
-                                         getModifierSecondAttr(),
+  if (failed(verifyDynGroupprivateClause(op, getAccessGroupAttr(),
+                                         getFallbackAttr(),
                                          getDynGroupprivateSize())))
     return failure();
 
diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir
index 87252419e5dbe..c5707ebea18b6 100644
--- a/mlir/test/Dialect/OpenMP/invalid.mlir
+++ b/mlir/test/Dialect/OpenMP/invalid.mlir
@@ -1490,8 +1490,8 @@ func.func @omp_teams_num_teams2(%lb : i32, %ub : i16) {
 // -----
 
 func.func @test_teams_dyn_groupprivate_errors_1(%dyn_size: i32) {
-  // expected-error @below {{duplicate dyn_groupprivate modifier 'strict'}}
-  omp.teams dyn_groupprivate(strict, strict : %dyn_size : i32) {
+  // expected-error @below {{duplicate access group modifier}}
+  omp.teams dyn_groupprivate(cgroup, cgroup, %dyn_size : i32) {
     omp.terminator
   }
   return
@@ -1500,8 +1500,40 @@ func.func @test_teams_dyn_groupprivate_errors_1(%dyn_size: i32) {
 // -----
 
 func.func @test_teams_dyn_groupprivate_errors_2(%dyn_size: i32) {
-  // expected-error @below {{incompatible dyn_groupprivate modifiers: 'strict' and 'fallback' cannot be used together}}
-  omp.teams dyn_groupprivate(strict, fallback : %dyn_size : i32) {
+  // expected-error @below {{duplicate fallback modifier}}
+  omp.teams dyn_groupprivate(fallback(null), fallback(abort), %dyn_size : i32) {
+    omp.terminator
+  }
+  return
+}
+
+// -----
+
+func.func @test_teams_dyn_groupprivate_errors_3(%dyn_size: i32) {
+  // expected-error @below {{invalid fallback modifier 'no'}}
+  omp.teams dyn_groupprivate(fallback(no), %dyn_size : i32) {
+    omp.terminator
+  }
+  return
+}
+
+// -----
+
+func.func @test_teams_dyn_groupprivate_errors_4(%dyn_size: i32) {
+  // expected-error @below {{custom op 'omp.teams' expected dyn_groupprivate_size operand}}
+  // expected-error @below {{expected SSA operand}}
+  omp.teams dyn_groupprivate(fallback(null)) {
+    omp.terminator
+  }
+  return
+}
+
+// -----
+
+func.func @test_teams_dyn_groupprivate_errors_5() {
+  // expected-error @below {{expected dyn_groupprivate_size operand}}
+  // expected-error @below {{expected SSA operand}}
+  omp.teams dyn_groupprivate() {
     omp.terminator
   }
   return
@@ -2501,20 +2533,6 @@ func.func @omp_target_depend(%data_var: memref<i32>) {
 
 // -----
 
-func.func @test_target_dyn_groupprivate_errors(%dyn_size: i32) {
-  // expected-error @below {{duplicate dyn_groupprivate modifier 'strict'}}
-  omp.target dyn_groupprivate(strict, strict : %dyn_size : i32) {
-    omp.terminator
-  }
-  // expected-error @below {{incompatible dyn_groupprivate modifiers: 'strict' and 'fallback' cannot be used together}}
-  omp.target dyn_groupprivate(strict, fallback : %dyn_size : i32) {
-    omp.terminator
-  }
-  return
-}
-
-// -----
-
 func.func @omp_distribute_schedule(%chunk_size : i32, %lb : i32, %ub : i32, %step : i32) -> () {
   // expected-error @below {{op chunk size set without dist_schedule_static being present}}
   "omp.distribute"(%chunk_size) <{operandSegmentSizes = array<i32: 0, 0, 1, 0>}> ({
diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir
index a6fde0e66515d..7cb1a0d597faf 100644
--- a/mlir/test/Dialect/OpenMP/ops.mlir
+++ b/mlir/test/Dialect/OpenMP/ops.mlir
@@ -1188,8 +1188,8 @@ func.func @omp_teams(%lb : i32, %ub : i32, %if_cond : i1, %num_threads : i32,
   }
   
   // Test dyn_groupprivate
-  // CHECK: omp.teams dyn_groupprivate(cgroup, strict : %{{.+}} : i32)
-  omp.teams dyn_groupprivate(cgroup, strict : %dyn_size : i32) {
+  // CHECK: omp.teams dyn_groupprivate(cgroup, fallback(null), %{{.+}} : i32)
+  omp.teams dyn_groupprivate(cgroup, fallback(null), %dyn_size : i32) {
     // CHECK: omp.terminator
     omp.terminator
   }
@@ -2256,17 +2256,21 @@ func.func @omp_target_depend(%arg0: memref<i32>, %arg1: memref<i32>) {
 
 // CHECK-LABEL: @omp_target_dyn_groupprivate
 func.func @omp_target_dyn_groupprivate(%dyn_size: i32, %large_size: i64) {
-  // CHECK: omp.target dyn_groupprivate(strict, cgroup : %{{.*}} : i32)
-  omp.target dyn_groupprivate(strict, cgroup : %dyn_size : i32) {
-    // CHECK: omp.terminator
+  // CHECK: omp.target dyn_groupprivate(%{{.*}} : i32)
+  omp.target dyn_groupprivate(%dyn_size : i32) {
+    omp.terminator
+  }
+  // CHECK: omp.target dyn_groupprivate(cgroup, %{{.*}} : i64)
+  omp.target dyn_groupprivate(cgroup, %large_size : i64) {
     omp.terminator
   }
-  // CHECK: omp.target dyn_groupprivate(cgroup : %{{.*}} : i64)
-  omp.target dyn_groupprivate(cgroup : %large_size : i64) {
+  // CHECK: omp.target dyn_groupprivate(cgroup, fallback(abort), %{{.*}} : i32)
+  omp.target dyn_groupprivate(cgroup, fallback(abort), %dyn_size : i32) {
+    // CHECK: omp.terminator
     omp.terminator
   }
-  // CHECK: omp.target dyn_groupprivate(fallback, cgroup : %{{.*}} : i32)
-  omp.target dyn_groupprivate(fallback, cgroup : %dyn_size : i32) {
+  // CHECK: omp.target dyn_groupprivate(cgroup, fallback(null), %{{.*}} : i32)
+  omp.target dyn_groupprivate(fallback(null), cgroup, %dyn_size : i32) {
     omp.terminator
   }
   // CHECK: omp.target dyn_groupprivate(%{{.*}} : i64)

>From dc72a63aca85a99583493ec832ea2b0b8b2eaef0 Mon Sep 17 00:00:00 2001
From: skc7 <Krishna.Sankisa at amd.com>
Date: Tue, 11 Nov 2025 14:45:05 +0530
Subject: [PATCH 3/4] Update ompBuilder->createTraget for dyn_groupprivate
 translation

---
 .../OpenMP/OpenMPToLLVMIRTranslation.cpp      | 30 ++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 2ccac5b020e93..f51ecd01c16ae 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -6383,6 +6383,25 @@ initTargetRuntimeAttrs(llvm::IRBuilderBase &builder,
   }
 }
 
+static llvm::omp::OMPDynGroupprivateFallbackType
+getFallbackType(omp::TargetOp targetOp) {
+  if (!targetOp.getFallbackAttr())
+    return llvm::omp::OMPDynGroupprivateFallbackType::DefaultMem;
+
+  // Extract the FallbackModifier enum value.
+  mlir::omp::FallbackModifier fb = targetOp.getFallbackAttr().getValue();
+  switch (fb) {
+  case mlir::omp::FallbackModifier::abort:
+    return llvm::omp::OMPDynGroupprivateFallbackType::Abort;
+  case mlir::omp::FallbackModifier::null:
+    return llvm::omp::OMPDynGroupprivateFallbackType::Null;
+  case mlir::omp::FallbackModifier::default_mem:
+    return llvm::omp::OMPDynGroupprivateFallbackType::DefaultMem;
+  }
+
+  llvm_unreachable("unexpected dyn_groupprivate fallback type");
+}
+
 static LogicalResult
 convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
                  LLVM::ModuleTranslation &moduleTranslation) {
@@ -6683,11 +6702,20 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
   if (Value targetIfCond = targetOp.getIfExpr())
     ifCond = moduleTranslation.lookupValue(targetIfCond);
 
+  mlir::Value dynGroupPrivateSize = targetOp.getDynGroupprivateSize();
+  llvm::Value *dynSizeVal = nullptr;
+  if (dynGroupPrivateSize)
+    dynSizeVal = moduleTranslation.lookupValue(dynGroupPrivateSize);
+
+  llvm::omp::OMPDynGroupprivateFallbackType fallbackType =
+      getFallbackType(targetOp);
+
   llvm::OpenMPIRBuilder::InsertPointOrErrorTy afterIP =
       moduleTranslation.getOpenMPBuilder()->createTarget(
           ompLoc, isOffloadEntry, allocaIP, builder.saveIP(), info, entryInfo,
           defaultAttrs, runtimeAttrs, ifCond, kernelInput, genMapInfoCB, bodyCB,
-          argAccessorCB, customMapperCB, dds, targetOp.getNowait());
+          argAccessorCB, customMapperCB, dds, targetOp.getNowait(), dynSizeVal,
+          fallbackType);
 
   if (failed(handleError(afterIP, opInst)))
     return failure();

>From 2cd384b2808e3ee6245d648918a220133f643754 Mon Sep 17 00:00:00 2001
From: skc7 <Krishna.Sankisa at amd.com>
Date: Wed, 28 Jan 2026 14:22:59 +0530
Subject: [PATCH 4/4] Fixes after rebase to latest

---
 mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td     |  4 ++--
 .../Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp      |  1 -
 mlir/test/Dialect/OpenMP/invalid.mlir                 |  2 +-
 mlir/test/Dialect/OpenMP/ops.mlir                     |  4 ++--
 mlir/test/Target/LLVMIR/openmp-todo.mlir              | 11 +++++++++++
 5 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
index 5f07f1115f2e9..7807673d3cba5 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
@@ -1703,7 +1703,7 @@ class OpenMP_DynGroupprivateClauseSkip<
                     extraClassDeclaration> {
 
   let arguments = (ins
-    OptionalAttr<AccessGroupModifierAttr>:$accessGroup,
+    OptionalAttr<AccessGroupModifierAttr>:$access_group,
     OptionalAttr<FallbackModifierAttr>:$fallback,
     Optional<AnyInteger>:$dyn_groupprivate_size
   );
@@ -1727,7 +1727,7 @@ class OpenMP_DynGroupprivateClauseSkip<
 
   let optAssemblyFormat = [{
     `dyn_groupprivate` `(`
-      custom<DynGroupprivateClause>($accessGroup, $fallback, 
+      custom<DynGroupprivateClause>($access_group, $fallback,
       $dyn_groupprivate_size, type($dyn_groupprivate_size))
     `)`
   }];
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index f51ecd01c16ae..2cfc409635dd9 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -460,7 +460,6 @@ static LogicalResult checkImplementationStatus(Operation &op) {
         checkBare(op, result);
         checkInReduction(op, result);
         checkThreadLimit(op, result);
-        checkDynGroupprivate(op, result);
       })
       .Default([](Operation &) {
         // Assume all clauses for an operation can be translated unless they are
diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir
index c5707ebea18b6..1e26e24afe0c2 100644
--- a/mlir/test/Dialect/OpenMP/invalid.mlir
+++ b/mlir/test/Dialect/OpenMP/invalid.mlir
@@ -1468,7 +1468,7 @@ func.func @omp_teams_num_teams_multidim_with_bounds() {
     // expected-error @below {{expected exactly one num_teams upper bound when lower bound is specified}}
     "omp.teams" (%lb, %v0, %v1) ({
       omp.terminator
-    }) {operandSegmentSizes = array<i32: 0,0,0,1,2,0,0,0>} : (i32, i32, i32) -> ()
+    }) {operandSegmentSizes = array<i32: 0,0,0,1,2,0,0,0,0>} : (i32, i32, i32) -> ()
     omp.terminator
   }
   return
diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir
index 7cb1a0d597faf..ee42c39635d1d 100644
--- a/mlir/test/Dialect/OpenMP/ops.mlir
+++ b/mlir/test/Dialect/OpenMP/ops.mlir
@@ -1090,7 +1090,7 @@ func.func @parallel_wsloop_reduction(%lb : index, %ub : index, %step : index) {
 // CHECK-LABEL: omp_teams
 func.func @omp_teams(%lb : i32, %ub : i32, %if_cond : i1, %num_threads : i32,
                      %data_var : memref<i32>, %ub64 : i64, %ub16 : i16,
-                     %dyn_size : i32,) -> () {
+                     %dyn_size : i32) -> () {
   // Test nesting inside of omp.target
   omp.target {
     // CHECK: omp.teams
@@ -1186,7 +1186,7 @@ func.func @omp_teams(%lb : i32, %ub : i32, %if_cond : i1, %num_threads : i32,
     // CHECK: omp.terminator
     omp.terminator
   }
-  
+
   // Test dyn_groupprivate
   // CHECK: omp.teams dyn_groupprivate(cgroup, fallback(null), %{{.+}} : i32)
   omp.teams dyn_groupprivate(cgroup, fallback(null), %dyn_size : i32) {
diff --git a/mlir/test/Target/LLVMIR/openmp-todo.mlir b/mlir/test/Target/LLVMIR/openmp-todo.mlir
index 36338e5cb1bed..de00d51e9f81b 100644
--- a/mlir/test/Target/LLVMIR/openmp-todo.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-todo.mlir
@@ -465,6 +465,17 @@ llvm.func @teams_thread_limit_multi_dim(%lb : i32, %ub : i32) {
 
 // -----
 
+llvm.func @teams_dyn_groupprivate(%dyn_size : i32) {
+  // expected-error at below {{not yet implemented: Unhandled clause dyn_groupprivate in omp.teams operation}}
+  // expected-error at below {{LLVM Translation failed for operation: omp.teams}}
+  omp.teams dyn_groupprivate(%dyn_size : i32) {
+    omp.terminator
+  }
+  llvm.return
+}
+
+// -----
+
 llvm.func @wsloop_allocate(%lb : i32, %ub : i32, %step : i32, %x : !llvm.ptr) {
   // expected-error at below {{not yet implemented: Unhandled clause allocate in omp.wsloop operation}}
   // expected-error at below {{LLVM Translation failed for operation: omp.wsloop}}



More information about the Mlir-commits mailing list