Create FunOp in MLIR file,MLIR Parse BUG

Hello everyone,I attempted to create a subfunction in the MLIR file through OpBuilder and call between the main function and the subfunction by creating CallOp. However, the MLIR Parser(mlir::parseSourceFile) parsed the file and found that it cannot recognize the subfunctions in the mian function. Do I need to create a function declaration before the main function and how to create it? I hope there are relevant examples for reference.
Code

module attributes {module.name = “mymodule”} {
func.func @main(%arg0: tensor<1x6x128x128xf32> loc(unknown)) → (tensor<128x128x6x1xf32>) {
%0 = “MyDialect.Input”(%arg0) : (tensor<1x6x128x128xf32>) → tensor<1x6x128x128xf32> loc(#loc1)
%1 = call @mysubfunc(%0) : (tensor<1x6x128x128xf32>) → (tensor<128x128x6x1xf32>) loc(#loc)
return %1: tensor<128x128x6x1xf32> loc(#loc)
} loc(#loc)
func.func @mysubfunc(%arg0: tensor<1x6x128x128xf32> loc(“myTensorData”)) → (tensor<128x128x6x1xf32>){… }

error:‘func.call’ op ‘mysubfunc’ does not reference a valid function

I’m trying to manually add one

func.func @mysubfunc(tensor<1x6x128x128xf32>) → (tensor<128x128x6x1xf32>)

But i got

error: ‘func.func’ op symbol declaration cannot have public visibility

There is no parsing bug here, this is a verification error and you should try to understand it and fix it.
In this case, this hints at symbol visibility, which is documented here: Symbols and Symbol Tables - MLIR

If you look at the various examples in the tests in the repo, you may figure that the external declarations must be private:

func.func private @mysubfunc(tensor<1x6x128x128xf32>) → (tensor<128x128x6x1xf32>)

thanks,i agree with your point of view.
I spent some time learning about Symbols and SymbolTable(DenseMap),know that ModuleOp is a SymbolTableOp that has a trait named SymbolTable,but funcOp does not,If you want to use callOp to call a symbol, you must use func.func to define a symbol first that needs to be inserted into the SymbolTable of MoudleOp.So I insert a new subfunction before the main func to insert the symbol into the SymbolTable of moduleOp.
Unfortunately, there were still errors.

error:‘func.call’ op ‘mysubfunc’ does not reference a valid function

I think that the definition of the insert function in file’Opdefinition.h’ is different from that of the insert function in SymbolTable.I used the following function.(end->front)

  /// Insert the operation into the back of the body.
  template <typename OpT = ConcreteType>
  enable_if_single_region<OpT> push_back(Operation *op) {
    insert(Block::iterator(getBody()->end()), op);
  }

SymbolTable::insert function:

 StringAttr insert(Operation *symbol, Block::iterator insertPt = {});

Is there any other function that can achieve this goal? Finally, I couldn’t find a way to add a function declaration to SymbolTable. Is this possible?

Can you print the IR that fails the verifier and post it?
(you can use --mlir-print-ir-after-failure if you’re using mlir-opt)

I have successfully completed inserting subfunction before the main function, but parse is completed in other file. Below is the output IR for completing pass。

#loc = loc(unknown)
#loc1 = loc("cat_image")
module attributes {module.name = “mymodule”} {
func.func @mysubfunc(%arg0: tensor<1x6x128x128xf32> loc(“cat_image”)) → (tensor<128x128x6x1xf32>){… }loc(#loc)
func.func @main(%arg0: tensor<1x6x128x128xf32> loc(unknown)) → (tensor<128x128x6x1xf32>) {
%0 = “MyDialect.Input”(%arg0) : (tensor<1x6x128x128xf32>) → tensor<1x6x128x128xf32> loc(#loc1)
%1 = call @mysubfunc(%0) : (tensor<1x6x128x128xf32>) → (tensor<128x128x6x1xf32>) loc(#loc)
return %1: tensor<128x128x6x1xf32> loc(#loc)
} loc(#loc)

hi,I hope to reproduce this parserSourceFile issue through Toy Ch2, know more about it ,based on your suggestion in
https://discourse.llvm.org/t/mlir-tutorial-ch6-failed-with-error-dialect-func-not-found-for-custom-op-func-func/67461/4?u=rrice

I modified the ch2 toyc.cpp code to parse func.func instead of toy.func in toy ch2 mlir file

#include “mlir/Dialect/Func/IR/FuncOps.h”
using namespace mlir::func;
mlir::MLIRContext context;
mlir::DialectRegistry registry;
registry.insert<mlir::func::FuncDialect,mlir::toy::ToyDialect>();
context.appendDialectRegistry(registry);

cl:

cmake --build . --target toyc-ch2

I successfully compiled mlir project through clang14 debug version
Compiled successfully, but there were some issues with the link. I don’t seem to understand why

tools/mlir/examples/toy/Ch2/CMakeFiles/toyc-ch2.dir/toyc.cpp.o: In function mlir::detail::TypeIDResolver<mlir::func::FuncDialect, void>::resolveTypeID()': /public/home/xxx/llvm-project main/build/tools/mlir/include/mlir/Dialect/Func/IR/FuncOpsDialect.h.inc:32: undefined reference to mlir::detail::TypeIDResolver<mlir::func::FuncDialect, void>::id’
tools/mlir/examples/toy/Ch2/CMakeFiles/toyc-ch2.dir/toyc.cpp.o: In function operator()': /public/home/xxx/llvm-project-main/mlir/include/mlir/IR/MLIRContext.h:100: undefined reference to mlir::func::FuncDialect::FuncDialect(mlir::MLIRContext*)‘’

Did you modify cmake to add a dependency on the library providing the func dialect?

Thanks!
I solved this problem by adding MLIRFuncDilalect in Cmake. I understand that ParseSourceFile is parsed based on mlir text format, so it has been validated here(Toy-ch2). The issue I mentioned earlier was maybe due to the issue of using pybind to transfer data from the Python to the C++. I will continue to understand the issue here. Thank you for your helpful answer.

Excuse me, I have redesigned the test case and compared two different MLIR files. The MLIR modified based on toy ch2 can pass through the ParserSource file, but the other one is not. I understand that Parser is parsed based on MLIR files. I hope you can help me find out where the file does not comply with MLIR rules, resulting in invalid function calls. Thank you a lot.
Base on toy ch2:

module {
  func.func @multiply_transpose(%arg0: tensor<*xf64> loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":4:1), %arg1: tensor<*xf64> loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":4:1)) -> tensor<*xf64> {
    %0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64> loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":5:10)
    %1 = toy.transpose(%arg1 : tensor<*xf64>) to tensor<*xf64> loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":5:25)
    %2 = toy.mul %0, %1 : tensor<*xf64> loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":5:25)
    return %2 : tensor<*xf64> loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":5:3)
  } loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":4:1)
  func.func @main() {
    %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":9:17)
    %1 = toy.reshape(%0 : tensor<2x3xf64>) to tensor<2x3xf64> loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":9:3)
    %2 = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64> loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":10:17)
    %3 = toy.reshape(%2 : tensor<6xf64>) to tensor<2x3xf64> loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":10:3)
    %4 = call @multiply_transpose(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":11:11)
    %5 = call @multiply_transpose(%3, %1) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":12:11)
    toy.print %5 : tensor<*xf64> loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":13:3)
    return loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":8:1)
  } loc("../../mlir/test/Examples/Toy/Ch2/codegen.toy":8:1)
} loc(unknown)

my mlir file which cannot pass Parser

module attributes {module.chip = "ALL", module.name = "Permutesigmoidchange", module.platform = "ONNX", module.state = "TOP_F32", module.weight_file = "permutesigmoidchange_top_f32_all_origin_weight.npz"} {
  func.func @subfunc(%arg0: tensor<1x16x128x128xf32> loc("codegen":4:1)) -> tensor<128x128x16x1xf32> {
    %0 = "top.Permute"(%arg0) {order = [3, 2, 1, 0]} : (tensor<1x16x128x128xf32>) -> tensor<128x128x16x1xf32> loc("transpose")
    return %0 : tensor<128x128x16x1xf32> loc("codegen":5:3)
  } loc("codegen":4:1)
  func.func @main(%arg0: tensor<1x16x128x128xf32> loc(unknown)) -> tensor<128x128x16x1xf32> {
    %0 = "top.Input"(%arg0) : (tensor<1x16x128x128xf32>) -> tensor<1x16x128x128xf32> loc("input")
    %1 = call @subfunc(%0) : (tensor<1x16x128x128xf32>) -> tensor<128x128x16x1xf32> loc("codegen":11:11)
    return %1 : tensor<128x128x16x1xf32> loc("codegen.toy":8:1)
  } loc("codegen.toy":8:1)
} loc(unknown)

error:

loc("codegen":11:11): error: 'func.call' op 'subfunc' does not reference a valid function

There is not parser issue here, this is an IR verification failure.

It says: error: 'func.call' op 'sunfunc' does not reference a valid function ; which means it looks for a @sunfunc function in the current module but can’t find it (you just use a textual search you may figure out why quickly :slight_smile:)

:grinning:Haha, it’s because I manually modified the text, but this is not the main validation issue. I have already corrected the character error in the previous answer, which is indeed a low-level error. However, after the modification is completed, it still cannot be passed. Are there any other errors here?
Thank you for your patience!

I suspect the file we see here isn’t reflecting the IR that is failing…
For example I can feed this IR through ./bin/mlir-opt /tmp/t.mlir -allow-unregistered-dialect without problem, how do you get this particular IR to fail?

I hope to simplify the problems encountered as much as possible, so only this part of the IR is shown.

Because the parser is based on text parsing, the above IR is a function call I created myself.

In fact, this is an open source project TPU-MLIR on the MLIR official website, and there are some codes as follows:

    DialectRegistry registry;
    registry.insert<func::FuncDialect, top::TopDialect, tpu::TpuDialect,
                    quant::QuantizationDialect>();
    context_ = std::make_unique<MLIRContext>(registry);
    llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileOrErr =
                           llvm::MemoryBuffer::getFileOrSTDIN(filename);
    llvm::SourceMgr sourceMgr;
    sourceMgr.AddNewSourceBuffer(std::move(*fileOrErr), llvm::SMLoc());
    module_ = mlir::parseSourceFile<mlir::ModuleOp>(sourceMgr, context_.get());

IR file passed in through filename,through analysis, an error was reported at the following function,error in finding func symbol

mlir::LogicalResult verifySymbolUses(::mlir::SymbolTableCollection &symbolTable);

For more original code that may also report errors, please refer to the website
tpu-mlir/pymlir.cpp at master · sophgo/tpu-mlir · GitHub(line 84)

I don’t understand what you mean here?

I am really not seeing how this can fail with the error you posted, again the exact same file works for me, so I would double check that the string passed here through loading filename is really what you posted.
Beyond that, I would build in debug mode and run within gdb.

I learned that the ParseSourceFile function parses MLIR files in text format, so I manually modified and created sub functions and function call relationships in this file(filename),yes, I am using gdb in debug mode, but for this project, the parser source code is linked in the form of a static link library (. a file), so I cannot obtain the relevant data to verify the issue, considering whether it is an MLIR text issue.

It’s extremely unlikely: the IR you’re showing does not match the error. If you have gdb and building the project with debug info, you should be able to break emitOpError, run, and then print the full module by walking back the IR in gdb.