Modelling local scopes with a high-level dialect

Hello!

I might be off in my understanding of this so if that’s the case please feel free to ignore.

I am currently working on a new MLIR dialect (lets call it foo) that is somewhat high-level.
This dialect is produced from the source AST of a high-level language that contains local scopes with local declarations.

How can we model these local declarations knowing that the built-in FunctionOp is not a SymbolTable Op and thus we cannot add symbols to a function scope (or an mlir::Block)?

An idea is to introduce a new Op called foo.block that has the SymbolTable trait.
However, this sounds simple enough for me to be worried that I might have missed something.
Surely others have encountered this ?
What would be the right way to go about handling local scopes in a custom dialect ?

P.S.: One of the optimizations we want to apply at that high-level dialect is that of constant folding. Having an initializer bundled together with a Symbol Op can make this straight forward as you can trace back a symbol to its value.

Thank you in advance!

Thanasis.

You could also just use your own foo.func instead of std.func and provide all the facilities there.

I could. But what about nested scopes ? For example:

func foo(...) some_type {
  var a: int = 10;
  if (condition) {
    var b: int = 20;
    ... 
  }
  {
    var c: int = 42;
    ...
  }
  ...
}

I’m not sure I’d try to use the MLIR symbol table to model this. In general this is the kind of thing where you can easily turn it into a handle to an SSA value in the frontend.
One example could be:

my.if ... {
  %b = my.var() : !my.var<int>
  my.var_assign(%b, %cst20)

It all depends on the language though, I sketched something above which is somehow akin to C/C++/Fortran/… where you can declare a variable which is a handle to a read/write memory storage and you can then use it as such.

1 Like

Thank you very much sir. I think that makes sense.
The only thing that I would change is that I would place the initialization in the declaration like so:

  %cst20 = constant 20 : i16
  %b = my.var() %cst20 : !my.var<i16>

That way we can effectively model “constant” decls that can be folded if possible.