How can I use symbol table to find operation

Hi I just came from here trying to find a way to build a normal symbol table with mlir.

However, I cannot understand the doc, nor does it provide any example on how to create one.

What I would like to do is to:

  1. Insert target operations (function or variables) into a symbol table
  2. Can search by name and find the target operation
  3. Can read relevant information (attribute, operands, type) of the target operation

I tried to use a std::map to do this, but it seems that the address of operation will change while inserting or removing other operations within the same region.

Thus I would like to ask how and what I should do? How I can keep track of target symbol and find target operation??

You can construct a SymbolTable object from any operation that has the corresponding trait (e.g., ModuleOp). This object has methods or all of your needs.

Thanks, so to my understanding:

  1. Any operations, say mod_Op, with trait OpTrait::SymbolTable can construct a symbol table with the following
    SymbolTable symTab(Operation *symbolTableOp);
    
  2. Any operation, say t_Op, that has SymbolRefAttr can be insert into the symTab
  3. The t_Op can be found using Operation *lookup(StringRef name) method of symTab with the right name

Are they right, is there more restrictions on the operation (e.g. t_Op has to be within the mod_Op) or t_Op can have other attribute or name???

The inserted operation must implement the Symbol interface. This interface provides access to the symbol name in an op-agnostic way. SymbolRefAttr is for referencing symbols, not naming them, symbol names are usually StringAttr.

Certainly, the symbol op to be looked up must be within the symbol table op for which the SymbolTable is constructed. Different symbol tables may have duplicate names, there is no global uniqueness guarantee, so you must anchor your search somewhere.

The symbol op may be anything as long as it implements the Symbol interface correctly.

Thanks a lot. hmmmm, I’m still kind of confused of how to use them, could I ask further for a small sample case that I can follow??

Thanks again for your kind help and patience!!

Builtin FuncOp is a symbol, it lists the interface in its definition llvm-project/BuiltinOps.td at main · llvm/llvm-project · GitHub. It also has the attribute for the symbol name llvm-project/BuiltinOps.td at main · llvm/llvm-project · GitHub (SymbolNameAttr is currently just an alias for StringAttr). If the attribute name corresponds to the default one of the SymbolTable (llvm-project/SymbolTable.h at main · llvm/llvm-project · GitHub), the default implementation of the interface methods just works without any further effort from the operation. In more advanced scenarios, the operation must implement interface methods for the Symbol interface llvm-project/SymbolInterfaces.td at main · llvm/llvm-project · GitHub, you can read about implementing interface methods in the documentation.

Hi super thanks for your answer. However, I’ve read most of the doc and posts. I still do not understand how to:

  1. Insert an op into a symbol table
  2. Find an op from a symbol table

All I know now is that:

  1. op with OpTrait::SymbolTable can create a symbol table
  2. A symbol must be:
    1. A StringAttr attribute named
    2. No SSA results
  3. I have to put some interface in the op definition, which may be done by OpTrait::Symbol

But to be honest, I still do not know how to use it. I’ve searched all the internet and read all docs that I can find, there is no sample, no simple illustration.

So let’s say we have

Mod = build.create<ModuleOp>("mod", ...);
fun = build.create<FuncOp>("fun", ...);

A very simple question would be how should I create a callOp that links to fun???

And may I further ask some sample code, really really thanks!!!

Maybe the unit-tests can help?

SymbolTable::insert() (example call site)

SymbolTable::lookup() (example call site)

The symbol table does not need to be involved here, your code sample has already a reference to the function fun apparently:

Operation *callOp = b.create<CallOp>(loc, fun.sym_name(), resultTypes, operands);

Thanks so much, BTW, may I further ask if I want to find the callee, should I

  1. Build the callOp with CallOpInterface trait
  2. Get operation like the following
    Operation *callee = callOp.resolveCallable(callOp.getCallableForCallee());
    

If the above operation is OK?? Really thanks!!!