diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1805,6 +1805,7 @@ CHECK_SIMPLE_CLAUSE(Bind, OMPC_bind) CHECK_SIMPLE_CLAUSE(Align, OMPC_align) CHECK_SIMPLE_CLAUSE(Compare, OMPC_compare) +CHECK_SIMPLE_CLAUSE(CancelConstructType, OMPC_cancel_construct_type) CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize) CHECK_REQ_SCALAR_INT_CLAUSE(NumTasks, OMPC_num_tasks) diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -163,6 +163,25 @@ ]; } +def OMP_CANCEL_CONSTRUCT_Parallel : ClauseVal<"parallel", 1, 1> {} +def OMP_CANCEL_CONSTRUCT_Loop : ClauseVal<"loop", 2, 1> {} +def OMP_CANCEL_CONSTRUCT_Sections : ClauseVal<"sections", 3, 1> {} +def OMP_CANCEL_CONSTRUCT_Taskgroup : ClauseVal<"taskgroup", 4, 1> {} +def OMP_CANCEL_CONSTRUCT_None : ClauseVal<"none", 5, 0> { + let isDefault = 1; +} + +def OMPC_CancelConstructType : Clause<"cancel_construct_type"> { + let enumClauseValue = "CancelConstructType"; + let allowedClauseValues = [ + OMP_CANCEL_CONSTRUCT_Parallel, + OMP_CANCEL_CONSTRUCT_Loop, + OMP_CANCEL_CONSTRUCT_Sections, + OMP_CANCEL_CONSTRUCT_Taskgroup, + OMP_CANCEL_CONSTRUCT_None + ]; +} + def OMPC_Ordered : Clause<"ordered"> { let clangClass = "OMPOrderedClause"; let flangClass = "ScalarIntConstantExpr"; diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -997,6 +997,40 @@ }]; } +//===----------------------------------------------------------------------===// +// 2.18.1 Cancel Construct +//===----------------------------------------------------------------------===// +def CancelOp : OpenMP_Op<"cancel"> { + let summary = "cancel directive"; + let description = [{ + The cancel construct activates cancellation of the innermost enclosing + region of the type specified. + }]; + let arguments = (ins CancelConstructTypeAttr:$cancel_construct_val, + Optional:$if_expr); + let assemblyFormat = [{ `cancel_construct` `(` + custom($cancel_construct_val) `)` + ( `if` `(` $if_expr^ `)` )? attr-dict}]; + let hasVerifier = 1; +} + +//===----------------------------------------------------------------------===// +// 2.18.2 Cancellation Point Construct +//===----------------------------------------------------------------------===// +def CancellationPointOp : OpenMP_Op<"cancellationpoint"> { + let summary = "cancellation point directive"; + let description = [{ + The cancellation point construct introduces a user-defined cancellation + point at which implicit or explicit tasks check if cancellation of the + innermost enclosing region of the type specified has been activated. + }]; + let arguments = (ins CancelConstructTypeAttr:$cancel_construct_val); + let assemblyFormat = [{ `cancel_construct` `(` + custom($cancel_construct_val) `)` + attr-dict}]; + let hasVerifier = 1; +} + //===----------------------------------------------------------------------===// // 2.19.5.7 declare reduction Directive //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp --- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp +++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp @@ -952,6 +952,57 @@ return success(); } +//===----------------------------------------------------------------------===// +// Verifier for CancelOp +//===----------------------------------------------------------------------===// + +LogicalResult CancelOp::verify() { + auto cct = cancel_construct_val(); + auto op = (*this)->getParentOp(); + + if (!op) + return emitOpError() << "must be used within an region supporting " + "cancel directive"; + + auto op_name = op->getName().getStringRef(); + if ((cct == ClauseCancelConstructType::Parallel) && + !(op_name.equals("omp.parallel"))) + return emitOpError() << "cancel parallel must appear " + << "inside a parallel region"; + else if ((cct == ClauseCancelConstructType::Sections) && + !(op_name.equals("omp.sections") || + op_name.equals("omp.section"))) + return emitOpError() << "cancel sections must appear " + << "inside a sections region"; + // TODO : Add more when we support taskgroup and do/for. + return success(); +} +//===----------------------------------------------------------------------===// +// Verifier for CancelOp +//===----------------------------------------------------------------------===// + +LogicalResult CancellationPointOp::verify() { + auto cct = cancel_construct_val(); + auto op = (*this)->getParentOp(); + + if (!op) + return emitOpError() << "must be used within an region supporting " + "cancellation point directive"; + + auto op_name = op->getName().getStringRef(); + if ((cct == ClauseCancelConstructType::Parallel) && + !(op_name.equals("omp.parallel"))) + return emitOpError() << "cancellation point parallel must appear " + << "inside a parallel region"; + else if ((cct == ClauseCancelConstructType::Sections) && + !(op_name.equals("omp.sections") || + op_name.equals("omp.section"))) + return emitOpError() << "cancellation point sections must appear " + << "inside a sections region"; + // TODO : Add more when we support taskgroup and do/for. + return success(); +} + #define GET_ATTRDEF_CLASSES #include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc" diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir --- a/mlir/test/Dialect/OpenMP/invalid.mlir +++ b/mlir/test/Dialect/OpenMP/invalid.mlir @@ -1047,3 +1047,51 @@ } return } + +// ----- + +func @omp_cancel() { + omp.sections { + // expected-error @below {{cancel parallel must appear inside a parallel region}} + omp.cancel cancel_construct(parallel) + // CHECK: omp.terminator + omp.terminator + } + return +} + +// ----- + +func @omp_cancel1() { + omp.parallel { + // expected-error @below {{cancel sections must appear inside a sections region}} + omp.cancel cancel_construct(sections) + // CHECK: omp.terminator + omp.terminator + } + return +} + +// ----- + +func @omp_cancellationpoint() { + omp.sections { + // expected-error @below {{cancellation point parallel must appear inside a parallel region}} + omp.cancellationpoint cancel_construct(parallel) + // CHECK: omp.terminator + omp.terminator + } + return +} + +// ----- + +func @omp_cancellationpoint1() { + omp.parallel { + // expected-error @below {{cancellation point sections must appear inside a sections region}} + omp.cancellationpoint cancel_construct(sections) + // CHECK: omp.terminator + omp.terminator + } + return +} diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir --- a/mlir/test/Dialect/OpenMP/ops.mlir +++ b/mlir/test/Dialect/OpenMP/ops.mlir @@ -1011,4 +1011,26 @@ return } +func @omp_cancel(%if_cond : i1) -> () { + // Test with optional operand; if_expr. + omp.parallel { + // CHECK: omp.cancel cancel_construct(parallel) if(%{{.*}}) + omp.cancel cancel_construct(parallel) if(%if_cond) + // CHECK: omp.terminator + omp.terminator + } + return +} + +func @omp_cancellationpoint() -> () { + omp.parallel { + // CHECK: omp.cancellationpoint cancel_construct(parallel) + omp.cancellationpoint cancel_construct(parallel) + // CHECK: omp.cancel cancel_construct(parallel) + omp.cancel cancel_construct(parallel) + omp.terminator + } + return +} + llvm.mlir.global internal @_QFsubEx() : i32