https://github.com/skc7 updated https://github.com/llvm/llvm-project/pull/171825
>From d02544b205133749563f6222fd0e71c863226d3c Mon Sep 17 00:00:00 2001 From: skc7 <[email protected]> Date: Thu, 11 Dec 2025 13:35:05 +0530 Subject: [PATCH 1/2] [OpenMP][MLIR] Add thread_limit with dims modifier support --- .../Optimizer/OpenMP/LowerWorkdistribute.cpp | 16 +- .../mlir/Dialect/OpenMP/OpenMPClauses.td | 29 +++- mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp | 72 ++++++++- .../OpenMP/OpenMPToLLVMIRTranslation.cpp | 8 + mlir/test/Dialect/OpenMP/invalid.mlir | 149 +++++++++++++++++- mlir/test/Dialect/OpenMP/ops.mlir | 8 +- 6 files changed, 264 insertions(+), 18 deletions(-) diff --git a/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp b/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp index 7b61539984232..a3b9e5c76bdd2 100644 --- a/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp +++ b/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp @@ -766,6 +766,7 @@ FailureOr<omp::TargetOp> splitTargetData(omp::TargetOp targetOp, targetOp.getInReductionSymsAttr(), targetOp.getIsDevicePtrVars(), innerMapInfos, targetOp.getNowaitAttr(), targetOp.getPrivateVars(), targetOp.getPrivateSymsAttr(), targetOp.getPrivateNeedsBarrierAttr(), + targetOp.getThreadLimitNumDimsAttr(), targetOp.getThreadLimitDimsValues(), targetOp.getThreadLimit(), targetOp.getPrivateMapsAttr()); rewriter.inlineRegionBefore(targetOp.getRegion(), newTargetOp.getRegion(), newTargetOp.getRegion().begin()); @@ -1485,8 +1486,9 @@ genPreTargetOp(omp::TargetOp targetOp, SmallVector<Value> &preMapOperands, targetOp.getInReductionByrefAttr(), targetOp.getInReductionSymsAttr(), targetOp.getIsDevicePtrVars(), preMapOperands, targetOp.getNowaitAttr(), targetOp.getPrivateVars(), targetOp.getPrivateSymsAttr(), - targetOp.getPrivateNeedsBarrierAttr(), targetOp.getThreadLimit(), - targetOp.getPrivateMapsAttr()); + targetOp.getPrivateNeedsBarrierAttr(), + targetOp.getThreadLimitNumDimsAttr(), targetOp.getThreadLimitDimsValues(), + targetOp.getThreadLimit(), targetOp.getPrivateMapsAttr()); auto *preTargetBlock = rewriter.createBlock( &preTargetOp.getRegion(), preTargetOp.getRegion().begin(), {}, {}); IRMapping preMapping; @@ -1575,8 +1577,9 @@ genIsolatedTargetOp(omp::TargetOp targetOp, SmallVector<Value> &postMapOperands, targetOp.getInReductionByrefAttr(), targetOp.getInReductionSymsAttr(), targetOp.getIsDevicePtrVars(), postMapOperands, targetOp.getNowaitAttr(), targetOp.getPrivateVars(), targetOp.getPrivateSymsAttr(), - targetOp.getPrivateNeedsBarrierAttr(), targetOp.getThreadLimit(), - targetOp.getPrivateMapsAttr()); + targetOp.getPrivateNeedsBarrierAttr(), + targetOp.getThreadLimitNumDimsAttr(), targetOp.getThreadLimitDimsValues(), + targetOp.getThreadLimit(), targetOp.getPrivateMapsAttr()); auto *isolatedTargetBlock = rewriter.createBlock(&isolatedTargetOp.getRegion(), isolatedTargetOp.getRegion().begin(), {}, {}); @@ -1655,8 +1658,9 @@ static omp::TargetOp genPostTargetOp(omp::TargetOp targetOp, targetOp.getInReductionByrefAttr(), targetOp.getInReductionSymsAttr(), targetOp.getIsDevicePtrVars(), postMapOperands, targetOp.getNowaitAttr(), targetOp.getPrivateVars(), targetOp.getPrivateSymsAttr(), - targetOp.getPrivateNeedsBarrierAttr(), targetOp.getThreadLimit(), - targetOp.getPrivateMapsAttr()); + targetOp.getPrivateNeedsBarrierAttr(), + targetOp.getThreadLimitNumDimsAttr(), targetOp.getThreadLimitDimsValues(), + targetOp.getThreadLimit(), targetOp.getPrivateMapsAttr()); // Create the block for postTargetOp auto *postTargetBlock = rewriter.createBlock( &postTargetOp.getRegion(), postTargetOp.getRegion().begin(), {}, {}); diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td index e36dc7c246f01..366855bf02968 100644 --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td @@ -1452,16 +1452,43 @@ class OpenMP_ThreadLimitClauseSkip< > : OpenMP_Clause<traits, arguments, assemblyFormat, description, extraClassDeclaration> { let arguments = (ins + ConfinedAttr<OptionalAttr<I64Attr>, [IntPositive]>:$thread_limit_num_dims, + Variadic<AnyInteger>:$thread_limit_dims_values, Optional<AnyInteger>:$thread_limit ); let optAssemblyFormat = [{ - `thread_limit` `(` $thread_limit `:` type($thread_limit) `)` + `thread_limit` `(` custom<ThreadLimitClause>( + $thread_limit_num_dims, $thread_limit_dims_values, type($thread_limit_dims_values), + $thread_limit, type($thread_limit) + ) `)` }]; let description = [{ The optional `thread_limit` specifies the limit on the number of threads. }]; + + let extraClassDeclaration = [{ + /// Returns true if the dims modifier is explicitly present + bool hasThreadLimitDimsModifier() { + return getThreadLimitNumDims().has_value() && getThreadLimitNumDims().value(); + } + + /// Returns the number of dimensions specified by dims modifier + unsigned getThreadLimitDimsCount() { + if (!hasThreadLimitDimsModifier()) + return 1; + return static_cast<unsigned>(*getThreadLimitNumDims()); + } + + /// Returns the value for a specific dimension index + /// Index must be less than getThreadLimitDimsCount() + ::mlir::Value getThreadLimitDimensionValue(unsigned index) { + assert(index < getThreadLimitDimsCount() && + "Thread limit dims index out of bounds"); + return getThreadLimitDimsValues()[index]; + } + }]; } def OpenMP_ThreadLimitClause : OpenMP_ThreadLimitClauseSkip<>; diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp index d4dbf5f5244df..a5348b817ab27 100644 --- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp +++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp @@ -2239,10 +2239,30 @@ void TargetOp::build(OpBuilder &builder, OperationState &state, /*in_reduction_syms=*/nullptr, clauses.isDevicePtrVars, clauses.mapVars, clauses.nowait, clauses.privateVars, makeArrayAttr(ctx, clauses.privateSyms), - clauses.privateNeedsBarrier, clauses.threadLimit, + clauses.privateNeedsBarrier, clauses.threadLimitNumDims, + clauses.threadLimitDimsValues, clauses.threadLimit, /*private_maps=*/nullptr); } +// helper for thread_limit clause restrictions +static LogicalResult +verifyThreadLimitClause(Operation *op, + std::optional<IntegerAttr> threadLimitNumDims, + OperandRange threadLimitDimsValues, Value threadLimit) { + bool hasDimsModifier = + threadLimitNumDims.has_value() && threadLimitNumDims.value(); + + if (hasDimsModifier && threadLimit) { + return op->emitError("thread_limit with dims modifier cannot be used " + "together with number of threads"); + } + + if (failed(verifyDimsModifier(op, threadLimitNumDims, threadLimitDimsValues))) + return failure(); + + return success(); +} + LogicalResult TargetOp::verify() { if (failed(verifyDependVarList(*this, getDependKinds(), getDependVars()))) return failure(); @@ -2254,6 +2274,11 @@ LogicalResult TargetOp::verify() { if (failed(verifyMapClause(*this, getMapVars()))) return failure(); + if (failed(verifyThreadLimitClause(*this, getThreadLimitNumDimsAttr(), + getThreadLimitDimsValues(), + getThreadLimit()))) + return failure(); + return verifyPrivateVarsMapping(*this); } @@ -2661,7 +2686,8 @@ void TeamsOp::build(OpBuilder &builder, OperationState &state, /*private_needs_barrier=*/nullptr, clauses.reductionMod, clauses.reductionVars, makeDenseBoolArrayAttr(ctx, clauses.reductionByref), - makeArrayAttr(ctx, clauses.reductionSyms), clauses.threadLimit); + makeArrayAttr(ctx, clauses.reductionSyms), clauses.threadLimitNumDims, + clauses.threadLimitDimsValues, clauses.threadLimit); } // Helper: Verify num_teams clause @@ -2721,6 +2747,12 @@ LogicalResult TeamsOp::verify() { return emitError( "expected equal sizes for allocate and allocator variables"); + // Check for thread_limit clause restrictions + if (failed(verifyThreadLimitClause(*this, getThreadLimitNumDimsAttr(), + getThreadLimitDimsValues(), + getThreadLimit()))) + return failure(); + return verifyReductionVarList(*this, getReductionSyms(), getReductionVars(), getReductionByref()); } @@ -4647,6 +4679,42 @@ static void printNumTeamsClause(OpAsmPrinter &p, Operation *op, } } +//===----------------------------------------------------------------------===// +// Parser and printer for thread_limit clause +//===----------------------------------------------------------------------===// +static ParseResult +parseThreadLimitClause(OpAsmParser &parser, IntegerAttr &dimsAttr, + SmallVectorImpl<OpAsmParser::UnresolvedOperand> &values, + SmallVectorImpl<Type> &types, + std::optional<OpAsmParser::UnresolvedOperand> &bounds, + Type &boundsType) { + if (succeeded(parseDimsModifierWithValues(parser, dimsAttr, values, types))) { + return success(); + } + + OpAsmParser::UnresolvedOperand boundsOperand; + if (parser.parseOperand(boundsOperand) || parser.parseColon() || + parser.parseType(boundsType)) { + return failure(); + } + bounds = boundsOperand; + return success(); +} + +static void printThreadLimitClause(OpAsmPrinter &p, Operation *op, + IntegerAttr dimsAttr, OperandRange values, + TypeRange types, Value bounds, + Type boundsType) { + if (!values.empty()) { + // Multidimensional: dims(N): values : type + printDimsModifierWithValues(p, dimsAttr, values, types); + } else if (bounds) { + // Both bounds: bounds : type + p.printOperand(bounds); + p << " : " << boundsType; + } +} + #define GET_ATTRDEF_CLASSES #include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc" diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp index 00f782e87d5af..b4cc0802d166f 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp @@ -1985,6 +1985,10 @@ convertOmpTeams(omp::TeamsOp op, llvm::IRBuilderBase &builder, return op.emitError("Lowering of num_teams with dims modifier is NYI."); } + if (op.hasThreadLimitDimsModifier()) { + return op.emitError("Lowering of thread_limit with dims modifier is NYI."); + } + DenseMap<Value, llvm::Value *> reductionVariableMap; unsigned numReductionVars = op.getNumReductionVars(); SmallVector<omp::DeclareReductionOp> reductionDecls; @@ -5594,6 +5598,8 @@ extractHostEvalClauses(omp::TargetOp targetOp, Value &numThreads, // num_teams dims and values are not yet supported assert(!teamsOp.hasNumTeamsDimsModifier() && "Lowering of num_teams with dims modifier is NYI."); + assert(!teamsOp.hasThreadLimitDimsModifier() && + "Lowering of thread_limit with dims modifier is NYI."); if (teamsOp.getNumTeamsLower() == blockArg) numTeamsLower = hostEvalVar; else if (teamsOp.getNumTeamsUpper() == blockArg) @@ -5719,6 +5725,8 @@ initTargetDefaultAttrs(omp::TargetOp targetOp, Operation *capturedOp, // num_teams dims and values are not yet supported assert(!teamsOp.hasNumTeamsDimsModifier() && "Lowering of num_teams with dims modifier is NYI."); + assert(!teamsOp.hasThreadLimitDimsModifier() && + "Lowering of thread_limit with dims modifier is NYI."); numTeamsLower = teamsOp.getNumTeamsLower(); numTeamsUpper = teamsOp.getNumTeamsUpper(); threadLimit = teamsOp.getThreadLimit(); diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir index dd367aba8da27..7f69ca5aaa064 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,0>} : (memref<i32>) -> () + }) {operandSegmentSizes = array<i32: 1,0,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 num_teams upper bound to be defined if the lower bound is defined}} "omp.teams" (%lb) ({ omp.terminator - }) {operandSegmentSizes = array<i32: 0,0,0,0,1,0,0,0,0>} : (i32) -> () + }) {operandSegmentSizes = array<i32: 0,0,0,0,1,0,0,0,0,0>} : (i32) -> () omp.terminator } return @@ -1466,7 +1466,7 @@ func.func @omp_teams_num_teams_dims_mismatch() { // expected-error @below {{dims(3) specified but 2 values provided}} "omp.teams" (%v0, %v1) ({ omp.terminator - }) {num_teams_num_dims = 3 : i64, operandSegmentSizes = array<i32: 0,0,0,2,0,0,0,0,0>} : (i32, i32) -> () + }) {num_teams_num_dims = 3 : i64, operandSegmentSizes = array<i32: 0,0,0,2,0,0,0,0,0,0>} : (i32, i32) -> () omp.terminator } return @@ -1483,7 +1483,7 @@ func.func @omp_teams_num_teams_dims_with_bounds() { // expected-error @below {{num_teams with dims modifier cannot be used together with lower/upper bounds}} "omp.teams" (%v0, %v1, %lb, %ub) ({ omp.terminator - }) {num_teams_num_dims = 2 : i64, operandSegmentSizes = array<i32: 0,0,0,2,1,1,0,0,0>} : (i32, i32, i32, i32) -> () + }) {num_teams_num_dims = 2 : i64, operandSegmentSizes = array<i32: 0,0,0,2,1,1,0,0,0,0>} : (i32, i32, i32, i32) -> () omp.terminator } return @@ -1498,7 +1498,7 @@ func.func @omp_teams_num_teams_values_without_dims() { // expected-error @below {{dims values can only be specified with dims modifier}} "omp.teams" (%v0, %v1) ({ omp.terminator - }) {operandSegmentSizes = array<i32: 0,0,0,2,0,0,0,0,0>} : (i32, i32) -> () + }) {operandSegmentSizes = array<i32: 0,0,0,2,0,0,0,0,0,0>} : (i32, i32) -> () omp.terminator } return @@ -1511,7 +1511,7 @@ func.func @omp_teams_num_teams_dims_no_values() { // expected-error @below {{dims modifier requires values to be specified}} "omp.teams" () ({ omp.terminator - }) {num_teams_num_dims = 2 : i64, operandSegmentSizes = array<i32: 0,0,0,0,0,0,0,0,0>} : () -> () + }) {num_teams_num_dims = 2 : i64, operandSegmentSizes = array<i32: 0,0,0,0,0,0,0,0,0,0>} : () -> () omp.terminator } return @@ -1526,7 +1526,7 @@ func.func @omp_teams_num_teams_dims_type_mismatch() { // expected-error @below {{dims modifier requires all values to have the same type}} "omp.teams" (%v0, %v1) ({ omp.terminator - }) {num_teams_num_dims = 2 : i64, operandSegmentSizes = array<i32: 0,0,0,2,0,0,0,0,0>} : (i32, i64) -> () + }) {num_teams_num_dims = 2 : i64, operandSegmentSizes = array<i32: 0,0,0,2,0,0,0,0,0,0>} : (i32, i64) -> () omp.terminator } return @@ -1547,6 +1547,139 @@ func.func @omp_teams_num_teams2(%lb : i32, %ub : i16) { // ----- +func.func @omp_teams_thread_limit_dims_mismatch() { + omp.target { + %v0 = arith.constant 1 : i32 + %v1 = arith.constant 2 : i32 + // expected-error @below {{dims(3) specified but 2 values provided}} + "omp.teams" (%v0, %v1) ({ + omp.terminator + }) {thread_limit_num_dims = 3 : i64, operandSegmentSizes = array<i32: 0,0,0,0,0,0,0,0,2,0>} : (i32, i32) -> () + omp.terminator + } + return +} + +// ----- + +func.func @omp_teams_thread_limit_dims_with_scalar() { + omp.target { + %v0 = arith.constant 1 : i32 + %v1 = arith.constant 2 : i32 + %tl = arith.constant 4 : i32 + // expected-error @below {{thread_limit with dims modifier cannot be used together with number of threads}} + "omp.teams" (%v0, %v1, %tl) ({ + omp.terminator + }) {thread_limit_num_dims = 2 : i64, operandSegmentSizes = array<i32: 0,0,0,0,0,0,0,0,2,1>} : (i32, i32, i32) -> () + omp.terminator + } + return +} + +// ----- + +func.func @omp_teams_thread_limit_dims_no_values() { + omp.target { + // expected-error @below {{dims modifier requires values to be specified}} + "omp.teams" () ({ + omp.terminator + }) {thread_limit_num_dims = 2 : i64, operandSegmentSizes = array<i32: 0,0,0,0,0,0,0,0,0>} : () -> () + omp.terminator + } + return +} + +// ----- + +func.func @omp_teams_thread_limit_values_without_dims() { + omp.target { + %v0 = arith.constant 1 : i32 + %v1 = arith.constant 2 : i32 + // expected-error @below {{dims values can only be specified with dims modifier}} + "omp.teams" (%v0, %v1) ({ + omp.terminator + }) {operandSegmentSizes = array<i32: 0,0,0,0,0,0,0,0,2,0>} : (i32, i32) -> () + omp.terminator + } + return +} + +// ----- + +func.func @omp_teams_thread_limit_dims_type_mismatch() { + omp.target { + %v0 = arith.constant 1 : i32 + %v1 = arith.constant 2 : i64 + // expected-error @below {{dims modifier requires all values to have the same type}} + "omp.teams" (%v0, %v1) ({ + omp.terminator + }) {thread_limit_num_dims = 2 : i64, operandSegmentSizes = array<i32: 0,0,0,0,0,0,0,0,2,0>} : (i32, i64) -> () + omp.terminator + } + return +} + +// ----- + +func.func @omp_target_thread_limit_dims_mismatch() { + %v0 = arith.constant 1 : i32 + %v1 = arith.constant 2 : i32 + // expected-error @below {{dims(3) specified but 2 values provided}} + "omp.target" (%v0, %v1) ({ + omp.terminator + }) {thread_limit_num_dims = 3 : i64, operandSegmentSizes = array<i32: 0,0,0,0,0,0,0,0,0,0,0,2,0>} : (i32, i32) -> () + return +} + +// ----- + +func.func @omp_target_thread_limit_dims_with_scalar() { + %v0 = arith.constant 1 : i32 + %v1 = arith.constant 2 : i32 + %tl = arith.constant 4 : i32 + // expected-error @below {{thread_limit with dims modifier cannot be used together with number of threads}} + "omp.target" (%v0, %v1, %tl) ({ + omp.terminator + }) {thread_limit_num_dims = 2 : i64, operandSegmentSizes = array<i32: 0,0,0,0,0,0,0,0,0,0,0,2,1>} : (i32, i32, i32) -> () + return +} + +// ----- + +func.func @omp_target_thread_limit_dims_no_values() { + // expected-error @below {{dims modifier requires values to be specified}} + "omp.target" () ({ + omp.terminator + }) {thread_limit_num_dims = 2 : i64, operandSegmentSizes = array<i32: 0,0,0,0,0,0,0,0,0,0,0,0,0>} : () -> () + return +} + +// ----- + +func.func @omp_target_thread_limit_values_without_dims() { + %v0 = arith.constant 1 : i32 + %v1 = arith.constant 2 : i32 + // expected-error @below {{dims values can only be specified with dims modifier}} + "omp.target" (%v0, %v1) ({ + omp.terminator + }) {operandSegmentSizes = array<i32: 0,0,0,0,0,0,0,0,0,0,0,2,0>} : (i32, i32) -> () + return +} + +// ----- + +func.func @omp_target_thread_limit_dims_type_mismatch() { + %v0 = arith.constant 1 : i32 + %v1 = arith.constant 2 : i64 + // expected-error @below {{dims modifier requires all values to have the same type}} + "omp.target" (%v0, %v1) ({ + omp.terminator + }) {thread_limit_num_dims = 2 : i64, operandSegmentSizes = array<i32: 0,0,0,0,0,0,0,0,0,0,0,2,0>} : (i32, i64) -> () + return +} + +// ----- + func.func @omp_sections(%data_var : memref<i32>) -> () { // expected-error @below {{expected equal sizes for allocate and allocator variables}} "omp.sections" (%data_var) ({ @@ -2533,7 +2666,7 @@ 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"() : () -> () } diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir index 3633a4be1eb62..a1146fbb263e6 100644 --- a/mlir/test/Dialect/OpenMP/ops.mlir +++ b/mlir/test/Dialect/OpenMP/ops.mlir @@ -823,7 +823,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,0,1>} : ( 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 = ""} @@ -1128,6 +1128,12 @@ func.func @omp_teams(%lb : i32, %ub : i32, %if_cond : i1, %num_threads : i32, omp.terminator } + // CHECK: omp.teams thread_limit(dims(2): %{{.*}}, %{{.*}} : i32) + omp.teams thread_limit(dims(2): %lb, %ub : i32) { + // CHECK: omp.terminator + omp.terminator + } + // Test reduction. %c1 = arith.constant 1 : i32 %0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr >From 67b209b82303f1b7133c7458193377cd27e52781 Mon Sep 17 00:00:00 2001 From: skc7 <[email protected]> Date: Thu, 11 Dec 2025 18:35:55 +0530 Subject: [PATCH 2/2] update thread_limit description --- mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td index 366855bf02968..4a0d1fd0af02c 100644 --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td @@ -1465,7 +1465,18 @@ class OpenMP_ThreadLimitClauseSkip< }]; let description = [{ - The optional `thread_limit` specifies the limit on the number of threads. + The `thread_limit` clause specifies the limit on the number of threads. + + With dims modifier: + - The number of dimensions is specified by the `thread_limit_num_dims` attribute. + - The values for each dimension are specified by the `thread_limit_dims_values` attribute. + - Format: `thread_limit(dims(N): values : type)` + - Example: `thread_limit(dims(2): %n, %m : i64)` + + Without dims modifier: + - The number of threads is specified by the `thread_limit`. + - Format: `thread_limit(number_of_threads : type)` + - Example: `thread_limit(%n : i64)` }]; let extraClassDeclaration = [{ _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
