[MLIR] Have some conceptual issues with the MLIR framework

I am a beginner familiarizing myself with the MLIR project, and recently I’ve encountered some issues understanding its structure which can be listed below:

  1. currently the kinds of regions contained in mlir is SSACFG and Graph , I am quite familiar with the architecture of SSA (Static Single Assignment) and can understand its structure, after I read the documentation GraphRegion, the doc says that this region is appropriate for concurrent semantics without control flow , but it doesn’t provide specific examples ,so I’m a little confused about this concept
  2. the doc gives an example:
"test.graph_region"() ({ // A Graph region
  %1 = "op1"(%1, %3) : (i32, i32) -> (i32)  // OK: %1, %3 allowed here
  %2 = "test.ssacfg_region"() ({
     %5 = "op2"(%1, %2, %3, %4) : (i32, i32, i32, i32) -> (i32) // OK: %1, %2, %3, %4 all defined in the containing region
  }) : () -> (i32)
  %3 = "op2"(%1, %4) : (i32, i32) -> (i32)  // OK: %4 allowed here
  %4 = "op3"(%1) : (i32) -> (i32)
}) : () -> ()

The SSA region is nested within the graph region, How do these two regions combine logically? I don’t quite understand.

I would really appreciate any help you can provide. :slight_smile:

There is no CFG control flow in the graph region in the example, but if/when the control is transferred to the nested region, these you find again the usual control flow.

It’s hard to find a concrete example that you could relate to without knowing your background, but imagine that the outer region is a ML dataflow graph, and there you could have a “custom operation” which defines a nested region implemented in LLVM dialect directly.

Thank a lot ! After reading the answer and revisiting the documentation, I have a clearer understanding of the concept of graph regions.
And another question bothers me: I think structure like LLVM using Module->Function->Block is OK, so why mlir use: operation->region->block , and the block also contains operation ,region, so what is the purpose of this design

The previous example should apply here as well?

Imagine a module, that contains a graph, this graph defines a graph region to model a ML dataflow graph, and there you could have a “custom operation” which defines a nested region implemented in LLVM dialect directly.

Now you have module>graph>custom_op>…

Another example can be the way we can model host code and device code using GPU module.

module {
  gpu.module {
    gpu.func @kernel { ...}
  }
  func @host() { ...}
}
1 Like

Got it ! Thanks a lot :blush: