Calling functions on different modules

According to the symbol table document, symbols can be referenced by full scope (ex. “@Foo::@bar()”). ModuleOps have the property of being a symbol table and add functions to its own when inserted into the module.

However, the docs only refer to the attribute uses and not to direct calls. I seem to be missing the point, but how can I directly call a function (or indirectly create a pointer to it and call that) that is in another module?

This is my example:

module @__  {
  module @Foo  {
    func @foo() -> i64 {
      %c21_i64 = constant 21 : i64
      return %c21_i64 : i64
    }
  }
  module @Bar  {
    func @bar(%arg0: i64) -> i64 {
      %0 = call @foo() : () -> i64
      %1 = addi %arg0, %0 : i64
      return %1 : i64
    }
  }
  func @main() -> i64 {
    %c21_i64 = constant 21 : i64
    %0 = call @bar(%c21_i64) : (i64) -> i64
    return %0 : i64
  }
}

Obviously, the calls fail with error:

out.mlir:17:10: error: 'std.call' op 'bar' does not reference a valid function
    %0 = call @bar(%c21_i64) : (i64) -> i64
         ^
out.mlir:17:10: note: see current operation: %0 = "std.call"(%c21_i64) {callee = @bar} : (i64) -> i64

But if I try @Bar::bar, I get:

out.mlir:17:21: error: expected nested symbol reference identifier
    %0 = call @Bar::bar(%c21_i64) : (i64) -> i64
                    ^

Which I’m assuming is the @ (as in the docs), so I tried @Bar::@bar, but I get a different error:

out.mlir:56:17: error: custom op 'std.call' invalid kind of attribute specified
      %5 = call @Bar::@bar(%4) : (i64) -> i64
                ^

I couldn’t find examples in the MLIR code to follow, only ones testing the “use” for symbols. Perhaps this isn’t meant to be called as a function?

The call operation in the standard dialect does not support nested reference: https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/Dialect/StandardOps/IR/Ops.td#L530

Thanks @mehdi_amini, that makes sense. I also imagine that if I were to build an operation that allows nested reference, I’d create a dependency between the two modules and they couldn’t be considered isolatedFromAbove anymore, right?

They would still be considered isolatedFromAbove: this trait is about SSA uses and not symbolic references (it impacts the guarantees we can infer on Value use-list mutation in general).