[Mlir-commits] [mlir] [OpenMP][MLIR] Add omp.canonical_loop operation, !omp.cli type, omp.new_cli operation (PR #71712)

Michael Kruse llvmlistbot at llvm.org
Mon Mar 11 05:16:57 PDT 2024


================
@@ -405,6 +405,170 @@ def SingleOp : OpenMP_Op<"single", [AttrSizedOperandSegments]> {
   let hasVerifier = 1;
 }
 
+//===---------------------------------------------------------------------===//
+// OpenMP Canonical Loop Info Type
+//===---------------------------------------------------------------------===//
+
+def CanonicalLoopInfoType : OpenMP_Type<"CanonicalLoopInfo", "cli"> {
+  let summary = "Type for representing a reference to a canonical loop";
+  let description = [{
+    A variable of type CanonicalLoopInfo refers to an OpenMP-compatible
+    canonical loop in the same function. Variables of this type are not
+    available at runtime and therefore cannot be used by the program itself,
+    i.e. an opaque type. It is similar to the transform dialect's
+    `!transform.interface` type, but instead of implementing an interface
+    for each transformation, the OpenMP dialect itself defines possible
+    operations on this type.
+
+    A CanonicalLoopInfo variable can
+
+    1. passed to omp.canonical_loop to assiciate the loop to that variable
+    2. passed to omp operations that take a CanonicalLoopInfo argument,
+       such as `omp.unroll`.
+
+    A CanonicalLoopInfo variable can not
+
+    1. be returned from a function,
+    2. passed to operations that are not specifically designed to take a
+       CanonicalLoopInfo, including AnyType.
+
+    A CanonicalLoopInfo variable directly corresponds to an object of
+    OpenMPIRBuilder's CanonicalLoopInfo struct when lowering to LLVM-IR.
+  }];
+}
+
+//===---------------------------------------------------------------------===//
+// OpenMP Canonical Loop Info Operation
+//===---------------------------------------------------------------------===//
+
+def NewCliOp : OpenMP_Op<"new_cli"> {
+  let summary = "Create a new Canonical Loop Info value.";
+  let description = [{
+    Create a new CLI that can be passed as an argument to a CanonicalLoopOp
+    and to loop transformation operations to handle dependencies between
+    loop transformation operations.
+    }];
+    let results = (outs CanonicalLoopInfoType:$result);
+    let assemblyFormat = [{
+        attr-dict `:` type($result)
+    }];
+}
+
+
+//===---------------------------------------------------------------------===//
+// OpenMP Canonical Loop Operation
+//===---------------------------------------------------------------------===//
+def CanonicalLoopOp : OpenMP_Op<"canonical_loop", []> {
+  let summary = "OpenMP Canonical Loop Operation";
+  let description = [{
+    All loops that conform to OpenMP's definition of a canonical loop can be
+    simplified to a CanonicalLoopOp. In particular, there are no loop-carried
+    variables and the number of iterations it will execute is know before the
----------------
Meinersbur wrote:

[`scf.for`](https://mlir.llvm.org/docs/Dialects/SCFDialect/#scffor-scfforop) models loop-carried variables using (1) an additional operation parameter, (2) an argument for the first block, and (3) an additional argument to yield. It's semantics are sequential, i.e. the yielded value is the block argument for the next iteration. This semantics makes any multiprocessing impossible, hence rather unusual for an OpenMP loop. 

For the cases where it is needed, the value can be carried across iterations using an alloca, i.e. mem2reg would just not  promote the variable to a register. This also preserves the semantics it would have when reordering the execution of iterations including race conditions, which is hard to reason about with promoted registers.

The exception is `reduction`(and maybe `lastprivate`) where the register itself is privatized, but the parallel semantics is defined by OpenMP. For wsloop` and `simd` this is done by an argument to `omp.yield`.

https://github.com/llvm/llvm-project/pull/71712


More information about the Mlir-commits mailing list